Commit 53fe0a5e by Sebastián Katzer

Release v0.8rc

parent 7f6c1ce0
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
id="de.appplant.cordova.plugin.local-notification" id="de.appplant.cordova.plugin.local-notification"
version="0.8.0dev"> version="0.8.0rc">
<name>LocalNotification</name> <name>LocalNotification</name>
...@@ -14,12 +14,16 @@ ...@@ -14,12 +14,16 @@
<author>Sebastián Katzer</author> <author>Sebastián Katzer</author>
<!-- cordova -->
<engines> <engines>
<engine name="cordova" version=">=3.0.0" /> <engine name="cordova" version=">=3.0.0" />
</engines> </engines>
<dependency id="org.apache.cordova.device" url="https://github.com/apache/cordova-plugin-device" /> <dependency
id="org.apache.cordova.device"
url="https://github.com/apache/cordova-plugin-device" />
<!-- js -->
<js-module src="www/local-notification.js" name="LocalNotification"> <js-module src="www/local-notification.js" name="LocalNotification">
<clobbers target="cordova.plugins.notification.local" /> <clobbers target="cordova.plugins.notification.local" />
<clobbers target="plugin.notification.local" /> <clobbers target="plugin.notification.local" />
...@@ -34,15 +38,15 @@ ...@@ -34,15 +38,15 @@
</feature> </feature>
</config-file> </config-file>
<header-file src="src/ios/AppDelegate+APPLocalNotification.h" />
<source-file src="src/ios/AppDelegate+APPLocalNotification.m" />
<header-file src="src/ios/APPLocalNotification.h" /> <header-file src="src/ios/APPLocalNotification.h" />
<source-file src="src/ios/APPLocalNotification.m" /> <source-file src="src/ios/APPLocalNotification.m" />
<header-file src="src/ios/APPLocalNotificationOptions.h" /> <header-file src="src/ios/APPLocalNotificationOptions.h" />
<source-file src="src/ios/APPLocalNotificationOptions.m" /> <source-file src="src/ios/APPLocalNotificationOptions.m" />
<header-file src="src/ios/AppDelegate+APPLocalNotification.h" />
<source-file src="src/ios/AppDelegate+APPLocalNotification.m" />
<header-file src="src/ios/UIApplication+APPLocalNotification.h" /> <header-file src="src/ios/UIApplication+APPLocalNotification.h" />
<source-file src="src/ios/UIApplication+APPLocalNotification.m" /> <source-file src="src/ios/UIApplication+APPLocalNotification.m" />
...@@ -59,38 +63,39 @@ ...@@ -59,38 +63,39 @@
</config-file> </config-file>
<config-file target="AndroidManifest.xml" parent="/manifest/application"> <config-file target="AndroidManifest.xml" parent="/manifest/application">
<!--
* The alarm receiver is triggered when a scheduled alarm is fired. This class <receiver
* reads the information in the intent and displays this information in the android:name="de.appplant.cordova.plugin.localnotification.TriggerReceiver"
* Android notification bar. The notification uses the default notification android:exported="false" />
* sound and it vibrates the phone.
--> <receiver
<receiver android:name="de.appplant.cordova.plugin.localnotification.Receiver" android:exported="false" /> android:name="de.appplant.cordova.plugin.localnotification.ClearReceiver"
android:exported="false" />
<!--
* The delete intent receiver is triggered when the user clears a notification <activity
* manually. It unpersists the cleared notification from the shared preferences. android:name="de.appplant.cordova.plugin.localnotification.ClickActivity"
--> android:launchMode="singleInstance"
<receiver android:name="de.appplant.cordova.plugin.localnotification.DeleteIntentReceiver" android:exported="false"/> android:theme="@android:style/Theme.NoDisplay" />
<!-- <receiver
* This class is triggered upon reboot of the device. It needs to re-register android:name="de.appplant.cordova.plugin.notification.TriggerReceiver"
* the alarms with the AlarmManager since these alarms are lost in case of android:exported="false" />
* reboot.
--> <receiver
<receiver android:name="de.appplant.cordova.plugin.localnotification.Restore" > android:name="de.appplant.cordova.plugin.notification.ClearReceiver"
android:exported="false" />
<receiver android:name="de.appplant.cordova.plugin.localnotification.RestoreReceiver" >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<activity
android:name="de.appplant.cordova.plugin.notification.ClickActivity"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.NoDisplay" />
<!--
* The receiver activity is triggered when a notification is clicked by a user.
* The activity calls the background callback and brings the launch inten
* up to foreground.
-->
<activity android:name="de.appplant.cordova.plugin.localnotification.ReceiverActivity" android:launchMode="singleInstance" android:theme="@android:style/Theme.NoDisplay" />
</config-file> </config-file>
<config-file target="AndroidManifest.xml" parent="/manifest"> <config-file target="AndroidManifest.xml" parent="/manifest">
...@@ -99,29 +104,74 @@ ...@@ -99,29 +104,74 @@
<lib-file src="libs/android/android-support-v4.jar" /> <lib-file src="libs/android/android-support-v4.jar" />
<source-file src="src/android/LocalNotification.java" target-dir="src/de/appplant/cordova/plugin/localnotification" /> <source-file
<source-file src="src/android/Receiver.java" target-dir="src/de/appplant/cordova/plugin/localnotification" /> src="src/android/LocalNotification.java"
<source-file src="src/android/Restore.java" target-dir="src/de/appplant/cordova/plugin/localnotification" /> target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/ReceiverActivity.java" target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/DeleteIntentReceiver.java" target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/notification/Options.java" target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file src="src/android/notification/Asset.java" target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file src="src/android/notification/Manager.java" target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file src="src/android/notification/NotificationBuilder.java" target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file src="src/android/notification/NotificationWrapper.java" target-dir="src/de/appplant/cordova/plugin/notification" />
</platform>
<!-- wp8 --> <source-file
<!-- <platform name="wp8"> src="src/android/TriggerReceiver.java"
<config-file target="config.xml" parent="/*"> target-dir="src/de/appplant/cordova/plugin/localnotification" />
<feature name="LocalNotification">
<param name="wp-package" value="LocalNotification"/>
</feature>
</config-file>
<source-file src="src/wp8/LocalNotification.cs" /> <source-file
<source-file src="src/wp8/Options.cs" /> src="src/android/ClickActivity.java"
</platform> --> target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file
src="src/android/ClearReceiver.java"
target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file
src="src/android/RestoreReceiver.java"
target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file
src="src/android/notification/AbstractClearReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/AbstractClickActivity.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/AbstractRestoreReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/AbstractTriggerReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/AssetUtil.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/Builder.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/ClearReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/ClickActivity.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/Manager.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/Notification.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/Options.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/TriggerReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
</platform>
</plugin> </plugin>
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.localnotification;
import de.appplant.cordova.plugin.notification.Notification;
/**
* The clear intent receiver is triggered when the user clears a
* notification manually. It un-persists the cleared notification from the
* shared preferences.
*/
public class ClearReceiver extends de.appplant.cordova.plugin.notification.ClearReceiver {
/**
* Called when a local notification was cleared from outside of the app.
*
* @param notification
* Wrapper around the local notification
*/
@Override
public void onClear (Notification notification) {
super.onClear(notification);
LocalNotification.fireEvent("clear", notification);
}
}
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.localnotification;
import de.appplant.cordova.plugin.notification.*;
import de.appplant.cordova.plugin.notification.TriggerReceiver;
/**
* The receiver activity is triggered when a notification is clicked by a user.
* The activity calls the background callback and brings the launch intent
* up to foreground.
*/
public class ClickActivity extends de.appplant.cordova.plugin.notification.ClickActivity {
/**
* Called when local notification was clicked by the user.
*
* @param notification
* Wrapper around the local notification
*/
@Override
public void onClick(Notification notification) {
LocalNotification.fireEvent("click", notification);
if (!notification.isRepeating()) {
LocalNotification.fireEvent("cancel", notification);
}
super.onClick(notification);
}
/**
* Build notification specified by options.
*
* @param builder
* Notification builder
*/
@Override
public Notification buildNotification (Builder builder) {
return builder
.setTriggerReceiver(TriggerReceiver.class)
.build();
}
}
/*
Copyright 2013-2014 appPlant UG
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package de.appplant.cordova.plugin.localnotification;
import java.util.Date;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import de.appplant.cordova.plugin.notification.Options;
public class DeleteIntentReceiver extends BroadcastReceiver {
public static final String OPTIONS = "LOCAL_NOTIFICATION_OPTIONS";
/**
* Is called when a Notification is cleared manualy by the User
*/
@Override
public void onReceive(Context context, Intent intent) {
Options options = null;
Bundle bundle = intent.getExtras();
JSONObject args;
try {
args = new JSONObject(bundle.getString(OPTIONS));
options = new Options(context).parse(args);
} catch (JSONException e) {
return;
}
// The context may got lost if the app was not running before
LocalNotification.setContext(context);
Date now = new Date();
if ((options.getInterval()!=0)){
options.setInitDate();
LocalNotification.persist(options.getId(), options.getJSONObject());
}
else if((new Date(options.getDate()).before(now))){
LocalNotification.unpersist(options.getId());
}
fireClearEvent(options);
}
/**
* Fires onclear event.
*/
private void fireClearEvent (Options options) {
JSONArray data = new JSONArray().put(options.getJSONObject());
LocalNotification.fireEvent("clear", options.getId(), options.getJSON(),data);
}
}
/*
Copyright 2013-2014 appPlant UG
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.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 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 (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification;
/**
* The alarm receiver is triggered when a scheduled alarm is fired. This class
* reads the information in the intent and displays this information in the
* Android notification bar. The notification uses the default notification
* sound and it vibrates the phone.
*/
public class TriggerReceiver extends AbstractTriggerReceiver {
/**
* Called when a local notification was triggered. Does present the local
* notification and re-schedule the alarm if necessary.
*
* @param notification
* Wrapper around the local notification
* @param updated
* If an update has triggered or the original
*/
@Override
public void onTrigger (Notification notification, boolean updated) {
if (notification.isRepeating()) {
notification.reschedule();
}
notification.show();
}
/**
* Build notification specified by options.
*
* @param builder
* Notification builder
*/
@Override
public Notification buildNotification (Builder builder) {
return builder.build();
}
}
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
...@@ -32,20 +34,24 @@ ...@@ -32,20 +34,24 @@
// Register permission to show notifications // Register permission to show notifications
- (void) registerPermission:(CDVInvokedUrlCommand*)command; - (void) registerPermission:(CDVInvokedUrlCommand*)command;
// Schedule a new notification // Schedule set of notifications
- (void) add:(CDVInvokedUrlCommand*)command; - (void) schedule:(CDVInvokedUrlCommand*)command;
// Update a notification // Update set of notifications
- (void) update:(CDVInvokedUrlCommand*)command; - (void) update:(CDVInvokedUrlCommand*)command;
// Cancel a given notification // Cancel set of notifications
- (void) cancel:(CDVInvokedUrlCommand*)command; - (void) cancel:(CDVInvokedUrlCommand*)command;
// Cancel all currently scheduled notifications // Cancel all notifications
- (void) cancelAll:(CDVInvokedUrlCommand*)command; - (void) cancelAll:(CDVInvokedUrlCommand*)command;
// Clear set of notifications
- (void) clear:(CDVInvokedUrlCommand*)command;
// Clear all notifications
- (void) clearAll:(CDVInvokedUrlCommand*)command;
// If a notification with an ID exists // If a notification with an ID is present
- (void) exist:(CDVInvokedUrlCommand*)command; - (void) isPresent:(CDVInvokedUrlCommand*)command;
// If a notification with an ID was scheduled // If a notification with an ID is scheduled
- (void) isScheduled:(CDVInvokedUrlCommand*)command; - (void) isScheduled:(CDVInvokedUrlCommand*)command;
// If a notification with an ID was triggered // If a notification with an ID is triggered
- (void) isTriggered:(CDVInvokedUrlCommand*)command; - (void) isTriggered:(CDVInvokedUrlCommand*)command;
// List all ids from all local notifications // List all ids from all local notifications
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
@interface APPLocalNotificationOptions : NSObject @interface APPLocalNotificationOptions : NSObject
...@@ -24,8 +26,6 @@ ...@@ -24,8 +26,6 @@
- (id) initWithDict:(NSDictionary*)dict; - (id) initWithDict:(NSDictionary*)dict;
@property (readonly, getter=id) NSString* id; @property (readonly, getter=id) NSString* id;
@property (readonly, getter=autoCancel) BOOL autoCancel;
@property (readonly, getter=json) NSString* json;
@property (readonly, getter=badgeNumber) NSInteger badgeNumber; @property (readonly, getter=badgeNumber) NSInteger badgeNumber;
@property (readonly, getter=alertBody) NSString* alertBody; @property (readonly, getter=alertBody) NSString* alertBody;
@property (readonly, getter=soundName) NSString* soundName; @property (readonly, getter=soundName) NSString* soundName;
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "APPLocalNotificationOptions.h" #import "APPLocalNotificationOptions.h"
#import <Cordova/CDVAvailability.h>
// Default sound ressource path
NSString* const DEFAULT_SOUND = @"res://platform_default";
@interface APPLocalNotificationOptions () @interface APPLocalNotificationOptions ()
...@@ -71,29 +75,9 @@ ...@@ -71,29 +75,9 @@
/** /**
* The notification's message. * The notification's message.
*/ */
- (NSString*) message - (NSString*) text
{
return [dict objectForKey:@"message"];
}
/**
* The notification's auto cancel flag.
*/
- (BOOL) autoCancel
{ {
if (IsAtLeastiOSVersion(@"8.0")){ return [dict objectForKey:@"text"];
return ![self isRepeating];
} else {
return [[dict objectForKey:@"autoCancel"] boolValue];
}
}
/**
* The notification's JSON data.
*/
- (NSString*) json
{
return [dict objectForKey:@"json"];
} }
/** /**
...@@ -101,13 +85,7 @@ ...@@ -101,13 +85,7 @@
*/ */
- (NSInteger) badgeNumber - (NSInteger) badgeNumber
{ {
NSInteger number = [[dict objectForKey:@"badge"] intValue]; return [[dict objectForKey:@"badge"] intValue];
if (number == -1) {
number = 1 + [UIApplication sharedApplication].applicationIconBadgeNumber;
}
return number;
} }
#pragma mark - #pragma mark -
...@@ -119,7 +97,7 @@ ...@@ -119,7 +97,7 @@
- (NSString*) alertBody - (NSString*) alertBody
{ {
NSString* title = [self title]; NSString* title = [self title];
NSString* msg = [self message]; NSString* msg = [self text];
NSString* alertBody = msg; NSString* alertBody = msg;
...@@ -139,16 +117,19 @@ ...@@ -139,16 +117,19 @@
{ {
NSString* path = [dict objectForKey:@"sound"]; NSString* path = [dict objectForKey:@"sound"];
if ([self stringIsNullOrEmpty:path])
return NULL;
if ([path isEqualToString:DEFAULT_SOUND])
return UILocalNotificationDefaultSoundName;
if ([path hasPrefix:@"file:/"]) if ([path hasPrefix:@"file:/"])
{
return [self soundNameForAsset:path]; return [self soundNameForAsset:path];
}
else if ([path hasPrefix:@"res:"]) if ([path hasPrefix:@"res:"])
{
return [self soundNameForResource:path]; return [self soundNameForResource:path];
}
return UILocalNotificationDefaultSoundName; return NULL;
} }
/** /**
...@@ -156,7 +137,7 @@ ...@@ -156,7 +137,7 @@
*/ */
- (NSDate*) fireDate - (NSDate*) fireDate
{ {
double timestamp = [[dict objectForKey:@"date"] double timestamp = [[dict objectForKey:@"at"]
doubleValue]; doubleValue];
return [NSDate dateWithTimeIntervalSince1970:timestamp]; return [NSDate dateWithTimeIntervalSince1970:timestamp];
...@@ -167,34 +148,30 @@ ...@@ -167,34 +148,30 @@
*/ */
- (NSCalendarUnit) repeatInterval - (NSCalendarUnit) repeatInterval
{ {
NSString* interval = [dict objectForKey:@"repeat"]; NSString* interval = [dict objectForKey:@"every"];
if ([interval isEqualToString:@"secondly"]) if ([self stringIsNullOrEmpty:interval]) {
{ return NSCalendarUnitEra;
}
else if ([interval isEqualToString:@"second"]) {
return NSCalendarUnitSecond; return NSCalendarUnitSecond;
} }
else if ([interval isEqualToString:@"minutely"]) else if ([interval isEqualToString:@"minute"]) {
{
return NSCalendarUnitMinute; return NSCalendarUnitMinute;
} }
else if ([interval isEqualToString:@"hourly"]) else if ([interval isEqualToString:@"houre"]) {
{
return NSCalendarUnitHour; return NSCalendarUnitHour;
} }
else if ([interval isEqualToString:@"daily"]) else if ([interval isEqualToString:@"day"]) {
{
return NSCalendarUnitDay; return NSCalendarUnitDay;
} }
else if ([interval isEqualToString:@"weekly"]) else if ([interval isEqualToString:@"week"]) {
{
return NSCalendarUnitWeekOfYear; return NSCalendarUnitWeekOfYear;
} }
else if ([interval isEqualToString:@"monthly"]) else if ([interval isEqualToString:@"month"]) {
{
return NSCalendarUnitMonth; return NSCalendarUnitMonth;
} }
else if ([interval isEqualToString:@"yearly"]) else if ([interval isEqualToString:@"year"]) {
{
return NSCalendarUnitYear; return NSCalendarUnitYear;
} }
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "AppDelegate.h" #import "AppDelegate.h"
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "AppDelegate+APPLocalNotification.h" #import "AppDelegate+APPLocalNotification.h"
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "UILocalNotification+APPLocalNotification.h"
@interface UIApplication (APPLocalNotification) @interface UIApplication (APPLocalNotification)
@property (readonly, getter=localNotifications) NSArray* localNotifications; @property (readonly, getter=localNotifications) NSArray* localNotifications;
@property (readonly, getter=scheduledLocalNotifications2) NSArray* triggeredLocalNotifications2;
@property (readonly, getter=triggeredLocalNotifications) NSArray* triggeredLocalNotifications;
@property (readonly, getter=localNotificationIds) NSArray* localNotificationIds; @property (readonly, getter=localNotificationIds) NSArray* localNotificationIds;
@property (readonly, getter=triggeredLocalNotificationIds) NSArray* triggeredLocalNotificationIds;
@property (readonly, getter=scheduledLocalNotificationIds) NSArray* scheduledLocalNotificationIds;
// If the app has the permission to schedule local notifications // If the app has the permission to schedule local notifications
- (BOOL) hasPermissionToScheduleLocalNotifications; - (BOOL) hasPermissionToScheduleLocalNotifications;
// Ask for permission to schedule local notifications // Ask for permission to schedule local notifications
- (void) registerPermissionToScheduleLocalNotifications; - (void) registerPermissionToScheduleLocalNotifications;
// Get local notification by ID // List of all local notification IDs from given type
- (NSArray*) localNotificationIdsByType:(APPLocalNotificationType)type;
// If local notification with ID exists
- (BOOL) localNotificationExist:(NSString*)id;
// If local notification with ID and type exists
- (BOOL) localNotificationExist:(NSString*)id type:(APPLocalNotificationType)type;
// Local notification by ID
- (UILocalNotification*) localNotificationWithId:(NSString*)id; - (UILocalNotification*) localNotificationWithId:(NSString*)id;
// Get scheduled local notification by ID // Local notification by ID and type
- (UILocalNotification*) scheduledLocalNotificationWithId:(NSString*)id; - (UILocalNotification*) localNotificationWithId:(NSString*)id andType:(APPLocalNotificationType)type;
// Get triggered local notification by ID
- (UILocalNotification*) triggeredLocalNotificationWithId:(NSString*)id;
// Property list from all local notifications // Property list from all local notifications
- (NSArray*) localNotificationOptions; - (NSArray*) localNotificationOptions;
// Property list from all scheduled notifications
- (NSArray*) scheduledLocalNotificationOptions;
// Property list from all triggered notifications
- (NSArray*) triggeredLocalNotificationOptions;
// Property list from given local notifications // Property list from given local notifications
- (NSArray*) localNotificationOptions:(NSArray*)ids; - (NSArray*) localNotificationOptionsById:(NSArray*)ids;
// Property list from given scheduled notifications // Property list from all local notifications with type constraint
- (NSArray*) scheduledLocalNotificationOptions:(NSArray*)ids; - (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type;
// Property list from given triggered notifications // Property list from given local notifications with type constraint
- (NSArray*) triggeredLocalNotificationOptions:(NSArray*)ids; - (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type andId:(NSArray*)ids;
// Clear single local notfications
- (void) clearLocalNotification:(UILocalNotification*)notification;
// Clear all local notfications
- (void) clearAllLocalNotifications;
@end @end
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "UIApplication+APPLocalNotification.h" #import "UIApplication+APPLocalNotification.h"
...@@ -101,7 +103,7 @@ ...@@ -101,7 +103,7 @@
for (UILocalNotification* notification in scheduledNotifications) for (UILocalNotification* notification in scheduledNotifications)
{ {
if (notification && [notification wasScheduled]) { if (notification && [notification isScheduled]) {
[notifications addObject:notification]; [notifications addObject:notification];
} }
} }
...@@ -120,7 +122,7 @@ ...@@ -120,7 +122,7 @@
for (UILocalNotification* notification in notifications) for (UILocalNotification* notification in notifications)
{ {
if ([notification wasTriggered]) { if ([notification isTriggered]) {
[triggeredNotifications addObject:notification]; [triggeredNotifications addObject:notification];
} }
} }
...@@ -129,8 +131,7 @@ ...@@ -129,8 +131,7 @@
} }
/** /**
* List of all triggered local notifications IDs which have been scheduled * List of all local notifications IDs.
* and not yet removed from the notification center.
*/ */
- (NSArray*) localNotificationIds - (NSArray*) localNotificationIds
{ {
...@@ -146,67 +147,58 @@ ...@@ -146,67 +147,58 @@
} }
/** /**
* List of all added local notifications IDs which have been scheduled * List of all local notifications IDs from given type.
* and not yet removed from the notification center. *
* @param type
* Notification life cycle type
*/ */
- (NSArray*) triggeredLocalNotificationIds - (NSArray*) localNotificationIdsByType:(APPLocalNotificationType)type
{ {
NSArray* notifications = self.triggeredLocalNotifications; NSArray* notifications = self.localNotifications;
NSMutableArray* ids = [[NSMutableArray alloc] init]; NSMutableArray* ids = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications) for (UILocalNotification* notification in notifications)
{ {
[ids addObject:notification.options.id]; if (notification.type == type) {
[ids addObject:notification.options.id];
}
} }
return ids; return ids;
} }
/** /*
* List of all scheduled local notifications IDs. * If local notification with ID exists.
*
* @param id
* Notification ID
*/ */
- (NSArray*) scheduledLocalNotificationIds - (BOOL) localNotificationExist:(NSString*)id
{ {
NSArray* notifications = self.scheduledLocalNotifications2; return [self localNotificationWithId:id] != NULL;
NSMutableArray* ids = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications)
{
[ids addObject:notification.options.id];
}
return ids;
} }
/** /* If local notification with ID and type exists
* Get local notification by ID.
* *
* @param id * @param id
* Notification ID * Notification ID
* @param type
* Notification life cycle type
*/ */
- (UILocalNotification*) localNotificationWithId:(NSString*)id - (BOOL) localNotificationExist:(NSString*)id type:(APPLocalNotificationType)type
{ {
NSArray* notifications = self.localNotifications; return [self localNotificationWithId:id andType:type] != NULL;
for (UILocalNotification* notification in notifications)
{
if ([notification.options.id isEqualToString:id]) {
return notification;
}
}
return NULL;
} }
/** /**
* Get scheduled local notification by ID. * Get local notification with ID.
* *
* @param id * @param id
* Notification ID * Notification ID
*/ */
- (UILocalNotification*) scheduledLocalNotificationWithId:(NSString*)id - (UILocalNotification*) localNotificationWithId:(NSString*)id
{ {
NSArray* notifications = self.scheduledLocalNotifications2; NSArray* notifications = self.localNotifications;
for (UILocalNotification* notification in notifications) for (UILocalNotification* notification in notifications)
{ {
...@@ -218,19 +210,20 @@ ...@@ -218,19 +210,20 @@
return NULL; return NULL;
} }
/** /*
* Get triggered local notification by ID. * Get local notification with ID and type.
* *
* @param id * @param id
* Notification ID * Notification ID
* @param type
* Notification life cycle type
*/ */
- (UILocalNotification*) triggeredLocalNotificationWithId:(NSString*)id - (UILocalNotification*) localNotificationWithId:(NSString*)id andType:(APPLocalNotificationType)type
{ {
UILocalNotification* notification = [self localNotificationWithId:id]; UILocalNotification* notification = [self localNotificationWithId:id];
if (notification && [notification wasTriggered]) { if (notification && notification.type == type)
return notification; return notification;
}
return NULL; return NULL;
} }
...@@ -252,32 +245,21 @@ ...@@ -252,32 +245,21 @@
} }
/** /**
* List of properties from all scheduled notifications. * List of properties from all local notifications from given type.
*/ *
- (NSArray*) scheduledLocalNotificationOptions * @param type
{ * Notification life cycle type
NSArray* notifications = [self scheduledLocalNotifications2];
NSMutableArray* options = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications)
{
[options addObject:notification.userInfo];
}
return options;
}
/**
* List of properties from all triggered notifications.
*/ */
- (NSArray*) triggeredLocalNotificationOptions - (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type
{ {
NSArray* notifications = self.triggeredLocalNotifications; NSArray* notifications = self.localNotifications;
NSMutableArray* options = [[NSMutableArray alloc] init]; NSMutableArray* options = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications) for (UILocalNotification* notification in notifications)
{ {
[options addObject:notification.userInfo]; if (notification.type == type) {
[options addObject:notification.userInfo];
}
} }
return options; return options;
...@@ -289,7 +271,7 @@ ...@@ -289,7 +271,7 @@
* @param ids * @param ids
* Notification IDs * Notification IDs
*/ */
- (NSArray*) localNotificationOptions:(NSArray*)ids - (NSArray*) localNotificationOptionsById:(NSArray*)ids
{ {
UILocalNotification* notification; UILocalNotification* notification;
NSMutableArray* options = [[NSMutableArray alloc] init]; NSMutableArray* options = [[NSMutableArray alloc] init];
...@@ -307,21 +289,23 @@ ...@@ -307,21 +289,23 @@
} }
/** /**
* List of properties from given scheduled notifications. * List of properties from given local notifications.
* *
* @param type
* Notification life cycle type
* @param ids * @param ids
* Notification IDs * Notification IDs
*/ */
- (NSArray*) scheduledLocalNotificationOptions:(NSArray*)ids - (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type andId:(NSArray*)ids
{ {
UILocalNotification* notification; UILocalNotification* notification;
NSMutableArray* options = [[NSMutableArray alloc] init]; NSMutableArray* options = [[NSMutableArray alloc] init];
for (NSString* id in ids) for (NSString* id in ids)
{ {
notification = [self scheduledLocalNotificationWithId:id]; notification = [self localNotificationWithId:id];
if (notification) { if (notification && notification.type == type) {
[options addObject:notification.userInfo]; [options addObject:notification.userInfo];
} }
} }
...@@ -329,27 +313,33 @@ ...@@ -329,27 +313,33 @@
return options; return options;
} }
/** /*
* List of properties from given triggered notifications. * Clear all local notfications.
*
* @param ids
* Notification IDs
*/ */
- (NSArray*) triggeredLocalNotificationOptions:(NSArray*)ids - (void) clearAllLocalNotifications
{ {
UILocalNotification* notification; NSArray* notifications = self.triggeredLocalNotifications;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (NSString* id in ids)
{
notification = [self triggeredLocalNotificationWithId:id];
if (notification) { for (UILocalNotification* notification in notifications) {
[options addObject:notification.userInfo]; [self clearLocalNotification:notification];
}
} }
}
return options; /*
* Clear single local notfication.
*
* @param notification
* The local notification object
*/
- (void) clearLocalNotification:(UILocalNotification*)notification
{
[self cancelLocalNotification:notification];
if ([notification isRepeating]) {
notification.fireDate = notification.options.fireDate;
[self scheduleLocalNotification:notification];
};
} }
@end @end
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "APPLocalNotificationOptions.h" #import "APPLocalNotificationOptions.h"
typedef NS_ENUM(NSUInteger, APPLocalNotificationType) {
NotifcationTypeAll = 0,
NotifcationTypeScheduled = 1,
NotifcationTypeTriggered = 2
};
@interface UILocalNotification (APPLocalNotification) @interface UILocalNotification (APPLocalNotification)
// Initialize a new local notification // Initialize a new local notification
- (id) initWithOptions:(NSDictionary*)dict; - (id) initWithOptions:(NSDictionary*)dict;
// The options provided by the plug-in // The options provided by the plug-in
- (APPLocalNotificationOptions*) options; - (APPLocalNotificationOptions*) options;
// Timeinterval since last trigger date
- (double) timeIntervalSinceLastTrigger;
// Timeinterval since fire date // Timeinterval since fire date
- (double) timeIntervalSinceFireDate; - (double) timeIntervalSinceFireDate;
// If the fire date was in the past // If the fire date was in the past
- (BOOL) wasInThePast; - (BOOL) wasInThePast;
// If the notification was already scheduled // If the notification was already scheduled
- (BOOL) wasScheduled; - (BOOL) isScheduled;
// If the notification was already triggered // If the notification was already triggered
- (BOOL) wasTriggered; - (BOOL) isTriggered;
// If the notification was updated // If the notification was updated
- (BOOL) wasUpdated; - (BOOL) wasUpdated;
// If it's a repeating notification // If it's a repeating notification
- (BOOL) isRepeating; - (BOOL) isRepeating;
// Notifciation type
- (APPLocalNotificationType) type;
// Encode the user info dict to JSON // Encode the user info dict to JSON
- (NSString*) encodeToJSON; - (NSString*) encodeToJSON;
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "UILocalNotification+APPLocalNotification.h" #import "UILocalNotification+APPLocalNotification.h"
...@@ -25,6 +27,9 @@ ...@@ -25,6 +27,9 @@
static char optionsKey; static char optionsKey;
NSInteger const APPLocalNotificationTypeScheduled = 1;
NSInteger const APPLocalNotificationTypeTriggered = 2;
@implementation UILocalNotification (APPLocalNotification) @implementation UILocalNotification (APPLocalNotification)
#pragma mark - #pragma mark -
...@@ -131,10 +136,20 @@ static char optionsKey; ...@@ -131,10 +136,20 @@ static char optionsKey;
- (double) timeIntervalSinceFireDate - (double) timeIntervalSinceFireDate
{ {
NSDate* now = [NSDate date]; NSDate* now = [NSDate date];
NSDate* fireDate = self.options.fireDate; NSDate* fireDate = self.fireDate;
int timespan = [now timeIntervalSinceDate:fireDate]; int timespan = [now timeIntervalSinceDate:fireDate];
return timespan;
}
/**
* Timeinterval since last trigger date.
*/
- (double) timeIntervalSinceLastTrigger
{
int timespan = [self timeIntervalSinceFireDate];
if ([self isRepeating]) { if ([self isRepeating]) {
timespan = timespan % [self repeatIntervalInSeconds]; timespan = timespan % [self repeatIntervalInSeconds];
} }
...@@ -173,11 +188,11 @@ static char optionsKey; ...@@ -173,11 +188,11 @@ static char optionsKey;
*/ */
- (BOOL) wasInThePast - (BOOL) wasInThePast
{ {
return [self timeIntervalSinceFireDate] > 0; return [self timeIntervalSinceLastTrigger] > 0;
} }
// If the notification was already scheduled // If the notification was already scheduled
- (BOOL) wasScheduled - (BOOL) isScheduled
{ {
return [self isRepeating] || ![self wasInThePast]; return [self isRepeating] || ![self wasInThePast];
} }
...@@ -185,7 +200,7 @@ static char optionsKey; ...@@ -185,7 +200,7 @@ static char optionsKey;
/** /**
* If the notification was already triggered. * If the notification was already triggered.
*/ */
- (BOOL) wasTriggered - (BOOL) isTriggered
{ {
NSDate* now = [NSDate date]; NSDate* now = [NSDate date];
NSDate* fireDate = self.fireDate; NSDate* fireDate = self.fireDate;
...@@ -219,4 +234,12 @@ static char optionsKey; ...@@ -219,4 +234,12 @@ static char optionsKey;
return [self.options isRepeating]; return [self.options isRepeating];
} }
/**
* Process state type of the local notification.
*/
- (APPLocalNotificationType) type
{
return [self isTriggered] ? NotifcationTypeTriggered : NotifcationTypeScheduled;
}
@end @end
/*
Copyright 2013-2014 appPlant UG
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
using System;
using System.Linq;
using Microsoft.Phone.Shell;
using WPCordovaClassLib.Cordova;
using WPCordovaClassLib.Cordova.Commands;
using WPCordovaClassLib.Cordova.JSON;
using De.APPPlant.Cordova.Plugin.LocalNotification;
namespace Cordova.Extension.Commands
{
/// <summary>
/// Implementes access to application live tiles
/// http://msdn.microsoft.com/en-us/library/hh202948(v=VS.92).aspx
/// </summary>
public class LocalNotification : BaseCommand
{
/// <summary>
/// Informs if the device is ready and the deviceready event has been fired
/// </summary>
private bool DeviceReady = false;
/// <summary>
/// Informs either the app is running in background or foreground
/// </summary>
private bool RunsInBackground = false;
/// <summary>
/// Sets application live tile
/// </summary>
public void add (string jsonArgs)
{
string[] args = JsonHelper.Deserialize<string[]>(jsonArgs);
Options options = JsonHelper.Deserialize<Options>(args[0]);
// Application Tile is always the first Tile, even if it is not pinned to Start.
ShellTile AppTile = ShellTile.ActiveTiles.First();
if (AppTile != null)
{
// Set the properties to update for the Application Tile
// Empty strings for the text values and URIs will result in the property being cleared.
FlipTileData TileData = CreateTileData(options);
AppTile.Update(TileData);
FireEvent("trigger", options.ID, options.JSON);
FireEvent("add", options.ID, options.JSON);
}
DispatchCommandResult();
}
/// <summary>
/// Clears the application live tile
/// </summary>
public void cancel (string jsonArgs)
{
string[] args = JsonHelper.Deserialize<string[]>(jsonArgs);
string notificationID = args[0];
cancelAll(jsonArgs);
FireEvent("cancel", notificationID, "");
DispatchCommandResult();
}
/// <summary>
/// Clears the application live tile
/// </summary>
public void cancelAll (string jsonArgs)
{
// Application Tile is always the first Tile, even if it is not pinned to Start.
ShellTile AppTile = ShellTile.ActiveTiles.First();
if (AppTile != null)
{
// Set the properties to update for the Application Tile
// Empty strings for the text values and URIs will result in the property being cleared.
FlipTileData TileData = new FlipTileData
{
Count = 0,
BackTitle = "",
BackContent = "",
WideBackContent = "",
SmallBackgroundImage = new Uri("appdata:Background.png"),
BackgroundImage = new Uri("appdata:Background.png"),
WideBackgroundImage = new Uri("/Assets/Tiles/FlipCycleTileLarge.png", UriKind.Relative),
};
// Update the Application Tile
AppTile.Update(TileData);
}
DispatchCommandResult();
}
/// <summary>
/// Checks wether a notification with an ID is scheduled
/// </summary>
public void isScheduled (string jsonArgs)
{
DispatchCommandResult();
}
/// <summary>
/// Retrieves a list with all currently pending notifications
/// </summary>
public void getScheduledIds (string jsonArgs)
{
DispatchCommandResult();
}
/// <summary>
/// Checks wether a notification with an ID was triggered
/// </summary>
public void isTriggered (string jsonArgs)
{
DispatchCommandResult();
}
/// <summary>
/// Retrieves a list with all currently triggered notifications
/// </summary>
public void getTriggeredIds (string jsonArgs)
{
DispatchCommandResult();
}
/// <summary>
/// Informs that the device is ready and the deviceready event has been fired
/// </summary>
public void deviceready (string jsonArgs)
{
DeviceReady = true;
}
/// <summary>
/// Creates tile data
/// </summary>
private FlipTileData CreateTileData (Options options)
{
FlipTileData tile = new FlipTileData();
// Badge sollte nur gelöscht werden, wenn expliziet eine `0` angegeben wurde
if (options.Badge != 0)
{
tile.Count = options.Badge;
}
tile.BackTitle = options.Title;
tile.BackContent = options.ShortMessage;
tile.WideBackContent = options.Message;
if (!String.IsNullOrEmpty(options.SmallImage))
{
tile.SmallBackgroundImage = new Uri(options.SmallImage, UriKind.RelativeOrAbsolute);
}
if (!String.IsNullOrEmpty(options.Image))
{
tile.BackgroundImage = new Uri(options.Image, UriKind.RelativeOrAbsolute);
}
if (!String.IsNullOrEmpty(options.WideImage))
{
tile.WideBackgroundImage = new Uri(options.WideImage, UriKind.RelativeOrAbsolute);
}
return tile;
}
/// <summary>
/// Fires the given event.
/// </summary>
private void FireEvent (string Event, string Id, string JSON = "")
{
string state = ApplicationState();
string args = String.Format("\'{0}\',\'{1}\',\'{2}\'", Id, state, JSON);
string js = String.Format("window.plugin.notification.local.on{0}({1})", Event, args);
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, js);
pluginResult.KeepCallback = true;
DispatchCommandResult(pluginResult);
}
/// <summary>
/// Retrieves the application state
/// Either "background" or "foreground"
/// </summary>
private String ApplicationState ()
{
return RunsInBackground ? "background" : "foreground";
}
/// <summary>
/// Occurs when the application is being deactivated.
/// </summary>
public override void OnPause (object sender, DeactivatedEventArgs e)
{
RunsInBackground = true;
}
/// <summary>
/// Occurs when the application is being made active after previously being put
/// into a dormant state or tombstoned.
/// </summary>
public override void OnResume (object sender, Microsoft.Phone.Shell.ActivatedEventArgs e)
{
RunsInBackground = false;
}
}
}
/*
Copyright 2013-2014 appPlant UG
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
using System;
using System.Linq;
using System.Runtime.Serialization;
namespace De.APPPlant.Cordova.Plugin.LocalNotification
{
/// <summary>
/// Represents LiveTile options
/// </summary>
[DataContract]
class Options
{
/// <summary>
/// The Title that is displayed
/// </summary>
[DataMember(IsRequired = false, Name = "title")]
public string Title { get; set; }
/// <summary>
/// The message that is displayed
/// </summary>
[DataMember(IsRequired = false, Name = "message")]
public string Message { get; set; }
/// <summary>
/// Gekürzte Nachricht (alles ab dem Zeilenumbruch entfernt)
/// </summary>
public string ShortMessage
{
get
{
string[] separator = new string[] { "\r\n", "\n" };
return Message.Split(separator, StringSplitOptions.RemoveEmptyEntries).First();
}
}
/// <summary>
/// Displays number badge to notification
/// </summary>
[DataMember(IsRequired = false, Name = "badge")]
public int Badge { get; set; }
/// <summary>
/// Tile count
/// </summary>
[DataMember(IsRequired = false, Name = "Date")]
public int Date { get; set; }
/// <summary>
/// Has the options of daily', 'weekly',''monthly','yearly')
/// </summary>
[DataMember(IsRequired = false, Name = "repeat")]
public string Repeat { get; set; }
/// <summary>
/// Notification specific data
/// </summary>
[DataMember(IsRequired = false, Name = "json")]
public string JSON { get; set; }
/// <summary>
/// Message-ID
/// </summary>
[DataMember(IsRequired = false, Name = "id")]
public string ID { get; set; }
/// <summary>
/// Setting this flag will make it so the notification is automatically canceled when the user clicks it
/// </summary>
[DataMember(IsRequired = false, Name = "autoCancel")]
public bool AutoCancel { get; set; }
/// <summary>
/// The notification small background image to be displayed
/// </summary>
[DataMember(IsRequired = false, Name = "smallImage")]
public string SmallImage { get; set; }
/// <summary>
/// The notification background image to be displayed
/// </summary>
[DataMember(IsRequired = false, Name = "image")]
public string Image { get; set; }
/// <summary>
/// The notification wide background image to be displayed
/// </summary>
[DataMember(IsRequired = false, Name = "wideImage")]
public string WideImage { get; set; }
}
}
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