Commit 53fe0a5e by Sebastián Katzer

Release v0.8rc

parent 7f6c1ce0
......@@ -3,7 +3,7 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="de.appplant.cordova.plugin.local-notification"
version="0.8.0dev">
version="0.8.0rc">
<name>LocalNotification</name>
......@@ -14,12 +14,16 @@
<author>Sebastián Katzer</author>
<!-- cordova -->
<engines>
<engine name="cordova" version=">=3.0.0" />
</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">
<clobbers target="cordova.plugins.notification.local" />
<clobbers target="plugin.notification.local" />
......@@ -34,15 +38,15 @@
</feature>
</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" />
<source-file src="src/ios/APPLocalNotification.m" />
<header-file src="src/ios/APPLocalNotificationOptions.h" />
<source-file src="src/ios/APPLocalNotificationOptions.m" />
<header-file src="src/ios/AppDelegate+APPLocalNotification.h" />
<source-file src="src/ios/AppDelegate+APPLocalNotification.m" />
<header-file src="src/ios/UIApplication+APPLocalNotification.h" />
<source-file src="src/ios/UIApplication+APPLocalNotification.m" />
......@@ -59,38 +63,39 @@
</config-file>
<config-file target="AndroidManifest.xml" parent="/manifest/application">
<!--
* 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.
-->
<receiver android:name="de.appplant.cordova.plugin.localnotification.Receiver" android:exported="false" />
<!--
* The delete intent receiver is triggered when the user clears a notification
* manually. It unpersists the cleared notification from the shared preferences.
-->
<receiver android:name="de.appplant.cordova.plugin.localnotification.DeleteIntentReceiver" android:exported="false"/>
<!--
* 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.
-->
<receiver android:name="de.appplant.cordova.plugin.localnotification.Restore" >
<receiver
android:name="de.appplant.cordova.plugin.localnotification.TriggerReceiver"
android:exported="false" />
<receiver
android:name="de.appplant.cordova.plugin.localnotification.ClearReceiver"
android:exported="false" />
<activity
android:name="de.appplant.cordova.plugin.localnotification.ClickActivity"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.NoDisplay" />
<receiver
android:name="de.appplant.cordova.plugin.notification.TriggerReceiver"
android:exported="false" />
<receiver
android:name="de.appplant.cordova.plugin.notification.ClearReceiver"
android:exported="false" />
<receiver android:name="de.appplant.cordova.plugin.localnotification.RestoreReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity
android:name="de.appplant.cordova.plugin.notification.ClickActivity"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.NoDisplay" />
<!--
* 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 target="AndroidManifest.xml" parent="/manifest">
......@@ -99,29 +104,74 @@
<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 src="src/android/Receiver.java" target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/Restore.java" target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/ReceiverActivity.java" target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/DeleteIntentReceiver.java" target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/notification/Options.java" target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file src="src/android/notification/Asset.java" target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file src="src/android/notification/Manager.java" target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file src="src/android/notification/NotificationBuilder.java" target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file src="src/android/notification/NotificationWrapper.java" target-dir="src/de/appplant/cordova/plugin/notification" />
</platform>
<source-file
src="src/android/LocalNotification.java"
target-dir="src/de/appplant/cordova/plugin/localnotification" />
<!-- wp8 -->
<!-- <platform name="wp8">
<config-file target="config.xml" parent="/*">
<feature name="LocalNotification">
<param name="wp-package" value="LocalNotification"/>
</feature>
</config-file>
<source-file
src="src/android/TriggerReceiver.java"
target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/wp8/LocalNotification.cs" />
<source-file src="src/wp8/Options.cs" />
</platform> -->
<source-file
src="src/android/ClickActivity.java"
target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file
src="src/android/ClearReceiver.java"
target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file
src="src/android/RestoreReceiver.java"
target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file
src="src/android/notification/AbstractClearReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/AbstractClickActivity.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/AbstractRestoreReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/AbstractTriggerReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/AssetUtil.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/Builder.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/ClearReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/ClickActivity.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/Manager.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/Notification.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/Options.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/TriggerReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
</platform>
</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
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.
*/
* 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 java.util.ArrayList;
import java.util.List;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
......@@ -32,467 +34,439 @@ import org.json.JSONArray;
import org.json.JSONException;
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.annotation.TargetApi;
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
* 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 {
protected final static String PLUGIN_NAME = "LocalNotification";
static protected final String STORAGE_FOLDER = "/localnotification";
private static CordovaWebView webView = null;
private static Boolean deviceready = false;
protected static Context context = null;
protected static Boolean isInBackground = true;
private static ArrayList<String> eventQueue = new ArrayList<String>();
static Activity activity;
Asset asset;
Manager manager;
NotificationWrapper nWrapper;
/**
* Called after plugin construction and fields have been initialized.
*/
@Override
public void initialize (CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
protected void pluginInitialize() {
LocalNotification.webView = super.webView;
LocalNotification.context = super.cordova.getActivity().getApplicationContext();
LocalNotification.activity = super.cordova.getActivity();
this.asset = new Asset(activity,STORAGE_FOLDER);
this.manager = new Manager(context, PLUGIN_NAME);
this.nWrapper = new NotificationWrapper(context,Receiver.class,PLUGIN_NAME,Receiver.OPTIONS);
}
@Override
public boolean execute (String action, final JSONArray args, final CallbackContext command) throws JSONException {
if (action.equalsIgnoreCase("add")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
add(args);
command.success();
/**
* Called when the system is about to start resuming a previous activity.
*
* @param multitasking
* Flag indicating if multitasking is turned on for app
*/
@Override
public void onPause(boolean multitasking) {
super.onPause(multitasking);
isInBackground = true;
}
});
/**
* Called when the activity will start interacting with the user.
*
* @param multitasking
* Flag indicating if multitasking is turned on for app
*/
@Override
public void onResume(boolean multitasking) {
super.onResume(multitasking);
isInBackground = false;
}
if (action.equalsIgnoreCase("update")) {
cordova.getThreadPool().execute( new Runnable() {
/**
* 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() {
update(args);
if (action.equals("schedule")) {
schedule(args);
command.success();
}
});
else if (action.equals("update")) {
update(args);
command.success();
}
if (action.equalsIgnoreCase("cancel")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
else if (action.equals("cancel")) {
cancel(args);
command.success();
}
});
}
if (action.equalsIgnoreCase("cancelAll")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
cancelAll(args);
else if (action.equals("cancelAll")) {
cancelAll();
command.success();
}
});
}
if (action.equalsIgnoreCase("clear")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
else if (action.equals("clear")) {
clear(args);
command.success();
}
});
}
if (action.equalsIgnoreCase("clearAll")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
clearAll(args);
else if (action.equals("clearAll")) {
clearAll();
command.success();
}
});
else if (action.equals("isPresent")) {
isPresent(args.optInt(0), command);
}
if (action.equalsIgnoreCase("isScheduled")) {
String id = args.optString(0);
boolean isScheduled = manager.isScheduled(id);
PluginResult result = new PluginResult(PluginResult.Status.OK, (isScheduled));
command.sendPluginResult(result);
else if (action.equals("isScheduled")) {
isScheduled(args.optInt(0), command);
}
if (action.equalsIgnoreCase("isTriggered")) {
String id = args.optString(0);
boolean isTriggered = manager.isTriggered(id);
PluginResult result = new PluginResult(PluginResult.Status.OK, isTriggered);
command.sendPluginResult(result);
else if (action.equals("isTriggered")) {
isTriggered(args.optInt(0), command);
}
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();
command.success(scheduledIds);
else if (action.equals("getAllIds")) {
getAllIds(command);
}
if (action.equalsIgnoreCase("getTriggeredIds")) {
JSONArray triggeredIds = manager.getTriggeredIds();
command.success(triggeredIds);
else if (action.equals("getScheduledIds")) {
getScheduledIds(command);
}
if (action.equalsIgnoreCase("getAllIds")) {
JSONArray allIds = manager.getAllIds();
command.success(allIds);
else if (action.equals("getTriggeredIds")) {
getTriggeredIds(command);
}
if (action.equalsIgnoreCase("getAll")) {
JSONArray ids;
JSONArray all;
try{
ids = args.getJSONArray(0);
all = manager.getAll(ids);
} catch (JSONException jse){
all = manager.getAll();
else if (action.equals("getAll")) {
getAll(args, command);
}
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();
else if (action.equals("getScheduled")) {
getScheduled(args, command);
}
command.success(scheduled);
else if (action.equals("getTriggered")) {
getTriggered(args, command);
}
if (action.equalsIgnoreCase("deviceready")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
else if (action.equals("deviceready")) {
deviceready();
}
});
}
if (action.equalsIgnoreCase("pause")) {
isInBackground = true;
}
if (action.equalsIgnoreCase("resume")) {
isInBackground = false;
}
});
return true;
}
//------------------------------------------------exec-Functions-----------------------------------------------
/**
* Schedule notifications contained in the args-Array
* @param args
* Schedule multiple local notifications.
*
* @param notifications
* Properties for each local notification
*/
private void add(JSONArray args){
JSONArray notifications = args;
JSONObject arguments;
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);
private void schedule (JSONArray notifications) {
for (int i = 0; i < notifications.length(); i++) {
JSONObject options = notifications.optJSONObject(i);
getNotificationMgr().schedule(options, TriggerReceiver.class);
}
}
/**
* Update existing notifications
* @param args
* Update multiple local notifications.
*
* @param updates
* Notification properties including their IDs
*/
private void update(JSONArray args){
JSONArray updates = args;
JSONObject updateContent;
for(int i=0;i<updates.length();i++){
updateContent = args.optJSONObject(i);
private void update (JSONArray updates) {
for (int i = 0; i < updates.length(); i++) {
JSONObject update = updates.optJSONObject(i);
int id = update.optInt("id", 0);
Notification notification =
getNotificationMgr().update(id, update, TriggerReceiver.class);
nWrapper.update(updateContent);
fireEvent("update", notification);
}
}
/**
* Cancel scheduled Notifications
* @param args
* Cancel multiple local notifications.
*
* @param ids
* Set of local notification IDs
*/
private void cancel(JSONArray args){
JSONArray ids = args;
String id;
for(int i=0;i<ids.length();i++){
id = args.optString(i);
nWrapper.cancel(id);
JSONArray managerId = new JSONArray().put(id);
JSONArray data = manager.getAll(managerId);
fireEvent("cancel", id, "",data);
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);
}
}
/**
* Cancel all scheduled notifications
* @param args
* Cancel all scheduled notifications.
*/
public void cancelAll(JSONArray args){
JSONArray options = manager.getAll();
nWrapper.cancelAll();
String id;
JSONObject arguments;
for(int i=0;i<options.length();i++){
arguments= (JSONObject) options.opt(i);
JSONArray data = new JSONArray().put(arguments);
id = arguments.optString("id");
fireEvent("cancel", id, "",data);
}
private void cancelAll() {
getNotificationMgr().cancelAll();
fireEvent("cancelall");
}
/**
* Clear triggered notifications without cancel repeating.
* @param args
* Clear multiple local notifications without canceling them.
*
* @param ids
* Set of local notification IDs
*/
public void clear(JSONArray args){
JSONArray ids = args;
String id;
for(int i=0;i<ids.length();i++){
id = args.optString(i);
nWrapper.clear(id);
JSONArray managerId = new JSONArray().put(id);
JSONArray data = manager.getAll(managerId);
fireEvent("clear", id, "",data);
private void clear(JSONArray ids){
for (int i = 0; i < ids.length(); i++) {
int id = ids.optInt(i, 0);
Notification notification =
getNotificationMgr().clear(id);
fireEvent("clear", notification);
}
}
/**
* Clear all triggered notifications without cancel repeating.
* @param args
* Clear all triggered notifications without canceling them.
*/
public void clearAll(JSONArray args){
JSONArray options = manager.getAll();
nWrapper.clearAll();
String id;
JSONObject arguments;
for(int i=0;i<options.length();i++){
arguments= (JSONObject) options.opt(i);
JSONArray data = new JSONArray().put(arguments);
id = arguments.optString("id");
fireEvent("clear", id, "",data);
private void clearAll() {
getNotificationMgr().clearAll();
fireEvent("clearall");
}
}
/**
* If a notification with an ID is present.
*
* @param id
* Notification ID
* @param command
* The callback context used when calling back into JavaScript.
*/
private void isPresent (int id, CallbackContext command) {
boolean exist = getNotificationMgr().exist(id);
PluginResult result = new PluginResult(
PluginResult.Status.OK, exist);
command.sendPluginResult(result);
}
//-------------------------------------------------------------------------------------------------------------
/**
* Calls all pending callbacks after the deviceready event has been fired.
* If a notification with an ID is scheduled.
*
* @param id
* Notification ID
* @param command
* The callback context used when calling back into JavaScript.
*/
private static void deviceready () {
deviceready = true;
private void isScheduled (int id, CallbackContext command) {
boolean exist = getNotificationMgr().exist(
id, Notification.Type.SCHEDULED);
for (String js : eventQueue) {
sendJavascript(js);
}
PluginResult result = new PluginResult(
PluginResult.Status.OK, exist);
eventQueue.clear();
command.sendPluginResult(result);
}
/**
* 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.
* If a notification with an ID is triggered.
*
* @param alarmId
* The Id of the notification that must be persisted.
* @param args
* The assumption is that parse has been called already.
* @param id
* Notification ID
* @param command
* The callback context used when calling back into JavaScript.
*/
public static void persist (String alarmId, JSONObject args) {
Editor editor = getSharedPreferences().edit();
private void isTriggered (int id, CallbackContext command) {
boolean exist = getNotificationMgr().exist(
id, Notification.Type.TRIGGERED);
if (alarmId != null) {
editor.putString(alarmId, args.toString());
if (Build.VERSION.SDK_INT<9) {
editor.commit();
} else {
editor.apply();
}
}
PluginResult result = new PluginResult(
PluginResult.Status.OK, exist);
command.sendPluginResult(result);
}
/**
* Remove a specific alarm from the Android shared Preferences.
* Set of IDs from all existent notifications.
*
* @param alarmId
* The Id of the notification that must be removed.
* @param command
* The callback context used when calling back into JavaScript.
*/
public static void unpersist (String alarmId) {
Editor editor = getSharedPreferences().edit();
private void getAllIds (CallbackContext command) {
List<Integer> ids = getNotificationMgr().getIds();
if (alarmId != null) {
editor.remove(alarmId);
if (Build.VERSION.SDK_INT<9) {
editor.commit();
} else {
editor.apply();
}
}
command.success(new JSONArray(ids));
}
/**
* Clear all alarms from the Android shared Preferences.
* Set of IDs from all scheduled notifications.
*
* @param command
* The callback context used when calling back into JavaScript.
*/
public static void unpersistAll () {
Editor editor = getSharedPreferences().edit();
private void getScheduledIds (CallbackContext command) {
List<Integer> ids = getNotificationMgr().getIdsByType(
Notification.Type.SCHEDULED);
editor.clear();
if (Build.VERSION.SDK_INT<9) {
editor.commit();
} else {
editor.apply();
}
command.success(new JSONArray(ids));
}
//
/**
* Fires the given event (Only one Callback also for multiple notifications in one action).
* Set of IDs from all triggered notifications.
*
* @param {String} event The Name of the event
* @param ids The IDs of the notifications as JSONArray
* @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) {
String state = getApplicationState();
String params = ids + ",\"" + state + "\"," + json;
String js = "setTimeout('plugin.notification.local.on" + event + "(" + params + ")',0)";
private void getTriggeredIds (CallbackContext command) {
List<Integer> ids = getNotificationMgr().getIdsByType(
Notification.Type.TRIGGERED);
// webview may available, but callbacks needs to be executed
// after deviceready
if (deviceready == false) {
eventQueue.add(js);
} else {
sendJavascript(js);
}
command.success(new JSONArray(ids));
}
//
/**
* Fires the given event. (Standard-method)
* Set of options from local notification.
*
* @param {String} event The Name of the event
* @param {String} id The ID of the notification
* @param {String} json A custom (JSON) string
* @param data The notifications as JSONObject
* @param ids
* Set of local notification IDs
* @param command
* The callback context used when calling back into JavaScript.
*/
public static void fireEvent (String event, String id, String json, JSONArray data) {
String state = getApplicationState();
String params = "\"" + id + "\",\"" + state + "\"," + JSONObject.quote(json)+","+ data;
String js = "setTimeout('plugin.notification.local.on" + event + "(" + params + ")',0)";
private void getAll (JSONArray ids, CallbackContext command) {
List<JSONObject> options;
// webview may available, but callbacks needs to be executed
// after deviceready
if (deviceready == false) {
eventQueue.add(js);
if (ids.length() == 0) {
options = getNotificationMgr().getOptions();
} else {
sendJavascript(js);
options = getNotificationMgr().getOptionsById(toList(ids));
}
}
command.success(new JSONArray(options));
}
/**
* Retrieves the application state
* Set of options from scheduled notifications.
*
* @return {String}
* Either "background" or "foreground"
* @param ids
* Set of local notification IDs
* @param command
* The callback context used when calling back into JavaScript.
*/
protected static String getApplicationState () {
return isInBackground ? "background" : "foreground";
private void getScheduled (JSONArray ids, CallbackContext command) {
List<JSONObject> options;
if (ids.length() == 0) {
options = getNotificationMgr().getOptionsByType(Notification.Type.SCHEDULED);
} else {
options = getNotificationMgr().getOptionsBy(
Notification.Type.SCHEDULED, toList(ids));
}
command.success(new JSONArray(options));
}
/**
* Set the application context if not already set.
* Set of options from triggered notifications.
*
* @param ids
* Set of local notification IDs
* @param command
* The callback context used when calling back into JavaScript.
*/
protected static void setContext (Context context) {
if (LocalNotification.context == null) {
LocalNotification.context = context;
private void getTriggered (JSONArray ids, CallbackContext command) {
List<JSONObject> options;
if (ids.length() == 0) {
options = getNotificationMgr().getOptionsByType(Notification.Type.TRIGGERED);
} else {
options = getNotificationMgr().getOptionsBy(
Notification.Type.TRIGGERED, toList(ids));
}
command.success(new JSONArray(options));
}
/**
* The Local storage for the application.
* Call all pending callbacks after the deviceready event has been fired.
*/
protected static SharedPreferences getSharedPreferences () {
return context.getSharedPreferences(PLUGIN_NAME, Context.MODE_PRIVATE);
private static synchronized void deviceready () {
isInBackground = false;
deviceready = true;
for (String js : eventQueue) {
sendJavascript(js);
}
eventQueue.clear();
}
/**
* The alarm manager for the application.
* Fire given event on JS side. Does inform all event listeners.
*
* @param event
* The event name
*/
protected static AlarmManager getAlarmManager () {
return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
private void fireEvent (String event) {
fireEvent(event, null);
}
/**
* The notification manager for the application.
* Fire given event on JS side. Does inform all event listeners.
*
* @param event
* The event name
* @param notification
* Optional local notification to pass the id and properties.
*/
protected static NotificationManager getNotificationManager () {
return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
static void fireEvent (String event, Notification notification) {
String state = getApplicationState();
String params = "\"" + state + "\"";
if (notification != null) {
params = notification.toString() + "," + params;
}
String js = "cordova.plugins.notification.local.fireEvent(" +
"\"" + event + "\"," + params + ")";
sendJavascript(js);
}
/**
* Use this instead of deprecated sendJavascript
*
* @param js
* JS code snippet as string
*/
@TargetApi(Build.VERSION_CODES.KITKAT)
private static void sendJavascript(final String js){
private static void sendJavascript(final String js) {
if (!deviceready) {
eventQueue.add(js);
return;
}
webView.post(new Runnable(){
public void run(){
if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.KITKAT){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript(js, null);
} else {
webView.loadUrl("javascript:" + js);
......@@ -501,5 +475,37 @@ public class LocalNotification extends CordovaPlugin {
});
}
/**
* Convert JSON array of integers to List.
*
* @param ary
* Array of integers
*/
private List<Integer> toList (JSONArray ary) {
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < ary.length(); i++) {
list.add(ary.optInt(i));
}
return list;
}
/**
* Current application state.
*
* @return
* "background" or "foreground"
*/
static String getApplicationState () {
return isInBackground ? "background" : "foreground";
}
/**
* Notification manager instance.
*/
private Manager getNotificationMgr() {
return Manager.getInstance(cordova.getActivity());
}
}
/*
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;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import static de.appplant.cordova.plugin.notification.Notification.PREF_KEY;
import android.app.NotificationManager;
import android.content.Context;
import android.content.SharedPreferences;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Build;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 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 {
//---------------Global Parameter------------------------------------------------------------
// Context passed through constructor and used for notification builder.
private Context context;
private final String PLUGIN_NAME;
//---------------Constructor-----------------------------------------------------------------
/**
* Constructor of NotificationWrapper-Class
* Constructor
*
* @param context
* Application context
*/
public Manager(Context context,String PluginName){
private Manager(Context context){
this.context = context;
this.PLUGIN_NAME = PluginName;
}
//---------------Public Functions------------------------------------------------------------
/**
* Checks if a notification with an ID is scheduled.
* Static method to retrieve class instance.
*
* @param id
* The notification ID to be check.
* @return true if the notification is scheduled
* @param context
* Application context
*/
public boolean isScheduled (String id) {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
boolean isScheduled = alarms.containsKey(id);
boolean isNotTriggered = false;
if (isScheduled) {
JSONObject arguments;
try {
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getDate());
isNotTriggered = new Date().before(fireDate);
} catch (JSONException e) {
isNotTriggered = false;
e.printStackTrace();
public static Manager getInstance(Context context) {
return new Manager(context);
}
/**
* Schedule local notification specified by JSON object.
*
* @param options
* JSON object with set of options
* @param receiver
* Receiver to handle the trigger event
*/
public Notification schedule (JSONObject options, Class<?> receiver) {
return schedule(new Options(context).parse(options), receiver);
}
return (isScheduled && isNotTriggered);
/**
* Schedule local notification specified by options object.
*
* @param options
* Set of notification options
* @param receiver
* Receiver to handle the trigger event
*/
public Notification schedule (Options options, Class<?> receiver) {
Notification notification = new Builder(options)
.setTriggerReceiver(receiver)
.build();
notification.schedule();
return notification;
}
/**
* Checks if a notification with an ID was triggered.
* Clear local notification specified by ID.
*
* @param id
* The notification ID to be check.
* @return true if the notification is triggered
* The notification ID
* @param updates
* JSON object with notification options
* @param receiver
* Receiver to handle the trigger event
*/
public boolean isTriggered (String id) {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
boolean isScheduled = alarms.containsKey(id);
boolean isTriggered = isScheduled;
if (isScheduled) {
JSONObject arguments;
public Notification update (int id, JSONObject updates, Class<?> receiver) {
Notification notification = get(id);
if (notification == null)
return null;
notification.cancel();
JSONObject options = mergeJSONObjects(
notification.getOptions().getDict(), updates);
try {
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getInitialDate());
isTriggered = new Date().after(fireDate);
} catch (JSONException e) {
isTriggered = false;
e.printStackTrace();
}
options.putOpt("updatedAt", new Date().getTime());
} catch (JSONException ignore) {}
return schedule(options, receiver);
}
return isTriggered;
}
/**
* Checks whether a notification with an ID exist.
* Clear local notification specified by ID.
*
* @param id
* The notification ID to check.
* @return true if the notification exist
* The notification ID
*/
public boolean exist(String id){
boolean exist;
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
exist = alarms.containsKey(id);
return exist;
public Notification clear (int id) {
Notification notification = get(id);
if (notification != null) {
notification.clear();
}
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 () {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray scheduledIds = new JSONArray();
for (String id : alarmIds) {
boolean isScheduled;
JSONObject arguments;
try {
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getDate());
isScheduled = new Date().before(fireDate);
} catch (JSONException e) {
isScheduled = false;
e.printStackTrace();
}
if (isScheduled){
scheduledIds.put(id);
}
}
public Notification cancel (int id) {
Notification notification = get(id);
return scheduledIds;
if (notification != null) {
notification.cancel();
}
return notification;
}
/**
* Retrieves a list with all currently triggered notification Ids.
*
* @return JSONArray with all Id-Strings
* Clear all local notifications.
*/
public JSONArray getTriggeredIds () {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray triggeredIds = new JSONArray();
Date now = new Date();
public void clearAll () {
List<Notification> notifications = getAll();
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;
for (Notification notification : notifications) {
notification.clear();
}
if (isTriggered == true) {
triggeredIds.put(id);
getNotMgr().cancelAll();
}
/**
* Cancel all local notifications.
*/
public void cancelAll () {
List<Notification> notifications = getAll();
for (Notification notification : notifications) {
notification.cancel();
}
return triggeredIds;
getNotMgr().cancelAll();
}
/**
* Retrieves a list with all currently triggered or scheduled notification-Ids.
* @return JSONArray with all Id-Strings
* All local notifications IDs.
*/
public JSONArray getAllIds (){
JSONArray allIds = new JSONArray();
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
for (String id : alarmIds) {
allIds.put(id);
public List<Integer> getIds() {
Set<String> keys = getPrefs().getAll().keySet();
ArrayList<Integer> ids = new ArrayList<Integer>();
for (String key : keys) {
ids.add(Integer.parseInt(key));
}
return 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(){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray all = new JSONArray();
public List<Integer> getIdsByType(Notification.Type type) {
List<Notification> notifications = getAll();
ArrayList<Integer> ids = new ArrayList<Integer>();
for (String id : alarmIds) {
JSONObject arguments;
try{
arguments = new JSONObject(alarms.get(id).toString());
all.put(arguments);
} catch(JSONException jse) {
jse.printStackTrace();
for (Notification notification : notifications) {
if (notification.getType() == type) {
ids.add(notification.getId());
}
}
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(){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray scheduled = new JSONArray();
for (String id : alarmIds) {
boolean isScheduled;
JSONObject arguments = null;
try {
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getDate());
isScheduled = new Date().before(fireDate);
} catch (JSONException e) {
isScheduled = false;
e.printStackTrace();
public List<Notification> getByIds(List<Integer> ids) {
ArrayList<Notification> notifications = new ArrayList<Notification>();
for (int id : ids) {
Notification notification = get(id);
if (notification != null) {
notifications.add(notification);
}
if (isScheduled){
scheduled.put(arguments);
}
return notifications;
}
/**
* List of all local notification.
*/
public List<Notification> getAll() {
return getByIds(getIds());
}
/**
* List of local notifications from given type.
*
* @param type
* The notification life cycle type
*/
public List<Notification> getByType(Notification.Type type) {
List<Notification> notifications = getAll();
ArrayList<Notification> list = new ArrayList<Notification>();
return scheduled;
for (Notification notification : notifications) {
if (notification.getType() == type) {
list.add(notification);
}
}
return list;
}
/**
* Retrieves a list with all currently triggered notification-JSONObjects.
* List of local notifications with matching ID from given type.
*
* @return JSONArray with all notification-JSONObjects
* @param type
* The notification life cycle type
* @param ids
* Set of notification IDs
*/
public JSONArray getTriggered(){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray triggered = new JSONArray();
Date now = new Date();
@SuppressWarnings("UnusedDeclaration")
public List<Notification> getBy(Notification.Type type, List<Integer> ids) {
ArrayList<Notification> notifications = new ArrayList<Notification>();
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;
}
for (int id : ids) {
Notification notification = get(id);
if (isTriggered == true) {
triggered.put(arguments);
if (notification != null && notification.isScheduled()) {
notifications.add(notification);
}
}
return triggered;
return notifications;
}
/**
* Retrieves a list with all currently pending notification JSONObjects that matches with the given String-Array
* If a notification with an ID exists.
*
* @return JSONArray with notification-JSONObjects
* @param id
* Notification ID
*/
public JSONArray getAll(JSONArray ids){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray all = new JSONArray();
for (String id : alarmIds) {
for(int i=0;i<ids.length();i++){
if(ids.optString(i).equals(id)){
JSONObject arguments;
try{
arguments = new JSONObject(alarms.get(id).toString());
all.put(arguments);
} catch(JSONException jse) {
jse.printStackTrace();
}
}
}
}
return all;
public boolean exist (int id) {
return get(id) != null;
}
/**
* Retrieves a list with all currently scheduled notification-JSONObjects.
* If a notification with an ID and type exists.
*
* @return JSONArray with all notification-JSONObjects
* @param id
* Notification ID
* @param type
* Notification type
*/
public JSONArray getScheduled(JSONArray ids){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray scheduled = new JSONArray();
boolean isScheduled;
for (String id : alarmIds) {
for(int i=0;i<ids.length();i++){
if(ids.optString(i).equals(id)){
JSONObject arguments = null;
try {
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getDate());
isScheduled = new Date().before(fireDate);
} catch (JSONException e) {
isScheduled = false;
e.printStackTrace();
}
if (isScheduled){
scheduled.put(arguments);
}
}
public boolean exist (int id, Notification.Type type) {
Notification notification = get(id);
return notification != null && notification.getType() == type;
}
/**
* List of properties from all local notifications.
*/
public List<JSONObject> getOptions() {
return getOptionsById(getIds());
}
/**
* List of properties from local notifications with matching ID.
*
* @param ids
* Set of notification IDs
*/
public List<JSONObject> getOptionsById(List<Integer> ids) {
ArrayList<JSONObject> options = new ArrayList<JSONObject>();
for (int id : ids) {
Notification notification = get(id);
return scheduled;
if (notification != null) {
options.add(notification.getOptions().getDict());
}
}
return options;
}
/**
* Retrieves a list with all currently triggered notification-JSONObjects.
* List of properties from all local notifications from given type.
*
* @return JSONArray with all notification-JSONObjects
* @param type
* The notification life cycle type
*/
public JSONArray getTriggered(JSONArray ids){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray triggered = new JSONArray();
Date now = new Date();
public List<JSONObject> getOptionsByType(Notification.Type type) {
ArrayList<JSONObject> options = new ArrayList<JSONObject>();
List<Notification> notifications = getByType(type);
for (String id : alarmIds) {
for(int i=0;i<ids.length();i++){
if(ids.optString(i).equals(id)){
boolean isTriggered;
JSONObject arguments = null;
try{
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getInitialDate());
isTriggered = now.after(fireDate);
} catch(ClassCastException cce) {
cce.printStackTrace();
isTriggered = false;
} catch(JSONException jse) {
jse.printStackTrace();
isTriggered = false;
for (Notification notification : notifications) {
options.add(notification.getOptions().getDict());
}
if (isTriggered == true) {
triggered.put(arguments);
}
return options;
}
/**
* List of properties from local notifications with matching ID from
* given type.
*
* @param type
* The notification life cycle type
* @param ids
* Set of notification IDs
*/
public List<JSONObject> getOptionsBy(Notification.Type type,
List<Integer> ids) {
ArrayList<JSONObject> options = new ArrayList<JSONObject>();
List<Notification> notifications = getByIds(ids);
for (Notification notification : notifications) {
if (notification.getType() == type) {
options.add(notification.getOptions().getDict());
}
}
return triggered;
return options;
}
/**
* Get existent local notification.
*
* @param id
* Notification ID
*/
public Notification get(int id) {
Map<String, ?> alarms = getPrefs().getAll();
String notId = Integer.toString(id);
JSONObject options;
if (!alarms.containsKey(notId))
return null;
//---------------Manage Shared Preferences---------------------------------------------------
/**
* The Local storage for the application.
*/
private SharedPreferences getSharedPreferences () {
return context.getSharedPreferences(PLUGIN_NAME, Context.MODE_PRIVATE);
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();
}
/**
* 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.
* Merge two JSON objects.
*
* @param alarmId
* The Id of the notification that must be persisted.
* @param args
* The assumption is that parse has been called already.
* @param obj1
* JSON object
* @param obj2
* JSON object with new options
*/
public void persist (String alarmId, JSONObject args) {
Editor editor = getSharedPreferences().edit();
private JSONObject mergeJSONObjects (JSONObject obj1, JSONObject obj2) {
Iterator it = obj2.keys();
if (alarmId != null) {
editor.putString(alarmId, args.toString());
if (Build.VERSION.SDK_INT<9) {
editor.commit();
} else {
editor.apply();
while (it.hasNext()) {
try {
String key = (String)it.next();
obj1.put(key, obj2.opt(key));
} catch (JSONException e) {
e.printStackTrace();
}
}
return obj1;
}
/**
* Remove a specific alarm from the Android shared Preferences.
*
* @param alarmId
* The Id of the notification that must be removed.
* Shared private preferences for the application.
*/
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 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
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.
*/
* 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.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Date;
import org.json.JSONException;
......@@ -31,215 +30,210 @@ import org.json.JSONObject;
import android.app.AlarmManager;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
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 {
// Key name for bundled extras
static final String EXTRA = "NOTIFICATION_OPTIONS";
// The original JSON object
private JSONObject options = new JSONObject();
private String packageName = null;
// Repeat interval
private long interval = 0;
private Context context;
// Application context
private final Context context;
// Asset util instance
private final AssetUtil assets;
/**
* Constructor
*
* @param context
* Application context
*/
public Options(Context context){
this.context= context;
this.packageName = context.getPackageName();
this.context = context;
this.assets = AssetUtil.getInstance(context);
}
/**
* Parses the given properties
* Parse given JSON properties.
*
* @param options
* JSON properties
*/
public Options parse (JSONObject options) {
String repeat = options.optString("repeat");
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;
} if (repeat.equalsIgnoreCase("minutely")) {
} else
if (every.equals("minute")) {
interval = AlarmManager.INTERVAL_FIFTEEN_MINUTES / 15;
} if (repeat.equalsIgnoreCase("hourly")) {
} else
if (every.equals("hour")) {
interval = AlarmManager.INTERVAL_HOUR;
} if (repeat.equalsIgnoreCase("daily")) {
} else
if (every.equals("day")) {
interval = AlarmManager.INTERVAL_DAY;
} else if (repeat.equalsIgnoreCase("weekly")) {
interval = AlarmManager.INTERVAL_DAY*7;
} else if (repeat.equalsIgnoreCase("monthly")) {
interval = AlarmManager.INTERVAL_DAY*31; // 31 days
} else if (repeat.equalsIgnoreCase("yearly")) {
interval = AlarmManager.INTERVAL_DAY*365;
} else
if (every.equals("week")) {
interval = AlarmManager.INTERVAL_DAY * 7;
} else
if (every.equals("month")) {
interval = AlarmManager.INTERVAL_DAY * 31;
} else
if (every.equals("year")) {
interval = AlarmManager.INTERVAL_DAY * 365;
} else {
try {
interval = Integer.parseInt(repeat) * 60000;
} catch (Exception e) {};
interval = Integer.parseInt(every) * 60000;
} catch (Exception e) {
e.printStackTrace();
}
}
return this;
}
/**
* Set new time according to interval
* Parse asset URIs.
*/
public Options moveDate () {
try {
options.put("date", (getDate() + interval) / 1000);
} catch (JSONException e) {}
private void parseAssets() {
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"));
Uri soundUri = assets.parseSound(options.optString("sound", null));
/**
* Returns time in milliseconds when notification is scheduled to fire
*/
public long getDate() {
return options.optLong("date", 0) * 1000;
try {
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 () {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(getDate()));
return calendar;
public Context getContext () {
return context;
}
/**
* Returns the notification's message
* Wrapped JSON object.
*/
public String getMessage () {
return options.optString("message", "");
JSONObject getDict () {
return options;
}
/**
* Returns the notification's title
* Text for the local notification.
*/
public String getTitle () {
return options.optString("title", "");
public String getText() {
return options.optString("text", "");
}
/**
* Returns the path of the notification's sound file
* Repeat interval (day, week, month, year, aso.)
*/
public Uri getSound () {
Uri soundUri = null;
try{
soundUri = Uri.parse(options.optString("soundUri"));
return soundUri;
} catch (Exception e){
e.printStackTrace();
}
return null;
public long getRepeatInterval() {
return interval;
}
/**
* Returns the icon's ID
* Badge number for the local notification.
*/
public Bitmap getIcon () {
String icon = options.optString("icon", "icon");
Bitmap bmp = null;
Uri iconUri = null;
try{
iconUri = Uri.parse(options.optString("iconUri"));
bmp = getIconFromUri(iconUri);
} catch (Exception e){
bmp = getIconFromRes(icon);
}
return bmp;
public int getBadgeNumber() {
return options.optInt("badge", 0);
}
/**
* Returns the small icon's ID
* Android only ongoing flag for local notifications.
*/
public int getSmallIcon () {
int resId = 0;
String iconName = options.optString("smallIcon", "");
resId = getIconValue(packageName, iconName);
if (resId == 0) {
resId = getIconValue("android", iconName);
}
if (resId == 0) {
resId = getIconValue(packageName, "icon");
}
return options.optInt("smallIcon", resId);
public Boolean isOngoing() {
return options.optBoolean("ongoing", false);
}
/**
* Returns notification repetition interval (daily, weekly, monthly, yearly)
* Trigger date in milliseconds.
*/
public long getInterval () {
return interval;
public long getTriggerTime() {
return options.optLong("at", 0) * 1000;
}
/**
* Returns notification badge number
* Trigger date.
*/
public int getBadge () {
return options.optInt("badge", 0);
public Date getTriggerDate() {
return new Date(getTriggerTime());
}
/**
* Returns PluginResults' callback ID
* ID for the local notification.
*/
public String getId () {
public String getId() {
return options.optString("id", "0");
}
/**
* Returns whether notification is cancelled automatically when clicked.
* ID for the local notification.
*/
public Boolean getAutoCancel () {
return options.optBoolean("autoCancel", false);
public int getIdAsInt() {
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 () {
return options.optBoolean("ongoing", false);
public String getTitle() {
String title = options.optString("title", "");
if (title.isEmpty()) {
title = context.getApplicationInfo().loadLabel(
context.getPackageManager()).toString();
}
/**
* Returns additional data as string
*/
public String getJSON () {
return options.optString("json", "");
return title;
}
/**
* @return
* The notification color for LED
*/
public int getColor () {
String hexColor = options.optString("led", "000000");
int aRGB = Integer.parseInt(hexColor,16);
public int getLedColor() {
String hex = options.optString("led", "000000");
int aRGB = Integer.parseInt(hex,16);
aRGB += 0xFF000000;
......@@ -247,87 +241,57 @@ public class Options {
}
/**
* Shows the behavior of notifications when the application is in foreground
*
* Sound file path for the local notification.
*/
public boolean getForegroundMode(){
return options.optBoolean("foregroundMode",false);
}
/**
* Returns numerical icon Value
*
* @param {String} className
* @param {String} iconName
*/
private int getIconValue (String className, String iconName) {
int icon = 0;
try {
Class<?> klass = Class.forName(className + ".R$drawable");
public Uri getSoundUri() {
Uri uri = null;
icon = (Integer) klass.getDeclaredField(iconName).get(Integer.class);
} catch (Exception e) {}
try{
uri = Uri.parse(options.optString("soundUri"));
} catch (Exception e){
e.printStackTrace();
}
return icon;
return uri;
}
/**
* Converts an resource to Bitmap.
*
* @param icon
* The resource name
* @return
* The corresponding bitmap
* Icon bitmap for the local notification.
*/
private Bitmap getIconFromRes (String icon) {
Resources res = context.getResources();
int iconId = 0;
iconId = getIconValue(packageName, icon);
if (iconId == 0) {
iconId = getIconValue("android", icon);
}
public Bitmap getIconBitmap() {
String icon = options.optString("icon", "icon");
Bitmap bmp;
if (iconId == 0) {
iconId = android.R.drawable.ic_menu_info_details;
try{
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;
}
/**
* Converts an Image URI to Bitmap.
*
* @param src
* The internal image URI
* @return
* The corresponding bitmap
* Small icon resource ID for the local notification.
*/
private Bitmap getIconFromUri (Uri uri) throws IOException {
Bitmap bmp = null;
public int getSmallIcon () {
String icon = options.optString("smallIcon", "");
InputStream input = context.getContentResolver().openInputStream(uri);
bmp = BitmapFactory.decodeStream(input);
int resId = assets.getResIdForDrawable(icon);
return bmp;
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(){
long initialDate = options.optLong("date", 0) * 1000;
try {
options.put("initialDate", initialDate);
} catch (JSONException e) {
e.printStackTrace();
}
public String toString() {
return options.toString();
}
}
/*
* 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
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.
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
#import <Foundation/Foundation.h>
......@@ -32,20 +34,24 @@
// Register permission to show notifications
- (void) registerPermission:(CDVInvokedUrlCommand*)command;
// Schedule a new notification
- (void) add:(CDVInvokedUrlCommand*)command;
// Update a notification
// Schedule set of notifications
- (void) schedule:(CDVInvokedUrlCommand*)command;
// Update set of notifications
- (void) update:(CDVInvokedUrlCommand*)command;
// Cancel a given notification
// Cancel set of notifications
- (void) cancel:(CDVInvokedUrlCommand*)command;
// Cancel all currently scheduled notifications
// Cancel all notifications
- (void) cancelAll:(CDVInvokedUrlCommand*)command;
// Clear set of notifications
- (void) clear:(CDVInvokedUrlCommand*)command;
// Clear all notifications
- (void) clearAll:(CDVInvokedUrlCommand*)command;
// If a notification with an ID exists
- (void) exist:(CDVInvokedUrlCommand*)command;
// If a notification with an ID was scheduled
// If a notification with an ID is present
- (void) isPresent:(CDVInvokedUrlCommand*)command;
// If a notification with an ID is scheduled
- (void) isScheduled:(CDVInvokedUrlCommand*)command;
// If a notification with an ID was triggered
// If a notification with an ID is triggered
- (void) isTriggered:(CDVInvokedUrlCommand*)command;
// List all ids from all local notifications
......
/*
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.
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
#import "APPLocalNotification.h"
......@@ -67,7 +69,7 @@
* @param properties
* A dict of properties for each notification
*/
- (void) add:(CDVInvokedUrlCommand*)command
- (void) schedule:(CDVInvokedUrlCommand*)command
{
NSArray* notifications = command.arguments;
......@@ -79,7 +81,7 @@
initWithOptions:options];
[self scheduleLocalNotification:[notification copy]];
[self fireEvent:@"add" localNotification:notification];
[self fireEvent:@"schedule" notification:notification];
if (notifications.count > 1) {
[NSThread sleepForTimeInterval:0.01];
......@@ -105,8 +107,7 @@
NSString* id = [options objectForKey:@"id"];
UILocalNotification* notification;
notification = [[UIApplication sharedApplication]
scheduledLocalNotificationWithId:id];
notification = [self.app localNotificationWithId:id];
if (!notification)
continue;
......@@ -114,6 +115,8 @@
[self updateLocalNotification:[notification copy]
withOptions:options];
[self fireEvent:@"update" notification:notification];
if (notifications.count > 1) {
[NSThread sleepForTimeInterval:0.01];
}
......@@ -135,14 +138,13 @@
for (NSString* id in command.arguments) {
UILocalNotification* notification;
notification = [[UIApplication sharedApplication]
scheduledLocalNotificationWithId:id];
notification = [self.app localNotificationWithId:id];
if (!notification)
continue;
[self cancelLocalNotification:notification];
[self fireEvent:@"cancel" localNotification:notification];
[self.app cancelLocalNotification:notification];
[self fireEvent:@"cancel" notification:notification];
}
[self execCallback:command];
......@@ -150,7 +152,7 @@
}
/**
* Cancel all currently scheduled notifications.
* Cancel all local notifications.
*/
- (void) cancelAll:(CDVInvokedUrlCommand*)command
{
......@@ -162,34 +164,54 @@
}
/**
* If a notification by ID exists.
* Clear a set of notifications.
*
* @param id
* The ID of the notification
* @param ids
* The IDs of the notifications
*/
- (void) exist:(CDVInvokedUrlCommand *)command
- (void) clear:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
NSString* id = [[command arguments]
objectAtIndex:0];
CDVPluginResult* result;
for (NSString* id in command.arguments) {
UILocalNotification* notification;
notification = [[UIApplication sharedApplication]
localNotificationWithId:id];
notification = [self.app localNotificationWithId:id];
bool exists = notification != NULL;
if (!notification)
continue;
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsBool:exists];
[self.app clearLocalNotification:notification];
[self fireEvent:@"clear" notification:notification];
}
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
[self execCallback:command];
}];
}
/**
* Clear all local notifications.
*/
- (void) clearAll:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
[self clearAllLocalNotifications];
[self fireEvent:@"clearall"];
[self execCallback:command];
}];
}
/**
* If a notification by ID is present.
*
* @param id
* The ID of the notification
*/
- (void) isPresent:(CDVInvokedUrlCommand *)command
{
[self isPresent:command type:NotifcationTypeAll];
}
/**
* If a notification by ID is scheduled.
*
* @param id
......@@ -197,48 +219,43 @@
*/
- (void) isScheduled:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
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];
}];
[self isPresent:command type:NotifcationTypeScheduled];
}
/**
* Check if a notification with an ID was triggered.
* Check if a notification with an ID is triggered.
*
* @param id
* The ID of the notification
*/
- (void) isTriggered:(CDVInvokedUrlCommand*)command
{
[self isPresent:command type:NotifcationTypeTriggered];
}
/**
* Check if a notification with an ID exists.
*
* @param type
* The notification life cycle type
*/
- (void) isPresent:(CDVInvokedUrlCommand*)command
type:(APPLocalNotificationType)type;
{
[self.commandDelegate runInBackground:^{
NSString* id = [[command arguments]
objectAtIndex:0];
NSString* id = [command argumentAtIndex:0];
BOOL exist;
CDVPluginResult* result;
UILocalNotification* notification;
notification = [[UIApplication sharedApplication]
triggeredLocalNotificationWithId:id];
bool isTriggered = notification != NULL;
if (type == NotifcationTypeAll) {
exist = [self.app localNotificationExist:id];
} else {
exist = [self.app localNotificationExist:id type:type];
}
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsBool:isTriggered];
messageAsBool:exist];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
......@@ -250,19 +267,7 @@
*/
- (void) getAllIds:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
CDVPluginResult* result;
NSArray* notIds;
notIds = [[UIApplication sharedApplication]
localNotificationIds];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:notIds];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
[self getIds:command byType:NotifcationTypeAll];
}
/**
......@@ -270,19 +275,7 @@
*/
- (void) getScheduledIds:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
CDVPluginResult* result;
NSArray* scheduledIds;
scheduledIds = [[UIApplication sharedApplication]
scheduledLocalNotificationIds];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:scheduledIds];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
[self getIds:command byType:NotifcationTypeScheduled];
}
/**
......@@ -290,44 +283,32 @@
*/
- (void) getTriggeredIds:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
CDVPluginResult* result;
NSArray* triggeredIds;
triggeredIds = [[UIApplication sharedApplication]
triggeredLocalNotificationIds];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:triggeredIds];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
[self getIds:command byType:NotifcationTypeTriggered];
}
/**
* Property list for given local notifications.
* List of ids for given local notifications.
*
* @param type
* Notification life cycle type
* @param ids
* The IDs of the notifications
*/
- (void) getAll:(CDVInvokedUrlCommand*)command
- (void) getIds:(CDVInvokedUrlCommand*)command
byType:(APPLocalNotificationType)type;
{
[self.commandDelegate runInBackground:^{
NSArray* ids = command.arguments;
NSArray* notifications;
CDVPluginResult* result;
NSArray* ids;
if (ids.count == 0) {
notifications = [[UIApplication sharedApplication]
localNotificationOptions];
if (type == NotifcationTypeAll) {
ids = [self.app localNotificationIds];
} else {
notifications = [[UIApplication sharedApplication]
localNotificationOptions:ids];
ids = [self.app localNotificationIdsByType:type];
}
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:notifications];
messageAsArray:ids];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
......@@ -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.
*
* @param ids
......@@ -342,25 +334,7 @@
*/
- (void) getScheduled:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
NSArray* ids = command.arguments;
NSArray* notifications;
CDVPluginResult* result;
if (ids.count == 0) {
notifications = [[UIApplication sharedApplication]
scheduledLocalNotificationOptions];
} else {
notifications = [[UIApplication sharedApplication]
scheduledLocalNotificationOptions:ids];
}
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:notifications];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
[self getOptions:command byType:NotifcationTypeScheduled];
}
/**
......@@ -371,17 +345,37 @@
*/
- (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:^{
NSArray* ids = command.arguments;
NSArray* notifications;
CDVPluginResult* result;
if (ids.count == 0) {
notifications = [[UIApplication sharedApplication]
triggeredLocalNotificationOptions];
} else {
notifications = [[UIApplication sharedApplication]
triggeredLocalNotificationOptions:ids];
if (type == NotifcationTypeAll && ids.count == 0) {
notifications = [self.app localNotificationOptions];
}
else if (type == NotifcationTypeAll) {
notifications = [self.app localNotificationOptionsById:ids];
}
else if (ids.count == 0) {
notifications = [self.app localNotificationOptionsByType:type];
}
else {
notifications = [self.app localNotificationOptionsByType:type
andId:ids];
}
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
......@@ -402,8 +396,7 @@
CDVPluginResult* result;
BOOL hasPermission;
hasPermission = [[UIApplication sharedApplication]
hasPermissionToScheduleLocalNotifications];
hasPermission = [self.app hasPermissionToScheduleLocalNotifications];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsBool:hasPermission];
......@@ -423,8 +416,7 @@
_command = command;
[self.commandDelegate runInBackground:^{
[[UIApplication sharedApplication]
registerPermissionToScheduleLocalNotifications];
[self.app registerPermissionToScheduleLocalNotifications];
}];
#else
[self hasPermission:command];
......@@ -440,9 +432,7 @@
- (void) scheduleLocalNotification:(UILocalNotification*)notification
{
[self cancelForerunnerLocalNotification:notification];
[[UIApplication sharedApplication]
scheduleLocalNotification:notification];
[self.app scheduleLocalNotification:notification];
}
/**
......@@ -460,31 +450,24 @@
initWithOptions:options];
[self scheduleLocalNotification:notification];
}
/**
* Cancel the local notification.
* Cancel all local notifications.
*/
- (void) cancelLocalNotification:(UILocalNotification*)notification
- (void) cancelAllLocalNotifications
{
[[UIApplication sharedApplication]
cancelLocalNotification:notification];
[UIApplication sharedApplication]
.applicationIconBadgeNumber -= 1;
[self.app cancelAllLocalNotifications];
[self.app setApplicationIconBadgeNumber:0];
}
/**
* Cancel all currently scheduled notifications.
* Clear all local notifications.
*/
- (void) cancelAllLocalNotifications
- (void) clearAllLocalNotifications
{
[[UIApplication sharedApplication]
cancelAllLocalNotifications];
[[UIApplication sharedApplication]
setApplicationIconBadgeNumber:0];
[self.app clearAllLocalNotifications];
[self.app setApplicationIconBadgeNumber:0];
}
/**
......@@ -495,13 +478,12 @@
NSString* id = notification.options.id;
UILocalNotification* forerunner;
forerunner = [[UIApplication sharedApplication]
scheduledLocalNotificationWithId:id];
forerunner = [self.app localNotificationWithId:id];
if (!forerunner)
return;
[self cancelLocalNotification:forerunner];
[self.app cancelLocalNotification:forerunner];
}
/**
......@@ -512,16 +494,16 @@
{
NSArray* notifications;
notifications = [[UIApplication sharedApplication]
scheduledLocalNotifications];
notifications = [self.app scheduledLocalNotifications];
for (UILocalNotification* notification in notifications)
{
if (notification && [notification isRepeating]
&& notification.timeIntervalSinceFireDate > seconds)
{
[self cancelLocalNotification:notification];
[self fireEvent:@"cancel" localNotification:notification];
[self.app cancelLocalNotification:notification];
[self fireEvent:@"cancel" notification:notification];
}
}
}
......@@ -540,21 +522,29 @@
if ([notification wasUpdated])
return;
BOOL autoCancel = notification.options.autoCancel;
NSTimeInterval timeInterval = [notification timeIntervalSinceFireDate];
NSTimeInterval timeInterval = [notification timeIntervalSinceLastTrigger];
NSString* event = (timeInterval <= 1 && deviceready) ? @"trigger" : @"click";
if ([event isEqualToString:@"click"]) {
[UIApplication sharedApplication]
.applicationIconBadgeNumber -= 1;
[self fireEvent:event notification:notification];
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"]) {
[self cancelLocalNotification:notification];
[self fireEvent:@"cancel" localNotification:notification];
if (timeInterval > 1 && [notification isRepeating])
{
[self fireEvent:@"fireUpdateEvent" notification:notification];
return;
}
}
......@@ -639,8 +629,7 @@
*/
- (NSString*) applicationState
{
UIApplicationState state = [[UIApplication sharedApplication]
applicationState];
UIApplicationState state = [self.app applicationState];
bool isActive = state == UIApplicationStateActive;
......@@ -660,37 +649,40 @@
}
/**
* Short hand for shared application instance.
*/
- (UIApplication*) app
{
return [UIApplication sharedApplication];
}
/**
* Fire general event.
*/
- (void) fireEvent:(NSString*)event
{
[self fireEvent:event localNotification:NULL];
[self fireEvent:event notification:NULL];
}
/**
* Fire event for local notification.
*/
- (void) fireEvent:(NSString*)event localNotification:(UILocalNotification*)notification
- (void) fireEvent:(NSString*)event notification:(UILocalNotification*)notification
{
NSString* js;
NSString* params = [NSString stringWithFormat:
@"\"%@\"", self.applicationState];
if (notification) {
NSString* id = notification.options.id;
NSString* json = notification.options.json;
NSString* args = [notification encodeToJSON];
json = [json stringByReplacingOccurrencesOfString:@"'"
withString:@"\\\\\\'"];
params = [NSString stringWithFormat:
@"\"%@\",\"%@\",\\'%@\\',JSON.parse(\\'%@\\')",
id, self.applicationState, json, args];
@"%@,'%@'",
args, self.applicationState];
}
js = [NSString stringWithFormat:
@"setTimeout('cordova.plugins.notification.local.on%@(%@)',0)",
@"cordova.plugins.notification.local.fireEvent('%@', %@)",
event, params];
if (deviceready) {
......
/*
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.
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
@interface APPLocalNotificationOptions : NSObject
......@@ -24,8 +26,6 @@
- (id) initWithDict:(NSDictionary*)dict;
@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=alertBody) NSString* alertBody;
@property (readonly, getter=soundName) NSString* soundName;
......
/*
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.
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
#import "APPLocalNotificationOptions.h"
#import <Cordova/CDVAvailability.h>
// Default sound ressource path
NSString* const DEFAULT_SOUND = @"res://platform_default";
@interface APPLocalNotificationOptions ()
......@@ -71,29 +75,9 @@
/**
* 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 ![self isRepeating];
} else {
return [[dict objectForKey:@"autoCancel"] boolValue];
}
}
/**
* The notification's JSON data.
*/
- (NSString*) json
{
return [dict objectForKey:@"json"];
return [dict objectForKey:@"text"];
}
/**
......@@ -101,13 +85,7 @@
*/
- (NSInteger) badgeNumber
{
NSInteger number = [[dict objectForKey:@"badge"] intValue];
if (number == -1) {
number = 1 + [UIApplication sharedApplication].applicationIconBadgeNumber;
}
return number;
return [[dict objectForKey:@"badge"] intValue];
}
#pragma mark -
......@@ -119,7 +97,7 @@
- (NSString*) alertBody
{
NSString* title = [self title];
NSString* msg = [self message];
NSString* msg = [self text];
NSString* alertBody = msg;
......@@ -139,16 +117,19 @@
{
NSString* path = [dict objectForKey:@"sound"];
if ([self stringIsNullOrEmpty:path])
return NULL;
if ([path isEqualToString:DEFAULT_SOUND])
return UILocalNotificationDefaultSoundName;
if ([path hasPrefix:@"file:/"])
{
return [self soundNameForAsset:path];
}
else if ([path hasPrefix:@"res:"])
{
if ([path hasPrefix:@"res:"])
return [self soundNameForResource:path];
}
return UILocalNotificationDefaultSoundName;
return NULL;
}
/**
......@@ -156,7 +137,7 @@
*/
- (NSDate*) fireDate
{
double timestamp = [[dict objectForKey:@"date"]
double timestamp = [[dict objectForKey:@"at"]
doubleValue];
return [NSDate dateWithTimeIntervalSince1970:timestamp];
......@@ -167,34 +148,30 @@
*/
- (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;
}
else if ([interval isEqualToString:@"minutely"])
{
else if ([interval isEqualToString:@"minute"]) {
return NSCalendarUnitMinute;
}
else if ([interval isEqualToString:@"hourly"])
{
else if ([interval isEqualToString:@"houre"]) {
return NSCalendarUnitHour;
}
else if ([interval isEqualToString:@"daily"])
{
else if ([interval isEqualToString:@"day"]) {
return NSCalendarUnitDay;
}
else if ([interval isEqualToString:@"weekly"])
{
else if ([interval isEqualToString:@"week"]) {
return NSCalendarUnitWeekOfYear;
}
else if ([interval isEqualToString:@"monthly"])
{
else if ([interval isEqualToString:@"month"]) {
return NSCalendarUnitMonth;
}
else if ([interval isEqualToString:@"yearly"])
{
else if ([interval isEqualToString:@"year"]) {
return NSCalendarUnitYear;
}
......
/*
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.
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
#import "AppDelegate.h"
......
/*
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.
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
#import "AppDelegate+APPLocalNotification.h"
......
/*
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.
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
#import "UILocalNotification+APPLocalNotification.h"
@interface UIApplication (APPLocalNotification)
@property (readonly, getter=localNotifications) NSArray* localNotifications;
@property (readonly, getter=scheduledLocalNotifications2) NSArray* triggeredLocalNotifications2;
@property (readonly, getter=triggeredLocalNotifications) NSArray* triggeredLocalNotifications;
@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
- (BOOL) hasPermissionToScheduleLocalNotifications;
// Ask for permission to schedule local notifications
- (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;
// Get scheduled local notification by ID
- (UILocalNotification*) scheduledLocalNotificationWithId:(NSString*)id;
// Get triggered local notification by ID
- (UILocalNotification*) triggeredLocalNotificationWithId:(NSString*)id;
// Local notification by ID and type
- (UILocalNotification*) localNotificationWithId:(NSString*)id andType:(APPLocalNotificationType)type;
// Property list from all local notifications
- (NSArray*) localNotificationOptions;
// Property list from all scheduled notifications
- (NSArray*) scheduledLocalNotificationOptions;
// Property list from all triggered notifications
- (NSArray*) triggeredLocalNotificationOptions;
// Property list from given local notifications
- (NSArray*) localNotificationOptions:(NSArray*)ids;
// Property list from given scheduled notifications
- (NSArray*) scheduledLocalNotificationOptions:(NSArray*)ids;
// Property list from given triggered notifications
- (NSArray*) triggeredLocalNotificationOptions:(NSArray*)ids;
- (NSArray*) localNotificationOptionsById:(NSArray*)ids;
// Property list from all local notifications with type constraint
- (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type;
// Property list from given local notifications with type constraint
- (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type andId:(NSArray*)ids;
// Clear single local notfications
- (void) clearLocalNotification:(UILocalNotification*)notification;
// Clear all local notfications
- (void) clearAllLocalNotifications;
@end
/*
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.
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
#import "UIApplication+APPLocalNotification.h"
......@@ -101,7 +103,7 @@
for (UILocalNotification* notification in scheduledNotifications)
{
if (notification && [notification wasScheduled]) {
if (notification && [notification isScheduled]) {
[notifications addObject:notification];
}
}
......@@ -120,7 +122,7 @@
for (UILocalNotification* notification in notifications)
{
if ([notification wasTriggered]) {
if ([notification isTriggered]) {
[triggeredNotifications addObject:notification];
}
}
......@@ -129,8 +131,7 @@
}
/**
* List of all triggered local notifications IDs which have been scheduled
* and not yet removed from the notification center.
* List of all local notifications IDs.
*/
- (NSArray*) localNotificationIds
{
......@@ -146,67 +147,58 @@
}
/**
* List of all added local notifications IDs which have been scheduled
* and not yet removed from the notification center.
* List of all local notifications IDs from given type.
*
* @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];
for (UILocalNotification* notification in notifications)
{
if (notification.type == type) {
[ids addObject:notification.options.id];
}
}
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;
NSMutableArray* ids = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications)
{
[ids addObject:notification.options.id];
}
return ids;
return [self localNotificationWithId:id] != NULL;
}
/**
* Get local notification by ID.
/* If local notification with ID and type exists
*
* @param id
* Notification ID
* @param type
* Notification life cycle type
*/
- (UILocalNotification*) localNotificationWithId:(NSString*)id
- (BOOL) localNotificationExist:(NSString*)id type:(APPLocalNotificationType)type
{
NSArray* notifications = self.localNotifications;
for (UILocalNotification* notification in notifications)
{
if ([notification.options.id isEqualToString:id]) {
return notification;
}
}
return NULL;
return [self localNotificationWithId:id andType:type] != NULL;
}
/**
* Get scheduled local notification by ID.
* Get local notification with ID.
*
* @param id
* Notification ID
*/
- (UILocalNotification*) scheduledLocalNotificationWithId:(NSString*)id
- (UILocalNotification*) localNotificationWithId:(NSString*)id
{
NSArray* notifications = self.scheduledLocalNotifications2;
NSArray* notifications = self.localNotifications;
for (UILocalNotification* notification in notifications)
{
......@@ -218,19 +210,20 @@
return NULL;
}
/**
* Get triggered local notification by ID.
/*
* Get local notification with ID and type.
*
* @param 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];
if (notification && [notification wasTriggered]) {
if (notification && notification.type == type)
return notification;
}
return NULL;
}
......@@ -252,32 +245,21 @@
}
/**
* List of properties from all scheduled notifications.
* List of properties from all local notifications from given type.
*
* @param type
* Notification life cycle type
*/
- (NSArray*) scheduledLocalNotificationOptions
- (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type
{
NSArray* notifications = [self scheduledLocalNotifications2];
NSArray* notifications = self.localNotifications;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications)
{
if (notification.type == type) {
[options addObject:notification.userInfo];
}
return options;
}
/**
* List of properties from all triggered notifications.
*/
- (NSArray*) triggeredLocalNotificationOptions
{
NSArray* notifications = self.triggeredLocalNotifications;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications)
{
[options addObject:notification.userInfo];
}
return options;
......@@ -289,7 +271,7 @@
* @param ids
* Notification IDs
*/
- (NSArray*) localNotificationOptions:(NSArray*)ids
- (NSArray*) localNotificationOptionsById:(NSArray*)ids
{
UILocalNotification* notification;
NSMutableArray* options = [[NSMutableArray alloc] init];
......@@ -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
* Notification IDs
*/
- (NSArray*) scheduledLocalNotificationOptions:(NSArray*)ids
- (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type andId:(NSArray*)ids
{
UILocalNotification* notification;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (NSString* id in ids)
{
notification = [self scheduledLocalNotificationWithId:id];
notification = [self localNotificationWithId:id];
if (notification) {
if (notification && notification.type == type) {
[options addObject:notification.userInfo];
}
}
......@@ -329,27 +313,33 @@
return options;
}
/**
* List of properties from given triggered notifications.
*
* @param ids
* Notification IDs
/*
* Clear all local notfications.
*/
- (NSArray*) triggeredLocalNotificationOptions:(NSArray*)ids
- (void) clearAllLocalNotifications
{
UILocalNotification* notification;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (NSString* id in ids)
{
notification = [self triggeredLocalNotificationWithId:id];
NSArray* notifications = self.triggeredLocalNotifications;
if (notification) {
[options addObject:notification.userInfo];
}
for (UILocalNotification* notification in notifications) {
[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
/*
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.
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
#import "APPLocalNotificationOptions.h"
typedef NS_ENUM(NSUInteger, APPLocalNotificationType) {
NotifcationTypeAll = 0,
NotifcationTypeScheduled = 1,
NotifcationTypeTriggered = 2
};
@interface UILocalNotification (APPLocalNotification)
// Initialize a new local notification
- (id) initWithOptions:(NSDictionary*)dict;
// The options provided by the plug-in
- (APPLocalNotificationOptions*) options;
// Timeinterval since last trigger date
- (double) timeIntervalSinceLastTrigger;
// Timeinterval since fire date
- (double) timeIntervalSinceFireDate;
// If the fire date was in the past
- (BOOL) wasInThePast;
// If the notification was already scheduled
- (BOOL) wasScheduled;
- (BOOL) isScheduled;
// If the notification was already triggered
- (BOOL) wasTriggered;
- (BOOL) isTriggered;
// If the notification was updated
- (BOOL) wasUpdated;
// If it's a repeating notification
- (BOOL) isRepeating;
// Notifciation type
- (APPLocalNotificationType) type;
// Encode the user info dict to JSON
- (NSString*) encodeToJSON;
......
/*
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.
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
#import "UILocalNotification+APPLocalNotification.h"
......@@ -25,6 +27,9 @@
static char optionsKey;
NSInteger const APPLocalNotificationTypeScheduled = 1;
NSInteger const APPLocalNotificationTypeTriggered = 2;
@implementation UILocalNotification (APPLocalNotification)
#pragma mark -
......@@ -131,10 +136,20 @@ static char optionsKey;
- (double) timeIntervalSinceFireDate
{
NSDate* now = [NSDate date];
NSDate* fireDate = self.options.fireDate;
NSDate* fireDate = self.fireDate;
int timespan = [now timeIntervalSinceDate:fireDate];
return timespan;
}
/**
* Timeinterval since last trigger date.
*/
- (double) timeIntervalSinceLastTrigger
{
int timespan = [self timeIntervalSinceFireDate];
if ([self isRepeating]) {
timespan = timespan % [self repeatIntervalInSeconds];
}
......@@ -173,11 +188,11 @@ static char optionsKey;
*/
- (BOOL) wasInThePast
{
return [self timeIntervalSinceFireDate] > 0;
return [self timeIntervalSinceLastTrigger] > 0;
}
// If the notification was already scheduled
- (BOOL) wasScheduled
- (BOOL) isScheduled
{
return [self isRepeating] || ![self wasInThePast];
}
......@@ -185,7 +200,7 @@ static char optionsKey;
/**
* If the notification was already triggered.
*/
- (BOOL) wasTriggered
- (BOOL) isTriggered
{
NSDate* now = [NSDate date];
NSDate* fireDate = self.fireDate;
......@@ -219,4 +234,12 @@ static char optionsKey;
return [self.options isRepeating];
}
/**
* Process state type of the local notification.
*/
- (APPLocalNotificationType) type
{
return [self isTriggered] ? NotifcationTypeTriggered : NotifcationTypeScheduled;
}
@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
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.
*/
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
var exec = require('cordova/exec'),
channel = require('cordova/channel');
// 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 () {
// 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
};
/*************
* INTERFACE *
*************/
/**
* Returns the default settings
......@@ -90,14 +47,14 @@ exports.setDefaults = function (newDefaults) {
var defaults = this.getDefaults();
for (var key in defaults) {
if (newDefaults[key] !== undefined) {
if (newDefaults.hasOwnProperty(key)) {
defaults[key] = newDefaults[key];
}
}
};
/**
* Add a new entry to the registry
* Schedule a new local notification.
*
* @param {Object} opts
* The notification properties
......@@ -106,7 +63,7 @@ exports.setDefaults = function (newDefaults) {
* @param {Object?} scope
* The scope for the callback function
*/
exports.add = function (opts, callback, scope) {
exports.schedule = function (opts, callback, scope) {
this.registerPermission(function(granted) {
if (!granted)
......@@ -121,7 +78,7 @@ exports.add = function (opts, callback, scope) {
this.convertProperties(properties);
}
this.exec('add', notifications, callback, scope);
this.exec('schedule', notifications, callback, scope);
}, this);
};
......@@ -141,7 +98,7 @@ exports.update = function (opts, callback, scope) {
for (var i = 0; i < notifications.length; i++) {
var properties = notifications[i];
this.convertUpdateProperties(properties);
this.convertProperties(properties);
}
this.exec('update', notifications, 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
* The ID of the notification
......@@ -218,17 +175,10 @@ exports.cancelAll = function (callback, scope) {
* @param {Object?} scope
* The scope for the callback function
*/
exports.exist = function (id, callback, scope) {
exports.isPresent = function (id, callback, scope) {
var notId = (id || '0').toString();
this.exec('exist', notId, callback, scope);
};
/**
* Alias for `exist`.
*/
exports.exists = function () {
this.exist.apply(this, arguments);
this.exec('isPresent', notId, callback, scope);
};
/**
......@@ -489,117 +439,83 @@ exports.promptForPermission = function (callback, scope) {
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.
*
* @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) {};
/**********
* EVENTS *
**********/
/**
* Fires after the notification was clicked.
* Register callback for given 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
* @param {String} event
* The event's name
* @param {Function} callback
* The function to be exec as callback
* @param {Object?} scope
* The callback function's scope
*/
exports.onclick = function (id, state, json, data) {};
exports.on = function (event, callback, scope) {
/**
* Fires if the notification was canceled.
*
* @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) {};
if (!this._listener[event]) {
this._listener[event] = [];
}
/**
* 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) {};
var item = [callback, scope || window];
/**
* 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;
this._listener[event].push(item);
};
/**
* 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
* 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
* @param {String} event
* The event's name
* @param {Function} callback
* The function to be exec as callback
*/
exports.onupdateCall = function (id, state, json, data) {
var updates = exports.onupdate(id, state, json, data);
if (updates != null){
updates.id = id;
update(updates,null,null);
};
exports.un = function (event, callback) {
var listener = this._listener[event];
if (!listener)
return;
for (var i = 0; i < listener.length; i++) {
var fn = listener[i][0];
if (fn == callback) {
listener.splice(i, 1);
break;
}
}
};
/***********
* 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
*
* Merges custom properties with the default values.
* Merge custom properties with the default values.
*
* @param {Object} options
* Set of custom values
......@@ -610,15 +526,23 @@ exports.onupdateCall = function (id, state, json, data) {
exports.mergeWithDefaults = function (options) {
var defaults = this.getDefaults();
options.date = this.getValueFor(options, 'date', 'at', 'firstAt');
options.repeat = this.getValueFor(options, 'repeat', 'every');
options.message = this.getValueFor(options, 'message', 'text');
options.at = this.getValueFor(options, 'at', 'firstAt', 'date');
options.text = this.getValueFor(options, 'text', 'message');
options.data = this.getValueFor(options, 'data', 'json');
if (options.at === undefined || options.at === null) {
options.at = new Date();
}
for (var key in defaults) {
if (options[key] === null || options[key] === undefined) {
if (options.hasOwnProperty(key) && ['data','sound'].indexOf(key) > -1) {
options[key] = undefined;
} else {
options[key] = defaults[key];
}
}
}
for (key in options) {
if (!defaults.hasOwnProperty(key)) {
......@@ -630,8 +554,6 @@ exports.mergeWithDefaults = function (options) {
};
/**
* @private
*
* Convert the passed values to their required type.
*
* @param {Object} options
......@@ -642,79 +564,43 @@ exports.mergeWithDefaults = function (options) {
*/
exports.convertProperties = function (options) {
options.id = options.id.toString();
options.title = options.title.toString();
options.message = options.message.toString();
options.autoCancel = options.autoCancel === true;
if (options.id) {
if (isNaN(options.id)) {
options.id = this.getDefaults().id;
} else {
options.id = options.id.toString();
}
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') {
options.json = JSON.stringify(options.json);
}
return options;
};
/**
* @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();
if (options.title) {
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 (options.text) {
options.text = options.text.toString();
}
if (options.badge) {
if (isNaN(options.badge)) {
options.badge = this.getDefaults().badge;
}
} else {
options.badge = Number(options.badge);
}
}
if (typeof options.date == 'object') {
options.date = Math.round(options.date.getTime()/1000);
if (typeof options.at == 'object') {
options.at = Math.round(options.at.getTime()/1000);
}
if (typeof options.json == 'object') {
options.json = JSON.stringify(options.json);
if (typeof options.data == 'object') {
options.data = JSON.stringify(options.data);
}
return options;
};
/**
* @private
*
* Merges the platform specific properties into the default properties.
* Merge platform specific properties into the default ones.
*
* @return {Object}
* The default properties for the platform
......@@ -724,26 +610,18 @@ exports.applyPlatformSpecificOptions = function () {
switch (device.platform) {
case 'Android':
defaults.icon = 'icon';
defaults.smallIcon = null;
defaults.icon = 'res://ic_popup_reminder';
defaults.smallIcon = 'res://ic_popup_reminder';
defaults.ongoing = false;
defaults.led = 'FFFFFF'; /*RRGGBB*/
defaults.sound = 'TYPE_NOTIFICATION'; break;
case 'iOS':
defaults.sound = ''; break;
case 'WinCE': case 'Win32NT':
defaults.smallImage = null;
defaults.image = null;
defaults.wideImage = null;
defaults.led = 'FFFFFF';
break;
}
return defaults;
};
/**
* @private
*
* Creates a callback, which will be executed within a specific scope.
* Create callback, which will be executed within a specific scope.
*
* @param {Function} callbackFn
* The callback function
......@@ -763,8 +641,6 @@ exports.createCallbackFn = function (callbackFn, scope) {
};
/**
* @private
*
* Convert the IDs to Strings.
*
* @param {String/Number[]} ids
......@@ -782,13 +658,10 @@ exports.convertIds = function (ids) {
};
/**
* @private
*
* Return the first found value for the given keys.
* First found value for the given keys.
*
* @param {Object} options
* Object with key-value properties
*
* @param {String[]} keys*
* Key list
*/
......@@ -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
* The name of the action
......@@ -830,3 +724,24 @@ exports.exec = function (action, args, callback, scope) {
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