Commit 6e0cb626 by Sebastián Katzer

WIP Android

parent 8366689e
{ {
"name": "cordova-plugin-local-notifications", "name": "cordova-plugin-local-notifications",
"version": "0.0.0", "version": "0.0.9",
"description": "Schedules and queries for local notifications", "description": "Schedules and queries for local notifications",
"cordova": { "cordova": {
"id": "cordova-plugin-local-notifications", "id": "cordova-plugin-local-notifications",
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,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="cordova-plugin-local-notifications" id="cordova-plugin-local-notifications"
version="0.0.0"> version="0.9.0">
<name>LocalNotification</name> <name>LocalNotification</name>
...@@ -40,10 +40,11 @@ ...@@ -40,10 +40,11 @@
<!-- cordova --> <!-- cordova -->
<engines> <engines>
<engine name="cordova" version=">=3.6.0" /> <engine name="cordova" version=">=3.6.0" />
<engine name="cordova-plugman" version=">=4.3.0" /> <engine name="cordova-plugman" version=">=4.3.0" />
<engine name="cordova-windows" version=">=4.2.0" /> <engine name="cordova-windows" version=">=4.2.0" />
<engine name="apple-ios" version=">=10.0.0" /> <engine name="apple-ios" version=">=10.0.0" />
<engine name="cordova-android" version=">=6.0.0" />
</engines> </engines>
<!-- dependencies --> <!-- dependencies -->
...@@ -66,7 +67,6 @@ ...@@ -66,7 +67,6 @@
<!-- ios --> <!-- ios -->
<platform name="ios"> <platform name="ios">
<config-file target="config.xml" parent="/*"> <config-file target="config.xml" parent="/*">
<feature name="LocalNotification"> <feature name="LocalNotification">
<param name="ios-package" value="APPLocalNotification" onload="true" /> <param name="ios-package" value="APPLocalNotification" onload="true" />
...@@ -91,13 +91,11 @@ ...@@ -91,13 +91,11 @@
<header-file src="src/ios/UNNotificationRequest+APPLocalNotification.h" /> <header-file src="src/ios/UNNotificationRequest+APPLocalNotification.h" />
<source-file src="src/ios/UNNotificationRequest+APPLocalNotification.m" /> <source-file src="src/ios/UNNotificationRequest+APPLocalNotification.m" />
</platform> </platform>
<!-- android --> <!-- android -->
<!-- <platform name="android"> <platform name="android">
<framework src="com.android.support:support-v4:26.+" value="gradle" />
<framework src="com.android.support:support-v4:+" value="gradle" />
<config-file target="res/xml/config.xml" parent="/*"> <config-file target="res/xml/config.xml" parent="/*">
<feature name="LocalNotification"> <feature name="LocalNotification">
...@@ -106,7 +104,6 @@ ...@@ -106,7 +104,6 @@
</config-file> </config-file>
<config-file target="AndroidManifest.xml" parent="/manifest/application"> <config-file target="AndroidManifest.xml" parent="/manifest/application">
<receiver <receiver
android:name="de.appplant.cordova.plugin.localnotification.TriggerReceiver" android:name="de.appplant.cordova.plugin.localnotification.TriggerReceiver"
android:exported="false" /> android:exported="false" />
...@@ -118,33 +115,19 @@ ...@@ -118,33 +115,19 @@
<activity <activity
android:name="de.appplant.cordova.plugin.localnotification.ClickActivity" android:name="de.appplant.cordova.plugin.localnotification.ClickActivity"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:theme="@android:style/Theme.NoDisplay" android:theme="@android:style/Theme.Translucent"
android:exported="false" />
<receiver
android:name="de.appplant.cordova.plugin.notification.TriggerReceiver"
android:exported="false" />
<receiver
android:name="de.appplant.cordova.plugin.notification.ClearReceiver"
android:exported="false" /> android:exported="false" />
<!--
<receiver android:name="de.appplant.cordova.plugin.localnotification.RestoreReceiver" android:exported="false" > <receiver android:name="de.appplant.cordova.plugin.localnotification.RestoreReceiver" android:exported="false" >
<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"
android:exported="false" />
</config-file> </config-file>
<config-file target="AndroidManifest.xml" parent="/manifest"> <config-file target="AndroidManifest.xml" parent="/manifest">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <!-- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</config-file> </config-file>
...@@ -163,41 +146,57 @@ ...@@ -163,41 +146,57 @@
<source-file <source-file
src="src/android/ClearReceiver.java" src="src/android/ClearReceiver.java"
target-dir="src/de/appplant/cordova/plugin/localnotification" /> target-dir="src/de/appplant/cordova/plugin/localnotification" />
<!--
<source-file <source-file
src="src/android/RestoreReceiver.java" src="src/android/RestoreReceiver.java"
target-dir="src/de/appplant/cordova/plugin/localnotification" /> target-dir="src/de/appplant/cordova/plugin/localnotification" />
-->
<source-file
src="src/android/notification/activity/AbstractClickActivity.java"
target-dir="src/de/appplant/cordova/plugin/notification/activity" />
<source-file <source-file
src="src/android/notification/AbstractClearReceiver.java" src="src/android/notification/activity/ClickActivity.java"
target-dir="src/de/appplant/cordova/plugin/notification" /> target-dir="src/de/appplant/cordova/plugin/notification/activity" />
<source-file <source-file
src="src/android/notification/AbstractClickActivity.java" src="src/android/notification/receiver/AbstractClearReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" /> target-dir="src/de/appplant/cordova/plugin/notification/receiver" />
<!--
<source-file
src="src/android/notification/receiver/AbstractRestoreReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification/receiver" />
-->
<source-file
src="src/android/notification/receiver/AbstractTriggerReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification/receiver" />
<source-file <source-file
src="src/android/notification/AbstractRestoreReceiver.java" src="src/android/notification/receiver/ClearReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" /> target-dir="src/de/appplant/cordova/plugin/notification/receiver" />
<source-file <source-file
src="src/android/notification/AbstractTriggerReceiver.java" src="src/android/notification/receiver/TriggerReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" /> target-dir="src/de/appplant/cordova/plugin/notification/receiver" />
<source-file <source-file
src="src/android/notification/AssetUtil.java" src="src/android/notification/trigger/DateTrigger.java"
target-dir="src/de/appplant/cordova/plugin/notification" /> target-dir="src/de/appplant/cordova/plugin/notification/trigger" />
<source-file <source-file
src="src/android/notification/Builder.java" src="src/android/notification/trigger/IntervalTrigger.java"
target-dir="src/de/appplant/cordova/plugin/notification" /> target-dir="src/de/appplant/cordova/plugin/notification/trigger" />
<source-file <source-file
src="src/android/notification/ClearReceiver.java" src="src/android/notification/trigger/MatchTrigger.java"
target-dir="src/de/appplant/cordova/plugin/notification" /> target-dir="src/de/appplant/cordova/plugin/notification/trigger" />
<source-file <source-file
src="src/android/notification/ClickActivity.java" src="src/android/notification/util/AssetUtil.java"
target-dir="src/de/appplant/cordova/plugin/notification/util" />
<source-file
src="src/android/notification/Builder.java"
target-dir="src/de/appplant/cordova/plugin/notification" /> target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file <source-file
...@@ -213,17 +212,12 @@ ...@@ -213,17 +212,12 @@
target-dir="src/de/appplant/cordova/plugin/notification" /> target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file <source-file
src="src/android/notification/TriggerReceiver.java" src="src/android/notification/Request.java"
target-dir="src/de/appplant/cordova/plugin/notification" /> target-dir="src/de/appplant/cordova/plugin/notification" />
</platform>
</platform> -->
<!-- windows --> <!-- windows -->
<platform name="windows"> <platform name="windows">
<config-file target="config.xml" parent="/*" >
<preference name="WindowsToastCapable" value="true" />
</config-file>
<framework src="src/windows/lib.UW/ARM/LocalNotificationProxy.winmd" target-dir="x86" arch="x86" custom="true"/> <framework src="src/windows/lib.UW/ARM/LocalNotificationProxy.winmd" target-dir="x86" arch="x86" custom="true"/>
<framework src="src/windows/lib.UW/ARM/LocalNotificationProxy.winmd" target-dir="x64" arch="x64" custom="true"/> <framework src="src/windows/lib.UW/ARM/LocalNotificationProxy.winmd" target-dir="x64" arch="x64" custom="true"/>
<framework src="src/windows/lib.UW/ARM/LocalNotificationProxy.winmd" target-dir="ARM" arch="ARM" custom="true"/> <framework src="src/windows/lib.UW/ARM/LocalNotificationProxy.winmd" target-dir="ARM" arch="ARM" custom="true"/>
......
...@@ -29,13 +29,12 @@ import de.appplant.cordova.plugin.notification.Notification; ...@@ -29,13 +29,12 @@ import de.appplant.cordova.plugin.notification.Notification;
* notification manually. It un-persists the cleared notification from the * notification manually. It un-persists the cleared notification from the
* shared preferences. * shared preferences.
*/ */
public class ClearReceiver extends de.appplant.cordova.plugin.notification.ClearReceiver { public class ClearReceiver extends de.appplant.cordova.plugin.notification.receiver.ClearReceiver {
/** /**
* Called when a local notification was cleared from outside of the app. * Called when a local notification was cleared from outside of the app.
* *
* @param notification * @param notification Wrapper around the local notification
* Wrapper around the local notification
*/ */
@Override @Override
public void onClear (Notification notification) { public void onClear (Notification notification) {
......
...@@ -21,22 +21,19 @@ ...@@ -21,22 +21,19 @@
package de.appplant.cordova.plugin.localnotification; package de.appplant.cordova.plugin.localnotification;
import de.appplant.cordova.plugin.notification.Builder;
import de.appplant.cordova.plugin.notification.Notification; import de.appplant.cordova.plugin.notification.Notification;
import de.appplant.cordova.plugin.notification.TriggerReceiver;
/** /**
* The receiver activity is triggered when a notification is clicked by a user. * The receiver activity is triggered when a notification is clicked by a user.
* The activity calls the background callback and brings the launch intent * The activity calls the background callback and brings the launch intent
* up to foreground. * up to foreground.
*/ */
public class ClickActivity extends de.appplant.cordova.plugin.notification.ClickActivity { public class ClickActivity extends de.appplant.cordova.plugin.notification.activity.ClickActivity {
/** /**
* Called when local notification was clicked by the user. * Called when local notification was clicked by the user.
* *
* @param notification * @param notification Wrapper around the local notification
* Wrapper around the local notification
*/ */
@Override @Override
public void onClick(Notification notification) { public void onClick(Notification notification) {
...@@ -44,24 +41,11 @@ public class ClickActivity extends de.appplant.cordova.plugin.notification.Click ...@@ -44,24 +41,11 @@ public class ClickActivity extends de.appplant.cordova.plugin.notification.Click
super.onClick(notification); super.onClick(notification);
if (notification.getOptions().isOngoing()) // if (notification.getOptions().isOngoing())
return; // return;
String event = notification.isRepeating() ? "clear" : "cancel"; // String event = notification.isRepeating() ? "clear" : "cancel";
LocalNotification.fireEvent(event, notification); // LocalNotification.fireEvent(event, notification);
}
/**
* Build notification specified by options.
*
* @param builder
* Notification builder
*/
@Override
public Notification buildNotification (Builder builder) {
return builder
.setTriggerReceiver(TriggerReceiver.class)
.build();
} }
} }
...@@ -30,16 +30,14 @@ import de.appplant.cordova.plugin.notification.Notification; ...@@ -30,16 +30,14 @@ import de.appplant.cordova.plugin.notification.Notification;
* Android notification bar. The notification uses the default notification * Android notification bar. The notification uses the default notification
* sound and it vibrates the phone. * sound and it vibrates the phone.
*/ */
public class TriggerReceiver extends de.appplant.cordova.plugin.notification.TriggerReceiver { public class TriggerReceiver extends de.appplant.cordova.plugin.notification.receiver.TriggerReceiver {
/** /**
* Called when a local notification was triggered. Does present the local * Called when a local notification was triggered. Does present the local
* notification, re-schedule the alarm if necessary and fire trigger event. * notification, re-schedule the alarm if necessary and fire trigger event.
* *
* @param notification * @param notification Wrapper around the local notification
* Wrapper around the local notification * @param updated If an update has triggered or the original
* @param updated
* If an update has triggered or the original
*/ */
@Override @Override
public void onTrigger (Notification notification, boolean updated) { public void onTrigger (Notification notification, boolean updated) {
...@@ -53,13 +51,11 @@ public class TriggerReceiver extends de.appplant.cordova.plugin.notification.Tri ...@@ -53,13 +51,11 @@ public class TriggerReceiver extends de.appplant.cordova.plugin.notification.Tri
/** /**
* Build notification specified by options. * Build notification specified by options.
* *
* @param builder * @param builder Notification builder
* Notification builder
*/ */
@Override @Override
public Notification buildNotification (Builder builder) { public Notification buildNotification (Builder builder) {
return builder return builder
.setTriggerReceiver(TriggerReceiver.class)
.setClickActivity(ClickActivity.class) .setClickActivity(ClickActivity.class)
.setClearReceiver(ClearReceiver.class) .setClearReceiver(ClearReceiver.class)
.build(); .build();
......
...@@ -24,13 +24,13 @@ package de.appplant.cordova.plugin.notification; ...@@ -24,13 +24,13 @@ package de.appplant.cordova.plugin.notification;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationCompat;
import org.json.JSONObject;
import java.util.Random; import java.util.Random;
import de.appplant.cordova.plugin.notification.activity.ClickActivity;
import de.appplant.cordova.plugin.notification.receiver.ClearReceiver;
/** /**
* Builder class for local notifications. Build fully configured local * Builder class for local notifications. Build fully configured local
* notification specified by JSON object passed from JS side. * notification specified by JSON object passed from JS side.
...@@ -43,9 +43,6 @@ public class Builder { ...@@ -43,9 +43,6 @@ public class Builder {
// Notification options passed by JS // Notification options passed by JS
private final Options options; private final Options options;
// Receiver to handle the trigger event
private Class<?> triggerReceiver;
// Receiver to handle the clear event // Receiver to handle the clear event
private Class<?> clearReceiver = ClearReceiver.class; private Class<?> clearReceiver = ClearReceiver.class;
...@@ -55,21 +52,7 @@ public class Builder { ...@@ -55,21 +52,7 @@ public class Builder {
/** /**
* Constructor * Constructor
* *
* @param context * @param options Notification options
* 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) { public Builder(Options options) {
this.context = options.getContext(); this.context = options.getContext();
...@@ -77,21 +60,9 @@ public class Builder { ...@@ -77,21 +60,9 @@ public class Builder {
} }
/** /**
* Set trigger receiver.
*
* @param receiver
* Broadcast receiver
*/
public Builder setTriggerReceiver(Class<?> receiver) {
this.triggerReceiver = receiver;
return this;
}
/**
* Set clear receiver. * Set clear receiver.
* *
* @param receiver * @param receiver Broadcast receiver for the clear event.
* Broadcast receiver
*/ */
public Builder setClearReceiver(Class<?> receiver) { public Builder setClearReceiver(Class<?> receiver) {
this.clearReceiver = receiver; this.clearReceiver = receiver;
...@@ -101,8 +72,7 @@ public class Builder { ...@@ -101,8 +72,7 @@ public class Builder {
/** /**
* Set click activity. * Set click activity.
* *
* @param activity * @param activity The activity to handler the click event.
* Activity
*/ */
public Builder setClickActivity(Class<?> activity) { public Builder setClickActivity(Class<?> activity) {
this.clickActivity = activity; this.clickActivity = activity;
...@@ -111,50 +81,45 @@ public class Builder { ...@@ -111,50 +81,45 @@ public class Builder {
/** /**
* Creates the notification with all its options passed through JS. * Creates the notification with all its options passed through JS.
*
* @return The final notification to display.
*/ */
public Notification build() { public Notification build() {
Uri sound = options.getSoundUri();
int smallIcon = options.getSmallIcon(); int smallIcon = options.getSmallIcon();
int ledColor = options.getLedColor();
NotificationCompat.Builder builder; NotificationCompat.Builder builder;
builder = new NotificationCompat.Builder(context) builder = new NotificationCompat.Builder(context, "group")
.setDefaults(0) .setDefaults(options.getDefaults())
.setContentTitle(options.getTitle()) .setContentTitle(options.getTitle())
.setContentText(options.getText()) .setContentText(options.getText())
.setNumber(options.getBadgeNumber()) .setNumber(options.getBadgeNumber())
.setTicker(options.getText())
.setAutoCancel(options.isAutoClear()) .setAutoCancel(options.isAutoClear())
.setOngoing(options.isOngoing()) .setOngoing(options.isSticky())
.setColor(options.getColor()); .setColor(options.getColor())
.setSound(options.getSound())
if (ledColor != 0) { .setVisibility(options.getVisibility())
builder.setLights(ledColor, 100, 100); .setPriority(options.getPriority())
} .setShowWhen(options.getShowWhen())
.setLights(options.getLedColor(), options.getLedOn(), options.getLedOff());
if (sound != null) {
builder.setSound(sound); if (smallIcon != 0) {
} builder.setSmallIcon(smallIcon);
builder.setLargeIcon(options.getLargeIcon());
if (smallIcon == 0) {
builder.setSmallIcon(options.getIcon());
} else { } else {
builder.setSmallIcon(options.getSmallIcon()); builder.setSmallIcon(options.getIcon());
builder.setLargeIcon(options.getIconBitmap());
} }
applyDeleteReceiver(builder); applyDeleteReceiver(builder);
applyContentReceiver(builder); applyContentReceiver(builder);
return new Notification(context, options, builder, triggerReceiver); return new Notification(context, options, builder);
} }
/** /**
* Set intent to handle the delete event. Will clean up some persisted * Set intent to handle the delete event. Will clean up some persisted
* preferences. * preferences.
* *
* @param builder * @param builder Local notification builder instance
* Local notification builder instance
*/ */
private void applyDeleteReceiver(NotificationCompat.Builder builder) { private void applyDeleteReceiver(NotificationCompat.Builder builder) {
...@@ -162,7 +127,7 @@ public class Builder { ...@@ -162,7 +127,7 @@ public class Builder {
return; return;
Intent intent = new Intent(context, clearReceiver) Intent intent = new Intent(context, clearReceiver)
.setAction(options.getIdStr()) .setAction(options.getIdentifier())
.putExtra(Options.EXTRA, options.toString()); .putExtra(Options.EXTRA, options.toString());
PendingIntent deleteIntent = PendingIntent.getBroadcast( PendingIntent deleteIntent = PendingIntent.getBroadcast(
...@@ -175,8 +140,7 @@ public class Builder { ...@@ -175,8 +140,7 @@ public class Builder {
* Set intent to handle the click event. Will bring the app to * Set intent to handle the click event. Will bring the app to
* foreground. * foreground.
* *
* @param builder * @param builder Local notification builder instance
* Local notification builder instance
*/ */
private void applyContentReceiver(NotificationCompat.Builder builder) { private void applyContentReceiver(NotificationCompat.Builder builder) {
......
/*
* 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 org.json.JSONObject;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import de.appplant.cordova.plugin.notification.trigger.MatchTrigger;
import de.appplant.cordova.plugin.notification.trigger.DateTrigger;
import de.appplant.cordova.plugin.notification.trigger.IntervalTrigger;
import static de.appplant.cordova.plugin.notification.trigger.IntervalTrigger.Unit;
public class Request {
// Key name for bundled extras
static final String EXTRA = "NOTIFICATION_OCCURRENCE_EXTRA";
// The options spec
private final Options options;
// The right trigger for the options
private final DateTrigger trigger;
// How often the trigger shall occur
private final int count;
// The trigger spec
private final JSONObject spec;
// The current trigger date
private Date triggerDate;
/**
* Constructor
*
* @param options The options spec.
*/
public Request(Options options) {
this.options = options;
this.spec = options.getTrigger();
this.count = spec.optInt("count", 1);
this.trigger = buildTrigger();
this.triggerDate = trigger.getNextTriggerDate(getBaseDate());
}
/**
* Gets the options spec.
*/
public Options getOptions() {
return options;
}
/**
* The identifier for the request.
*
* @return The notification ID as the string
*/
public String getIdentifier() {
return options.getId().toString() + "-" + getOccurrence();
}
/**
* The value of the internal occurrence counter.
*/
int getOccurrence() {
return trigger.getOccurrence();
}
/**
* If there's one more trigger date to calculate.
*/
private boolean hasNext() {
return triggerDate != null && getOccurrence() < count;
}
/**
* Moves the internal occurrence counter by one.
*/
boolean moveNext() {
if (hasNext()) {
triggerDate = getNextTriggerDate();
} else {
triggerDate = null;
}
return this.triggerDate != null;
}
/**
* Gets the current trigger date.
*
* @return null if there's no trigger date.
*/
Date getTriggerDate() {
Calendar now = Calendar.getInstance();
if (triggerDate == null)
return null;
if ((now.getTimeInMillis() - triggerDate.getTime()) > 60000) {
return null;
}
return triggerDate;
}
/**
* Gets the next trigger date based on the current trigger date.
*/
private Date getNextTriggerDate() {
return trigger.getNextTriggerDate(triggerDate);
}
/**
* Build the trigger specified in options.
*/
private DateTrigger buildTrigger() {
Object every = spec.opt("every");
if (every instanceof JSONObject) {
return new MatchTrigger(getDateMatchingComponents());
}
Unit unit = getUnit();
int ticks = getTicks();
return new IntervalTrigger(ticks, unit);
}
/**
* Gets the unit value.
*/
private Unit getUnit() {
Object every = spec.opt("every");
String unit = "SECOND";
if (spec.has("unit")) {
unit = spec.optString("unit", "second");
} else
if (every instanceof String) {
unit = spec.optString("every", "second");
}
return Unit.valueOf(unit.toUpperCase());
}
/**
* Gets the tick value.
*/
private int getTicks() {
Object every = spec.opt("every");
int ticks = 0;
if (spec.has("at")) {
ticks = 0;
} else
if (spec.has("in")) {
ticks = spec.optInt("in", 0);
} else
if (every instanceof String) {
ticks = 1;
} else
if (!(every instanceof JSONObject)) {
ticks = spec.optInt("every", 0);
}
return ticks;
}
/**
* Gets an array of all date parts to construct a datetime instance.
*
* @return [min, hour, day, month, year]
*/
private List<Integer> getDateMatchingComponents() {
JSONObject every = spec.optJSONObject("every");
return Arrays.asList(
(Integer) every.opt("minute"),
(Integer) every.opt("hour"),
(Integer) every.opt("day"),
(Integer) every.opt("month"),
(Integer) every.opt("year")
);
}
/**
* Gets the base date from where to calculate the next trigger date.
*/
private Date getBaseDate() {
if (spec.has("at")) {
return new Date(spec.optLong("at", 0) * 1000);
} else {
return new Date();
}
}
}
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
* limitations under the License. * limitations under the License.
*/ */
package de.appplant.cordova.plugin.notification; package de.appplant.cordova.plugin.notification.activity;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
...@@ -29,6 +29,9 @@ import android.os.Bundle; ...@@ -29,6 +29,9 @@ import android.os.Bundle;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import de.appplant.cordova.plugin.notification.Notification;
import de.appplant.cordova.plugin.notification.Options;
/** /**
* Abstract content receiver activity for local notifications. Creates the * Abstract content receiver activity for local notifications. Creates the
* local notification and calls the event functions for further proceeding. * local notification and calls the event functions for further proceeding.
...@@ -38,8 +41,7 @@ abstract public class AbstractClickActivity extends Activity { ...@@ -38,8 +41,7 @@ abstract public class AbstractClickActivity extends Activity {
/** /**
* Called when local notification was clicked to launch the main intent. * Called when local notification was clicked to launch the main intent.
* *
* @param state * @param state Saved instance state
* Saved instance state
*/ */
@Override @Override
public void onCreate (Bundle state) { public void onCreate (Bundle state) {
...@@ -50,14 +52,12 @@ abstract public class AbstractClickActivity extends Activity { ...@@ -50,14 +52,12 @@ abstract public class AbstractClickActivity extends Activity {
Context context = getApplicationContext(); Context context = getApplicationContext();
try { try {
String data = bundle.getString(Options.EXTRA); String data = bundle.getString(Options.EXTRA);
JSONObject options = new JSONObject(data); JSONObject dict = new JSONObject(data);
Options options = new Options(context, dict);
Builder builder =
new Builder(context, options);
Notification notification = Notification notification =
buildNotification(builder); new Notification(context, options);
onClick(notification); onClick(notification);
} catch (JSONException e) { } catch (JSONException e) {
...@@ -78,20 +78,11 @@ abstract public class AbstractClickActivity extends Activity { ...@@ -78,20 +78,11 @@ abstract public class AbstractClickActivity extends Activity {
/** /**
* Called when local notification was clicked by the user. * Called when local notification was clicked by the user.
* *
* @param notification * @param notification Wrapper around the local notification
* Wrapper around the local notification
*/ */
abstract public void onClick (Notification 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. * Launch main intent from package.
*/ */
public void launchApp() { public void launchApp() {
......
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
* limitations under the License. * limitations under the License.
*/ */
package de.appplant.cordova.plugin.notification; package de.appplant.cordova.plugin.notification.activity;
import de.appplant.cordova.plugin.notification.Notification;
/** /**
* The receiver activity is triggered when a notification is clicked by a user. * The receiver activity is triggered when a notification is clicked by a user.
...@@ -32,28 +34,17 @@ public class ClickActivity extends AbstractClickActivity { ...@@ -32,28 +34,17 @@ public class ClickActivity extends AbstractClickActivity {
* Called when local notification was clicked by the user. Will * Called when local notification was clicked by the user. Will
* move the app to foreground. * move the app to foreground.
* *
* @param notification * @param notification Wrapper around the local notification
* Wrapper around the local notification
*/ */
@Override @Override
public void onClick(Notification notification) { public void onClick(Notification notification) {
launchApp(); launchApp();
if (notification.isRepeating()) { // if (notification.isRepeating()) {
notification.clear(); // notification.clear();
} else { // } else {
notification.cancel(); // notification.cancel();
} // }
}
/**
* Build notification specified by options.
*
* @param builder
* Notification builder
*/
public Notification buildNotification (Builder builder) {
return builder.build();
} }
} }
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
* limitations under the License. * limitations under the License.
*/ */
package de.appplant.cordova.plugin.notification; package de.appplant.cordova.plugin.notification.receiver;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
...@@ -29,6 +29,9 @@ import android.os.Bundle; ...@@ -29,6 +29,9 @@ import android.os.Bundle;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import de.appplant.cordova.plugin.notification.Notification;
import de.appplant.cordova.plugin.notification.Options;
/** /**
* Abstract delete receiver for local notifications. Creates the local * Abstract delete receiver for local notifications. Creates the local
* notification and calls the event functions for further proceeding. * notification and calls the event functions for further proceeding.
...@@ -38,35 +41,31 @@ abstract public class AbstractClearReceiver extends BroadcastReceiver { ...@@ -38,35 +41,31 @@ abstract public class AbstractClearReceiver extends BroadcastReceiver {
/** /**
* Called when the notification was cleared from the notification center. * Called when the notification was cleared from the notification center.
* *
* @param context * @param context Application context
* Application context * @param intent Received intent with content data
* @param intent
* Received intent with content data
*/ */
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras(); Bundle bundle = intent.getExtras();
JSONObject options; String data = bundle.getString(Options.EXTRA);
try { try {
String data = bundle.getString(Options.EXTRA); JSONObject dict = new JSONObject(data);
options = new JSONObject(data); Options options = new Options(context, dict);
Notification notification =
new Notification(context, options);
onClear(notification);
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
return;
} }
Notification notification =
new Builder(context, options).build();
onClear(notification);
} }
/** /**
* Called when a local notification was cleared from outside of the app. * Called when a local notification was cleared from outside of the app.
* *
* @param notification * @param notification Wrapper around the local notification
* Wrapper around the local notification
*/ */
abstract public void onClear (Notification notification); abstract public void onClear (Notification notification);
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
* limitations under the License. * limitations under the License.
*/ */
package de.appplant.cordova.plugin.notification; package de.appplant.cordova.plugin.notification.receiver;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
...@@ -29,7 +29,9 @@ import android.os.Bundle; ...@@ -29,7 +29,9 @@ import android.os.Bundle;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.util.Calendar; import de.appplant.cordova.plugin.notification.Builder;
import de.appplant.cordova.plugin.notification.Notification;
import de.appplant.cordova.plugin.notification.Options;
/** /**
* Abstract broadcast receiver for local notifications. Creates the * Abstract broadcast receiver for local notifications. Creates the
...@@ -40,10 +42,8 @@ abstract public class AbstractTriggerReceiver extends BroadcastReceiver { ...@@ -40,10 +42,8 @@ abstract public class AbstractTriggerReceiver extends BroadcastReceiver {
/** /**
* Called when an alarm was triggered. * Called when an alarm was triggered.
* *
* @param context * @param context Application context
* Application context * @param intent Received intent with content data
* @param intent
* Received intent with content data
*/ */
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
...@@ -54,21 +54,15 @@ abstract public class AbstractTriggerReceiver extends BroadcastReceiver { ...@@ -54,21 +54,15 @@ abstract public class AbstractTriggerReceiver extends BroadcastReceiver {
String data = bundle.getString(Options.EXTRA); String data = bundle.getString(Options.EXTRA);
JSONObject dict = new JSONObject(data); JSONObject dict = new JSONObject(data);
options = new Options(context).parse(dict); options = new Options(context, dict);
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
return; return;
} }
if (options == null) Builder builder = new Builder(options);
return;
if (isFirstAlarmInFuture(options))
return;
Builder builder = new Builder(options);
Notification notification = buildNotification(builder); Notification notification = buildNotification(builder);
boolean updated = notification.isUpdate(false); boolean updated = false;// notification.isUpdate(false);
onTrigger(notification, updated); onTrigger(notification, updated);
} }
...@@ -76,45 +70,16 @@ abstract public class AbstractTriggerReceiver extends BroadcastReceiver { ...@@ -76,45 +70,16 @@ abstract public class AbstractTriggerReceiver extends BroadcastReceiver {
/** /**
* Called when a local notification was triggered. * Called when a local notification was triggered.
* *
* @param notification * @param notification Wrapper around the local notification
* Wrapper around the local notification * @param updated If an update has triggered or the original
* @param updated
* If an update has triggered or the original
*/ */
abstract public void onTrigger (Notification notification, boolean updated); abstract public void onTrigger (Notification notification, boolean updated);
/** /**
* Build notification specified by options. * Build notification specified by options.
* *
* @param builder * @param builder Notification builder
* Notification builder
*/ */
abstract public Notification buildNotification (Builder 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);
}
} }
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
* limitations under the License. * limitations under the License.
*/ */
package de.appplant.cordova.plugin.notification; package de.appplant.cordova.plugin.notification.receiver;
import de.appplant.cordova.plugin.notification.Notification;
/** /**
* The clear intent receiver is triggered when the user clears a * The clear intent receiver is triggered when the user clears a
...@@ -31,12 +33,11 @@ public class ClearReceiver extends AbstractClearReceiver { ...@@ -31,12 +33,11 @@ public class ClearReceiver extends AbstractClearReceiver {
/** /**
* Called when a local notification was cleared from outside of the app. * Called when a local notification was cleared from outside of the app.
* *
* @param notification * @param notification Wrapper around the local notification
* Wrapper around the local notification
*/ */
@Override @Override
public void onClear (Notification notification) { public void onClear (Notification notification) {
notification.clear(); // notification.clear();
} }
} }
...@@ -19,7 +19,10 @@ ...@@ -19,7 +19,10 @@
* limitations under the License. * limitations under the License.
*/ */
package de.appplant.cordova.plugin.notification; package de.appplant.cordova.plugin.notification.receiver;
import de.appplant.cordova.plugin.notification.Builder;
import de.appplant.cordova.plugin.notification.Notification;
/** /**
* The alarm receiver is triggered when a scheduled alarm is fired. This class * The alarm receiver is triggered when a scheduled alarm is fired. This class
...@@ -33,10 +36,8 @@ public class TriggerReceiver extends AbstractTriggerReceiver { ...@@ -33,10 +36,8 @@ public class TriggerReceiver extends AbstractTriggerReceiver {
* Called when a local notification was triggered. Does present the local * Called when a local notification was triggered. Does present the local
* notification and re-schedule the alarm if necessary. * notification and re-schedule the alarm if necessary.
* *
* @param notification * @param notification Wrapper around the local notification
* Wrapper around the local notification * @param updated If an update has triggered or the original
* @param updated
* If an update has triggered or the original
*/ */
@Override @Override
public void onTrigger (Notification notification, boolean updated) { public void onTrigger (Notification notification, boolean updated) {
...@@ -46,8 +47,7 @@ public class TriggerReceiver extends AbstractTriggerReceiver { ...@@ -46,8 +47,7 @@ public class TriggerReceiver extends AbstractTriggerReceiver {
/** /**
* Build notification specified by options. * Build notification specified by options.
* *
* @param builder * @param builder Notification builder
* Notification builder
*/ */
@Override @Override
public Notification buildNotification (Builder builder) { public Notification buildNotification (Builder builder) {
......
/*
* Apache 2.0 License
*
* Copyright (c) Sebastian Katzer 2017
*
* 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.
*/
package de.appplant.cordova.plugin.notification.trigger;
import java.util.Calendar;
import java.util.Date;
abstract public class DateTrigger {
// Default unit is SECOND
public enum Unit { SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, YEAR }
// Internal counter
private int occurrence = 1;
/**
* Gets the next trigger date.
*
* @param base The date from where to calculate the trigger date.
*
* @return null if there's none next trigger date.
*/
abstract public Date getNextTriggerDate(Date base);
/**
* The value of the occurrence.
*/
public int getOccurrence() {
return occurrence;
}
/**
* Increase the occurrence by 1.
*/
void incOccurrence() {
occurrence += 1;
}
/**
* Gets a calendar instance pointing to the specified date.
*
* @param date The date to point.
*/
Calendar getCal (Date date) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
return cal;
}
}
\ No newline at end of file
/*
* Apache 2.0 License
*
* Copyright (c) Sebastian Katzer 2017
*
* 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.
*/
package de.appplant.cordova.plugin.notification.trigger;
import java.util.Calendar;
import java.util.Date;
/**
* Trigger class for interval based notification. Trigger by a fixed interval
* from now.
*/
public class IntervalTrigger extends DateTrigger {
// The number of ticks per interval
private final int ticks;
// The unit of the ticks
final Unit unit;
/**
* Interval trigger based from now.
*
* @param ticks The number of ticks per interval.
* @param unit The unit of the ticks.
*/
public IntervalTrigger(int ticks, Unit unit) {
this.ticks = ticks;
this.unit = unit;
}
/**
* Gets the next trigger date.
*
* @param base The date from where to calculate the trigger date.
*
* @return null if there's none next trigger date.
*/
@Override
public Date getNextTriggerDate(Date base) {
Calendar cal = getCal(base);
addInterval(cal);
incOccurrence();
return cal.getTime();
}
/**
* Adds the amount of ticks to the calendar.
*
* @param cal The calendar to manipulate.
*
* @return The calendar instance.
*/
Calendar addInterval(Calendar cal) {
switch (unit) {
case SECOND:
cal.add(Calendar.SECOND, ticks);
break;
case MINUTE:
cal.add(Calendar.MINUTE, ticks);
break;
case HOUR:
cal.add(Calendar.HOUR_OF_DAY, ticks);
break;
case DAY:
cal.add(Calendar.DAY_OF_YEAR, ticks);
break;
case WEEK:
cal.add(Calendar.WEEK_OF_YEAR, ticks);
break;
case MONTH:
cal.add(Calendar.MONTH, ticks);
break;
case QUARTER:
cal.add(Calendar.MONTH, ticks * 3);
break;
case YEAR:
cal.add(Calendar.YEAR, ticks);
break;
}
return cal;
}
}
\ No newline at end of file
/*
* Apache 2.0 License
*
* Copyright (c) Sebastian Katzer 2017
*
* 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.
*/
package de.appplant.cordova.plugin.notification.trigger;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import static de.appplant.cordova.plugin.notification.trigger.DateTrigger.Unit.DAY;
import static de.appplant.cordova.plugin.notification.trigger.DateTrigger.Unit.HOUR;
import static de.appplant.cordova.plugin.notification.trigger.DateTrigger.Unit.MINUTE;
import static de.appplant.cordova.plugin.notification.trigger.DateTrigger.Unit.MONTH;
import static de.appplant.cordova.plugin.notification.trigger.DateTrigger.Unit.YEAR;
/**
* Trigger for date matching components.
*/
public class MatchTrigger extends IntervalTrigger {
// Used to determine the interval
private static Unit[] INTERVALS = { null, MINUTE, HOUR, DAY, MONTH, YEAR };
// The date matching components
private final List<Integer> matchers;
/**
* Date matching trigger from now.
*
* @param matchers Describes the date matching parts.
* { day: 15, month: ... }
*/
public MatchTrigger(List<Integer> matchers) {
super(1, INTERVALS[1 + matchers.indexOf(null)]);
this.matchers = matchers;
}
/**
* Gets the date from where to start calculating the initial trigger date.
*/
private Calendar getBaseTriggerDate(Date date) {
Calendar cal = getCal(date);
cal.set(Calendar.SECOND, 0);
if (matchers.get(0) != null) {
cal.set(Calendar.MINUTE, matchers.get(0));
} else {
cal.set(Calendar.MINUTE, 0);
}
if (matchers.get(1) != null) {
cal.set(Calendar.HOUR_OF_DAY, matchers.get(1));
} else {
cal.set(Calendar.HOUR_OF_DAY, 0);
}
if (matchers.get(2) != null) {
cal.set(Calendar.DAY_OF_MONTH, matchers.get(2));
}
if (matchers.get(3) != null) {
cal.set(Calendar.MONTH, matchers.get(3));
}
if (matchers.get(4) != null) {
cal.set(Calendar.YEAR, matchers.get(4));
}
return cal;
}
/**
* Gets the first trigger date.
*
* @param base The date from where to calculate the trigger date.
*
* @return null if there's none trigger date.
*/
private Date getTriggerDate (Date base) {
Calendar date = getBaseTriggerDate(base);
Calendar now = getCal(base);
if (date.compareTo(now) >= 0)
return date.getTime();
if (unit == null || date.get(Calendar.YEAR) < now.get(Calendar.YEAR))
return null;
if (date.get(Calendar.MONTH) < now.get(Calendar.MONTH)) {
switch (unit) {
case MINUTE:
case HOUR:
case DAY:
if (matchers.get(4) == null) {
return addToDate(date, now, Calendar.YEAR, 1);
} else break;
case YEAR:
return addToDate(date, now, Calendar.YEAR, 1);
}
} else
if (date.get(Calendar.DAY_OF_YEAR) < now.get(Calendar.DAY_OF_YEAR)) {
switch (unit) {
case MINUTE:
case HOUR:
if (matchers.get(3) == null) {
return addToDate(date, now, Calendar.MONTH, 1);
} else
if (matchers.get(4) == null) {
return addToDate(date, now, Calendar.YEAR, 1);
}
else break;
case MONTH:
return addToDate(date, now, Calendar.MONTH, 1);
case YEAR:
return addToDate(date, now, Calendar.YEAR, 1);
}
} else
if (date.get(Calendar.HOUR_OF_DAY) < now.get(Calendar.HOUR_OF_DAY)) {
switch (unit) {
case MINUTE:
if (matchers.get(2) == null) {
return addToDate(date, now, Calendar.DAY_OF_YEAR, 1);
} else
if (matchers.get(3) == null) {
return addToDate(date, now, Calendar.MONTH, 1);
}
else break;
case HOUR:
return addToDate(date, now, Calendar.HOUR_OF_DAY, 0);
case DAY:
return addToDate(date, now, Calendar.DAY_OF_YEAR, 1);
case MONTH:
return addToDate(date, now, Calendar.MONTH, 1);
case YEAR:
return addToDate(date, now, Calendar.YEAR, 1);
}
} else
if (date.get(Calendar.MINUTE) < now.get(Calendar.MINUTE)) {
switch (unit) {
case MINUTE:
return addToDate(date, now, Calendar.MINUTE, 1);
case HOUR:
return addToDate(date, now, Calendar.HOUR_OF_DAY, 1);
case DAY:
return addToDate(date, now, Calendar.DAY_OF_YEAR, 1);
case MONTH:
return addToDate(date, now, Calendar.MONTH, 1);
case YEAR:
return addToDate(date, now, Calendar.YEAR, 1);
}
}
return null;
}
/**
* Gets the next trigger date.
*
* @param base The date from where to calculate the trigger date.
*
* @return null if there's none next trigger date.
*/
@Override
public Date getNextTriggerDate (Date base) {
Date date = base;
if (getOccurrence() > 1) {
Calendar cal = getCal(base);
addInterval(cal);
date = cal.getTime();
}
incOccurrence();
return getTriggerDate(date);
}
/**
* Sets the field value of now to date and adds by count.
*
* @return The new date.
*/
private Date addToDate(Calendar date, Calendar now, int field, int count) {
date.set(field, now.get(field));
date.add(field, count);
return date.getTime();
}
}
\ No newline at end of file
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
* limitations under the License. * limitations under the License.
*/ */
package de.appplant.cordova.plugin.notification; package de.appplant.cordova.plugin.notification.util;
import android.content.Context; import android.content.Context;
import android.content.res.AssetManager; import android.content.res.AssetManager;
...@@ -42,20 +42,19 @@ import java.net.MalformedURLException; ...@@ -42,20 +42,19 @@ import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.UUID; import java.util.UUID;
import static android.media.RingtoneManager.TYPE_NOTIFICATION;
/** /**
* Util class to map unified asset URIs to native URIs. URIs like file:/// * Util class to map unified asset URIs to native URIs. URIs like file:///
* map to absolute paths while file:// point relatively to the www folder * map to absolute paths while file:// point relatively to the www folder
* within the asset resources. And res:// means a resource from the native * within the asset resources. And res:// means a resource from the native
* res folder. Remote assets are accessible via http:// for example. * res folder. Remote assets are accessible via http:// for example.
*/ */
class AssetUtil { public class AssetUtil {
// Name of the storage folder // Name of the storage folder
private static final String STORAGE_FOLDER = "/localnotification"; private static final String STORAGE_FOLDER = "/localnotification";
// Placeholder URI for default sound
private static final String DEFAULT_SOUND = "res://platform_default";
// Ref to the context passed through the constructor to access the // Ref to the context passed through the constructor to access the
// resources and app directory. // resources and app directory.
private final Context context; private final Context context;
...@@ -63,8 +62,7 @@ class AssetUtil { ...@@ -63,8 +62,7 @@ class AssetUtil {
/** /**
* Constructor * Constructor
* *
* @param context * @param context Application context
* Application context
*/ */
private AssetUtil(Context context) { private AssetUtil(Context context) {
this.context = context; this.context = context;
...@@ -73,41 +71,22 @@ class AssetUtil { ...@@ -73,41 +71,22 @@ class AssetUtil {
/** /**
* Static method to retrieve class instance. * Static method to retrieve class instance.
* *
* @param context * @param context Application context
* Application context
*/ */
static AssetUtil getInstance(Context context) { public static AssetUtil getInstance(Context context) {
return new AssetUtil(context); return new AssetUtil(context);
} }
/** /**
* Parse path path to native URI.
*
* @param path
* Path to path file
*/
Uri parseSound (String path) {
if (path == null || path.isEmpty())
return Uri.EMPTY;
if (path.equalsIgnoreCase(DEFAULT_SOUND)) {
return RingtoneManager.getDefaultUri(RingtoneManager
.TYPE_NOTIFICATION);
}
return parse(path);
}
/**
* The URI for a path. * The URI for a path.
* *
* @param path * @param path
* The given path * The given path
*/ */
Uri parse (String path) { public Uri parse (String path) {
if (path == null || path.isEmpty()) {
if (path.startsWith("res:")) { return Uri.EMPTY;
} else if (path.startsWith("res:")) {
return getUriForResourcePath(path); return getUriForResourcePath(path);
} else if (path.startsWith("file:///")) { } else if (path.startsWith("file:///")) {
return getUriFromPath(path); return getUriFromPath(path);
...@@ -191,7 +170,7 @@ class AssetUtil { ...@@ -191,7 +170,7 @@ class AssetUtil {
*/ */
private Uri getUriForResourcePath(String path) { private Uri getUriForResourcePath(String path) {
String resPath = path.replaceFirst("res://", ""); String resPath = path.replaceFirst("res://", "");
int resId = getResIdForDrawable(resPath); int resId = getResId(resPath);
File file = getTmpFile(); File file = getTmpFile();
if (resId == 0) { if (resId == 0) {
...@@ -296,14 +275,15 @@ class AssetUtil { ...@@ -296,14 +275,15 @@ class AssetUtil {
/** /**
* Resource ID for drawable. * Resource ID for drawable.
* *
* @param resPath * @param resPath Resource path as string.
* Resource path as string *
* @return The resource ID or 0 if not found.
*/ */
int getResIdForDrawable(String resPath) { public int getResId(String resPath) {
int resId = getResIdForDrawable(getPkgName(), resPath); int resId = getResId(context.getResources(), resPath);
if (resId == 0) { if (resId == 0) {
resId = getResIdForDrawable("android", resPath); resId = getResId(Resources.getSystem(), resPath);
} }
return resId; return resId;
...@@ -312,56 +292,32 @@ class AssetUtil { ...@@ -312,56 +292,32 @@ class AssetUtil {
/** /**
* Resource ID for drawable. * Resource ID for drawable.
* *
* @param clsName * @param res The resources where to look for.
* Relative package or global android name space * @param resPath The name of the resource.
* @param resPath
* Resource path as string
*/
int getResIdForDrawable(String clsName, String resPath) {
String drawable = getBaseName(resPath);
int resId = 0;
try {
Class<?> cls = Class.forName(clsName + ".R$drawable");
resId = (Integer) cls.getDeclaredField(drawable).get(Integer.class);
} catch (Exception ignore) {}
return resId;
}
/**
* Convert drawable resource to bitmap.
* *
* @param drawable * @return The resource ID or 0 if not found.
* Drawable resource name
*/ */
Bitmap getIconFromDrawable (String drawable) { private int getResId(Resources res, String resPath) {
Resources res = context.getResources(); String pkgName = getPkgName(res);
int iconId; String resName = getBaseName(resPath);
int resId;
iconId = getResIdForDrawable(getPkgName(), drawable);
if (iconId == 0) { resId = res.getIdentifier(resName, "mipmap", pkgName);
iconId = getResIdForDrawable("android", drawable);
}
if (iconId == 0) { if (resId == 0) {
iconId = android.R.drawable.screen_background_dark_transparent; resId = res.getIdentifier(resName, "drawable", pkgName);
} }
return BitmapFactory.decodeResource(res, iconId); return resId;
} }
/** /**
* Convert URI to Bitmap. * Convert URI to Bitmap.
* *
* @param uri * @param uri Internal image URI
* Internal image URI
*/ */
Bitmap getIconFromUri (Uri uri) throws IOException { public Bitmap getIconFromUri(Uri uri) throws IOException {
InputStream input = context.getContentResolver().openInputStream(uri); InputStream input = context.getContentResolver().openInputStream(uri);
return BitmapFactory.decodeStream(input); return BitmapFactory.decodeStream(input);
} }
...@@ -422,10 +378,10 @@ class AssetUtil { ...@@ -422,10 +378,10 @@ class AssetUtil {
} }
/** /**
* Package name specified by context. * Package name specified by the resource bundle.
*/ */
private String getPkgName () { private String getPkgName (Resources res) {
return context.getPackageName(); return res == Resources.getSystem() ? "android" : context.getPackageName();
} }
} }
...@@ -158,12 +158,13 @@ ...@@ -158,12 +158,13 @@
NSString* path = [dict objectForKey:@"sound"]; NSString* path = [dict objectForKey:@"sound"];
NSString* file; NSString* file;
if ([path isKindOfClass:NSNumber.class]) {
return [path boolValue] ? [UNNotificationSound defaultSound] : NULL;
}
if (!path.length) if (!path.length)
return NULL; return NULL;
if ([path isEqualToString:@"res://platform_default"])
return [UNNotificationSound defaultSound];
if ([path hasPrefix:@"file:/"]) { if ([path hasPrefix:@"file:/"]) {
file = [self soundNameForAsset:path]; file = [self soundNameForAsset:path];
} else } else
......
...@@ -51,12 +51,17 @@ exports.applyPlatformSpecificOptions = function () { ...@@ -51,12 +51,17 @@ exports.applyPlatformSpecificOptions = function () {
switch (device.platform) { switch (device.platform) {
case 'Android': case 'Android':
defaults.icon = 'res://ic_popup_reminder'; defaults.icon = 'res://icon';
defaults.smallIcon = undefined; defaults.smallIcon = undefined;
defaults.ongoing = false; defaults.sticky = false;
defaults.autoClear = true; defaults.autoClear = true;
defaults.led = undefined; defaults.led = true;
defaults.color = undefined; defaults.color = undefined;
defaults.vibrate = false;
defaults.lockscreen = true;
defaults.showWhen = true;
defaults.priority = 0;
defaults.defaults = 0;
break; break;
} }
}; };
...@@ -111,14 +116,17 @@ exports.mergeWithDefaults = function (options) { ...@@ -111,14 +116,17 @@ exports.mergeWithDefaults = function (options) {
* @return [ Object ] The converted property list * @return [ Object ] The converted property list
*/ */
exports.convertProperties = function (options) { exports.convertProperties = function (options) {
var parseToInt = function (prop, options) {
if (options.id) { if (isNaN(options[prop])) {
if (isNaN(options.id)) { console.warn(prop + ' is not a number: ' + options[prop]);
options.id = this.getDefaults().id; return this.getDefaults()[prop];
console.warn('Id is not a number: ' + options.id);
} else { } else {
options.id = Number(options.id); return Number(options[prop]);
} }
};
if (options.id) {
options.id = parseToInt('id', options);
} }
if (options.title) { if (options.title) {
...@@ -130,12 +138,15 @@ exports.convertProperties = function (options) { ...@@ -130,12 +138,15 @@ exports.convertProperties = function (options) {
} }
if (options.badge) { if (options.badge) {
if (isNaN(options.badge)) { options.badge = parseToInt('badge', options);
options.badge = this.getDefaults().badge; }
console.warn('Badge number is not a number: ' + options.id);
} else { if (options.priority) {
options.badge = Number(options.badge); options.priority = parseToInt('priority', options);
} }
if (options.defaults) {
options.defaults = parseToInt('defaults', options);
} }
if (typeof options.data == 'object') { if (typeof options.data == 'object') {
......
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