Commit 504b36cb by Sebastián Katzer

Minimize android-support-v4.jar to only include required classes

parent cf7ca7d7
...@@ -21,352 +21,171 @@ ...@@ -21,352 +21,171 @@
package de.appplant.cordova.plugin.localnotification; package de.appplant.cordova.plugin.localnotification;
import java.util.ArrayList; import java.util.Calendar;
import java.util.Map; import java.util.Random;
import java.util.Set;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import android.app.AlarmManager; import android.annotation.SuppressLint;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.*;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.graphics.Bitmap;
import android.content.SharedPreferences.Editor; import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
/** /**
* This plugin utilizes the Android AlarmManager in combination with StatusBar * The alarm receiver is triggered when a scheduled alarm is fired. This class
* notifications. When a local notification is scheduled the alarm manager takes * reads the information in the intent and displays this information in the
* care of firing the event. When the event is processed, a notification is put * Android notification bar. The notification uses the default notification
* in the Android status bar. * sound and it vibrates the phone.
*/ */
public class LocalNotification extends CordovaPlugin { public class Receiver extends BroadcastReceiver {
protected final static String PLUGIN_NAME = "LocalNotification";
private static CordovaWebView webView = null; public static final String OPTIONS = "LOCAL_NOTIFICATION_OPTIONS";
private static Boolean deviceready = false;
protected static Context context = null;
protected static Boolean isInBackground = true;
private static ArrayList<String> eventQueue = new ArrayList<String>();
@Override private Context context;
public void initialize (CordovaInterface cordova, CordovaWebView webView) { private Options options;
super.initialize(cordova, webView);
LocalNotification.webView = super.webView;
LocalNotification.context = super.cordova.getActivity().getApplicationContext();
}
@Override @Override
public boolean execute (String action, final JSONArray args, CallbackContext callbackContext) throws JSONException { public void onReceive (Context context, Intent intent) {
if (action.equalsIgnoreCase("add")) { Options options = null;
cordova.getThreadPool().execute( new Runnable() { Bundle bundle = intent.getExtras();
public void run() { JSONObject args;
JSONObject arguments = args.optJSONObject(0);
Options options = new Options(context).parse(arguments);
persist(options.getId(), args);
add(options, true);
}
});
return true;
}
if (action.equalsIgnoreCase("cancel")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
String id = args.optString(0);
cancel(id);
unpersist(id);
}
});
return true;
}
if (action.equalsIgnoreCase("cancelAll")) { try {
cordova.getThreadPool().execute( new Runnable() { args = new JSONObject(bundle.getString(OPTIONS));
public void run() { options = new Options(context).parse(args);
cancelAll(); } catch (JSONException e) {
unpersistAll(); return;
}
});
return true;
}
if (action.equalsIgnoreCase("isScheduled")) {
String id = args.optString(0);
isScheduled(id, callbackContext);
return true;
}
if (action.equalsIgnoreCase("getScheduledIds")) {
getScheduledIds(callbackContext);
return true;
} }
if (action.equalsIgnoreCase("deviceready")) { this.context = context;
cordova.getThreadPool().execute( new Runnable() { this.options = options;
public void run() {
deviceready();
}
});
return true; // The context may got lost if the app was not running before
} LocalNotification.setContext(context);
if (action.equalsIgnoreCase("pause")) { fireTriggerEvent();
isInBackground = true;
return true; if (options.getInterval() == 0) {
LocalNotification.unpersist(options.getId());
} else if (isFirstAlarmInFuture()) {
return;
} else {
LocalNotification.add(options.moveDate(), false);
} }
if (action.equalsIgnoreCase("resume")) { Builder notification = buildNotification();
isInBackground = false;
return true;
}
// Returning false results in a "MethodNotFound" error. showNotification(notification);
return false;
} }
/** /*
* Calls all pending callbacks after the deviceready event has been fired. * 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 static void deviceready () { private Boolean isFirstAlarmInFuture () {
deviceready = true; if (options.getInterval() > 0) {
Calendar now = Calendar.getInstance();
for (String js : eventQueue) { Calendar alarm = options.getCalendar();
webView.sendJavascript(js);
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;
}
} }
eventQueue.clear(); return false;
} }
/** /**
* Set an alarm. * Creates the notification.
*
* @param options
* The options that can be specified per alarm.
* @param doFireEvent
* If the onadd callback shall be called.
*/ */
public static void add (Options options, boolean doFireEvent) { @SuppressLint("NewApi")
long triggerTime = options.getDate(); private Builder buildNotification () {
Bitmap icon = BitmapFactory.decodeResource(context.getResources(), options.getIcon());
Intent intent = new Intent(context, Receiver.class) Uri sound = options.getSound();
.setAction("" + options.getId())
.putExtra(Receiver.OPTIONS, options.getJSONObject().toString()); Builder notification = new NotificationCompat.Builder(context)
.setContentTitle(options.getTitle())
AlarmManager am = getAlarmManager(); .setContentText(options.getMessage())
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); .setNumber(options.getBadge())
.setTicker(options.getMessage())
if (doFireEvent) { .setSmallIcon(options.getSmallIcon())
fireEvent("add", options.getId(), options.getJSON()); .setLargeIcon(icon)
.setAutoCancel(options.getAutoCancel())
.setOngoing(options.getOngoing());
if (sound != null) {
notification.setSound(sound);
} }
am.set(AlarmManager.RTC_WAKEUP, triggerTime, pi); if (Build.VERSION.SDK_INT > 16) {
} notification.setStyle(new NotificationCompat.BigTextStyle()
.bigText(options.getMessage()));
/**
* Cancel a specific notification that was previously registered.
*
* @param notificationId
* The original ID of the notification that was used when it was
* registered using add()
*/
public static void cancel (String notificationId) {
/*
* Create an intent that looks similar, to the one that was registered
* using add. Making sure the notification id in the action is the same.
* Now we can search for such an intent using the 'getService' method
* and cancel it.
*/
Intent intent = new Intent(context, Receiver.class)
.setAction("" + notificationId);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager am = getAlarmManager();
NotificationManager nc = getNotificationManager();
am.cancel(pi);
try {
nc.cancel(Integer.parseInt(notificationId));
} catch (Exception e) {}
fireEvent("cancel", notificationId, "");
}
/**
* Cancel all notifications that were created by this plugin.
*
* Android can only unregister a specific alarm. There is no such thing
* as cancelAll. Therefore we rely on the Shared Preferences which holds
* all our alarms to loop through these alarms and unregister them one
* by one.
*/
public static void cancelAll() {
SharedPreferences settings = getSharedPreferences();
NotificationManager nc = getNotificationManager();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
for (String alarmId : alarmIds) {
cancel(alarmId);
} }
nc.cancelAll(); setClickEvent(notification);
}
/**
* Checks wether a notification with an ID is scheduled.
*
* @param id
* The notification ID to be check.
* @param callbackContext
*/
public static void isScheduled (String id, CallbackContext callbackContext) {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
boolean isScheduled = alarms.containsKey(id);
PluginResult result = new PluginResult(PluginResult.Status.OK, isScheduled);
callbackContext.sendPluginResult(result);
}
/**
* Retrieves a list with all currently pending notifications.
*
* @param callbackContext
*/
public static void getScheduledIds (CallbackContext callbackContext) {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray pendingIds = new JSONArray(alarmIds);
callbackContext.success(pendingIds); return notification;
} }
/** /**
* Persist the information of this alarm to the Android Shared Preferences. * Adds an onclick handler to the notification
* This will allow the application to restore the alarm upon device reboot.
* Also this is used by the cancelAll method.
*
* @param alarmId
* The Id of the notification that must be persisted.
* @param args
* The assumption is that parse has been called already.
*/ */
public static void persist (String alarmId, JSONArray args) { private Builder setClickEvent (Builder notification) {
Editor editor = getSharedPreferences().edit(); Intent intent = new Intent(context, ReceiverActivity.class)
.putExtra(OPTIONS, options.getJSONObject().toString())
.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
if (alarmId != null) { int requestCode = new Random().nextInt();
editor.putString(alarmId, args.toString());
editor.apply();
}
}
/** PendingIntent contentIntent = PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
* Remove a specific alarm from the Android shared Preferences.
*
* @param alarmId
* The Id of the notification that must be removed.
*/
public static void unpersist (String alarmId) {
Editor editor = getSharedPreferences().edit();
if (alarmId != null) { return notification.setContentIntent(contentIntent);
editor.remove(alarmId);
editor.apply();
}
} }
/** /**
* Clear all alarms from the Android shared Preferences. * Shows the notification
*/ */
public static void unpersistAll () { @SuppressWarnings("deprecation")
Editor editor = getSharedPreferences().edit(); @SuppressLint("NewApi")
private void showNotification (Builder notification) {
editor.clear(); NotificationManager mgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
editor.apply(); int id = 0;
}
/** try {
* Fires the given event. id = Integer.parseInt(options.getId());
* } catch (Exception e) {}
* @param {String} event The Name of the event
* @param {String} id The ID of the notification
* @param {String} json A custom (JSON) string
*/
public static void fireEvent (String event, String id, String json) {
String state = getApplicationState();
String params = "\"" + id + "\",\"" + state + "\",\\'" + JSONObject.quote(json) + "\\'.replace(/(^\"|\"$)/g, \\'\\')";
String js = "setTimeout('plugin.notification.local.on" + event + "(" + params + ")',0)";
// webview may available, but callbacks needs to be executed
// after deviceready
if (deviceready == false) {
eventQueue.add(js);
} else {
webView.sendJavascript(js);
}
}
/**
* Retrieves the application state
*
* @return {String}
* Either "background" or "foreground"
*/
protected static String getApplicationState () {
return isInBackground ? "background" : "foreground";
}
/** if (Build.VERSION.SDK_INT<16) {
* Set the application context if not already set. // build notification for HoneyComb to ICS
*/ mgr.notify(id, notification.getNotification());
protected static void setContext (Context context) { } else if (Build.VERSION.SDK_INT>15) {
if (LocalNotification.context == null) { // Notification for Jellybean and above
LocalNotification.context = context; mgr.notify(id, notification.build());
} }
} }
/** /**
* The Local storage for the application. * Fires ontrigger event.
*/
protected static SharedPreferences getSharedPreferences () {
return context.getSharedPreferences(PLUGIN_NAME, Context.MODE_PRIVATE);
}
/**
* The alarm manager for the application.
*/
protected static AlarmManager getAlarmManager () {
return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
/**
* The notification manager for the application.
*/ */
protected static NotificationManager getNotificationManager () { private void fireTriggerEvent () {
return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); LocalNotification.fireEvent("trigger", options.getId(), options.getJSON());
} }
} }
\ No newline at end of file
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