Commit 0c3f71e1 authored by Sebastián Katzer's avatar Sebastián Katzer
Browse files

Initial start for Android support

parent fe9661a6
Loading
Loading
Loading
Loading
+23 −6
Changes for plugin.xml: 23 added lines, 6 removed lines.
Original line number Diff line number Diff line
@@ -2,12 +2,12 @@

<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
        id="de.appplant.cordova.plugin.local-notifications"
        version="0.2.0">
        version="0.4.0.dev">

    <name>LocalNotifications</name>

    <description>A bunch of local-notification plugins for Cordova 3.x.x</description>
    <keywords>notification, localnotification, ios</keywords>
    <keywords>notification, local notification, alarm, ios, android</keywords>
    <license>GPL v2 License</license>

    <author>Sebastián Katzer (github.com/katzer)</author>
@@ -16,6 +16,10 @@
        <engine name="cordova" version=">=3.0.0" />
    </engines>

    <js-module src="www/local-notification.js" name="LocalNotification">
        <clobbers target="plugin.notification.local" />
    </js-module>

    <!-- ios -->
    <platform name="ios">

@@ -25,13 +29,26 @@
    		</feature>
        </config-file>

        <js-module src="www/local-notification.js" name="LocalNotification">
            <clobbers target="plugin.notification.local" />
        </js-module>

	<header-file src="src/ios/APPLocalNotification.h" />
	<source-file src="src/ios/APPLocalNotification.m" />

    </platform>

    <!-- android -->
    <platform name="android">

        <config-file target="res/xml/config.xml" parent="/*">
            <feature name="LocalNotification">
                <param name="android-package" value="de.appplant.cordova.plugin.LocalNotification"/>
            </feature>
        </config-file>

        <source-file src="src/android/AlarmReceiver.java" target-dir="src/de/appplant/cordova/plugin" />
        <source-file src="src/android/AlarmHelper.java" target-dir="src/de/appplant/cordova/plugin" />
        <source-file src="src/android/AlarmOptions.java" target-dir="src/de/appplant/cordova/plugin" />
        <source-file src="src/android/AlarmRestoreOnBoot.java" target-dir="src/de/appplant/cordova/plugin" />
        <source-file src="src/android/LocalNotification.java" target-dir="src/de/appplant/cordova/plugin" />

    </platform>

</plugin>
+87 −0
Changes for src/android/AlaramReceiver.java: 87 added lines, 0 removed lines.
Original line number Diff line number Diff line
package de.appplant.cordova.plugin;

import java.util.Calendar;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;

/**
 * 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.
 *
 * @author dvtoever
 */
public class AlarmReceiver extends BroadcastReceiver {

	public static final String TITLE = "ALARM_TITLE";
	public static final String SUBTITLE = "ALARM_SUBTITLE";
	public static final String TICKER_TEXT = "ALARM_TICKER";
	public static final String NOTIFICATION_ID = "NOTIFICATION_ID";

	/* Contains time in 24hour format 'HH:mm' e.g. '04:30' or '18:23' */
	public static final String HOUR_OF_DAY = "HOUR_OF_DAY";
	public static final String MINUTE = "MINUTES";

	@Override
	public void onReceive(Context context, Intent intent) {
		Log.d("AlarmReceiver", "AlarmReceiver invoked!");

		final Bundle bundle = intent.getExtras();
		final Object systemService = context.getSystemService(Context.NOTIFICATION_SERVICE);

		// Retrieve notification details from the intent
		final String tickerText = bundle.getString(TICKER_TEXT);
		final String notificationTitle = bundle.getString(TITLE);
		final String notificationSubText = bundle.getString(SUBTITLE);
		int notificationId = 0;

		try {
			notificationId = Integer.parseInt(bundle.getString(NOTIFICATION_ID));
		} catch (Exception e) {
			Log.d("AlarmReceiver", "Unable to process alarm with id: " + bundle.getString(NOTIFICATION_ID));
		}

		Calendar currentCal = Calendar.getInstance();
		int alarmHour = bundle.getInt(HOUR_OF_DAY);
		int alarmMin = bundle.getInt(MINUTE);
		int currentHour = currentCal.get(Calendar.HOUR_OF_DAY);
		int currentMin = currentCal.get(Calendar.MINUTE);

		if (currentHour != alarmHour && currentMin != alarmMin) {
			/*
			 * 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'.
			 */
			Log.d(LocalNotification.PLUGIN_NAME, "AlarmReceiver, ignoring alarm since it is due");
			return;
		}

		// Construct the notification and notificationManager objects
		final NotificationManager notificationMgr = (NotificationManager) systemService;
		final Notification notification = new Notification(R.drawable.ic_launcher, tickerText,
				System.currentTimeMillis());
		final PendingIntent contentIntent = PendingIntent.getActivity(context, 0, new Intent(), 0);
		notification.defaults |= Notification.DEFAULT_SOUND;
		notification.vibrate = new long[] { 0, 100, 200, 300 };
		notification.setLatestEventInfo(context, notificationTitle, notificationSubText, contentIntent);

		/*
		 * If you want all reminders to stay in the notification bar, you should
		 * generate a random ID. If you want do replace an existing
		 * notification, make sure the ID below matches the ID that you store in
		 * the alarm intent.
		 */
		notificationMgr.notify(notificationId, notification);
	}
}
 No newline at end of file
+109 −0
Changes for src/android/AlarmHelper.java: 109 added lines, 0 removed lines.
Original line number Diff line number Diff line
package de.appplant.cordova.plugin;

import java.util.Calendar;
import java.util.Map;
import java.util.Set;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;

/**
 * Helper class for the LocalNotification plugin. This class is reused by the
 * AlarmRestoreOnBoot.
 *
 * @see LocalNotification
 * @see AlarmRestoreOnBoot
 *
 * @author dvtoever
 */
public class AlarmHelper {

    private Context ctx;

    public AlarmHelper(Context context) {
	this.ctx = context;
    }

    /**
     * @see LocalNotification#add(boolean, String, String, String, int,
     *      Calendar)
     */
    public boolean addAlarm(boolean repeatDaily, String alarmTitle, String alarmSubTitle, String alarmTicker,
	    String notificationId, Calendar cal) {

	final long triggerTime = cal.getTimeInMillis();
	final Intent intent = new Intent(this.ctx, AlarmReceiver.class);
	final int hour = cal.get(Calendar.HOUR_OF_DAY);
	final int min = cal.get(Calendar.MINUTE);

	intent.setAction("" + notificationId);
	intent.putExtra(AlarmReceiver.TITLE, alarmTitle);
	intent.putExtra(AlarmReceiver.SUBTITLE, alarmSubTitle);
	intent.putExtra(AlarmReceiver.TICKER_TEXT, alarmTicker);
	intent.putExtra(AlarmReceiver.NOTIFICATION_ID, notificationId);
	intent.putExtra(AlarmReceiver.HOUR_OF_DAY, hour);
	intent.putExtra(AlarmReceiver.MINUTE, min);

	final PendingIntent sender = PendingIntent.getBroadcast(this.ctx, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
	/* Get the AlarmManager service */
	final AlarmManager am = getAlarmManager();

	if (repeatDaily) {
	    am.setRepeating(AlarmManager.RTC_WAKEUP, triggerTime, AlarmManager.INTERVAL_DAY, sender);
	} else {
	    am.set(AlarmManager.RTC_WAKEUP, triggerTime, sender);
	}

	return true;
    }

    /**
     * @see LocalNotification#cancelNotification(int)
     */
    public boolean cancelAlarm(String notificationId) {
	/*
	 * Create an intent that looks similar, to the one that was registered
	 * using add. Making sure the notification id in the action is the same.
	 * Now we can search for such an intent using the 'getService' method
	 * and cancel it.
	 */
	final Intent intent = new Intent(this.ctx, AlarmReceiver.class);
	intent.setAction("" + notificationId);

	final PendingIntent pi = PendingIntent.getBroadcast(this.ctx, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
	final AlarmManager am = getAlarmManager();

	try {
	    am.cancel(pi);
	} catch (Exception e) {
	    return false;
	}
	return true;
    }

    /**
     * @see LocalNotification#cancelAllNotifications()
     */
    public boolean cancelAll(SharedPreferences alarmSettings) {
	final Map<String, ?> allAlarms = alarmSettings.getAll();
	final Set<String> alarmIds = allAlarms.keySet();

	for (String alarmId : alarmIds) {
	    Log.d(LocalNotification.PLUGIN_NAME, "Canceling notification with id: " + alarmId);
	    String alarmInt = alarmId;
	    cancelAlarm(alarmInt);
	}

	return true;
    }

    private AlarmManager getAlarmManager() {
	final AlarmManager am = (AlarmManager) this.ctx.getSystemService(Context.ALARM_SERVICE);

	return am;
    }
}
 No newline at end of file
+111 −0
Changes for src/android/AlarmOptions.java: 111 added lines, 0 removed lines.
Original line number Diff line number Diff line
package de.appplant.cordova.plugin;

import java.util.Calendar;

import org.json.JSONArray;
import org.json.JSONObject;

/**
 * Class that helps to store the options that can be specified per alarm.
 *
 * @author dvtoever
 */
public class AlarmOptions {

    /*
     * Options that can be set when this plugin is invoked
     */
    private Calendar cal = Calendar.getInstance();
    private String alarmTitle = "";
    private String alarmSubTitle = "";
    private String alarmTicker = "";
    private boolean repeatDaily = false;
    private String notificationId = "";

    /**
     * Parse options passed from javascript part of this plugin.
     *
     * @param optionsArr
     *            JSON Array containing the list options.
     */
    public void parseOptions(JSONArray optionsArr) {
	final JSONObject options = optionsArr.optJSONObject(0);

	if (options != null) {

	    // Parse string representing the date
	    String textDate = options.optString("date");
	    if (!"".equals(textDate)) {
		String[] datePart = textDate.split("/");
		int month = Integer.parseInt(datePart[0]);
		int day = Integer.parseInt(datePart[1]);
		int year = Integer.parseInt(datePart[2]);
		int hour = Integer.parseInt(datePart[3]);
		int min = Integer.parseInt(datePart[4]);

		cal.set(year, month, day, hour, min);
	    }

	    String optString = options.optString("message");
	    if (!"".equals(optString)) {
		String lines[] = optString.split("\\r?\\n");
		alarmTitle = lines[0];
		if (lines.length > 1)
		    alarmSubTitle = lines[1];
	    }

	    alarmTicker = options.optString("ticker");
	    repeatDaily = options.optBoolean("repeatDaily");
	    notificationId = options.optString("id");
	}
    }

    public Calendar getCal() {
	return cal;
    }

    public void setCal(Calendar cal) {
	this.cal = cal;
    }

    public String getAlarmTitle() {
	return alarmTitle;
    }

    public void setAlarmTitle(String alarmTitle) {
	this.alarmTitle = alarmTitle;
    }

    public String getAlarmSubTitle() {
	return alarmSubTitle;
    }

    public void setAlarmSubTitle(String alarmSubTitle) {
	this.alarmSubTitle = alarmSubTitle;
    }

    public String getAlarmTicker() {
	return alarmTicker;
    }

    public void setAlarmTicker(String alarmTicker) {
	this.alarmTicker = alarmTicker;
    }

    public boolean isRepeatDaily() {
	return repeatDaily;
    }

    public void setRepeatDaily(boolean repeatDaily) {
	this.repeatDaily = repeatDaily;
    }

    public String getNotificationId() {
	return notificationId;
    }

    public void setNotificationId(String notificationId) {
	this.notificationId = notificationId;
    }

}
 No newline at end of file
+63 −0
Changes for src/android/AlarmRestoreOnBoot.java: 63 added lines, 0 removed lines.
Original line number Diff line number Diff line
package de.appplant.cordova.plugin;

import java.util.Calendar;
import java.util.Map;
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 android.util.Log;

/**
 * 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.
 *
 * @author dvtoever
 */
public class AlarmRestoreOnBoot extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
	final String pluginName = LocalNotification.PLUGIN_NAME;

	// Obtain alarm details form Shared Preferences
	final SharedPreferences alarmSettings = context.getSharedPreferences(pluginName, Context.MODE_PRIVATE);
	final Map<String, ?> allAlarms = alarmSettings.getAll();
	final Set<String> alarmIds = allAlarms.keySet();

	/*
	 * For each alarm, parse its alarm options and register is again with
	 * the Alarm Manager
	 */
	for (String alarmId : alarmIds) {
	    try {
		final AlarmHelper alarm = new AlarmHelper(context);
		final JSONArray alarmDetails = new JSONArray(alarmSettings.getString(alarmId, ""));
		final AlarmOptions options = new AlarmOptions();

		options.parseOptions(alarmDetails);

		final boolean daily = options.isRepeatDaily();
		final String title = options.getAlarmTitle();
		final String subTitle = options.getAlarmSubTitle();
		final String ticker = options.getAlarmTicker();
		final String id = options.getNotificationId();
		final Calendar cal = options.getCal();

		alarm.addAlarm(daily, title, subTitle, ticker, id, cal);

	    } catch (JSONException e) {
		Log.d(pluginName,
			"AlarmRestoreOnBoot: Error while restoring alarm details after reboot: " + e.toString());
	    }

	    Log.d(pluginName, "AlarmRestoreOnBoot: Successfully restored alarms upon reboot");
	}
    }
}
 No newline at end of file
Loading