summaryrefslogtreecommitdiff
path: root/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap
diff options
context:
space:
mode:
authorArjun Roychowdhury <pliablepixels@gmail.com>2015-10-18 20:27:36 -0400
committerArjun Roychowdhury <pliablepixels@gmail.com>2015-10-18 20:27:36 -0400
commitced14a385a8606319e5d7d604f65c7a33c8e1476 (patch)
treea146b48048b31fd36c6a0336052ee5d2c34093b4 /plugins/phonegap-plugin-push/src/android/com/adobe/phonegap
parent50f2e00b5be8c0e13e5790c11cc2dc234577d447 (diff)
switched to new push plugin that works with JSON payloads
Diffstat (limited to 'plugins/phonegap-plugin-push/src/android/com/adobe/phonegap')
-rw-r--r--plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/CordovaGCMBroadcastReceiver.java19
-rw-r--r--plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/GCMIntentService.java530
-rw-r--r--plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/PushConstants.java44
-rw-r--r--plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/PushHandlerActivity.java70
-rw-r--r--plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/PushPlugin.java250
5 files changed, 913 insertions, 0 deletions
diff --git a/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/CordovaGCMBroadcastReceiver.java b/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/CordovaGCMBroadcastReceiver.java
new file mode 100644
index 00000000..8bae76d9
--- /dev/null
+++ b/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/CordovaGCMBroadcastReceiver.java
@@ -0,0 +1,19 @@
+package com.adobe.phonegap.push;
+
+import android.content.Context;
+
+import com.google.android.gcm.GCMBroadcastReceiver;
+import static com.google.android.gcm.GCMConstants.DEFAULT_INTENT_SERVICE_CLASS_NAME;
+
+/*
+ * Implementation of GCMBroadcastReceiver that hard-wires the intent service to be
+ * com.plugin.gcm.GCMIntentService, instead of your_package.GCMIntentService
+ */
+public class CordovaGCMBroadcastReceiver extends GCMBroadcastReceiver implements PushConstants {
+
+ @Override
+ protected String getGCMIntentServiceClassName(Context context) {
+ return COM_ADOBE_PHONEGAP_PUSH + DEFAULT_INTENT_SERVICE_CLASS_NAME;
+ }
+
+} \ No newline at end of file
diff --git a/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/GCMIntentService.java b/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/GCMIntentService.java
new file mode 100644
index 00000000..b22712d0
--- /dev/null
+++ b/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/GCMIntentService.java
@@ -0,0 +1,530 @@
+package com.adobe.phonegap.push;
+
+import android.annotation.SuppressLint;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.v4.app.NotificationCompat;
+import android.text.Html;
+import android.util.Log;
+
+import com.google.android.gcm.GCMBaseIntentService;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Random;
+
+@SuppressLint("NewApi")
+public class GCMIntentService extends GCMBaseIntentService implements PushConstants {
+
+ private static final String LOG_TAG = "PushPlugin_GCMIntentService";
+ private static HashMap<Integer, ArrayList<String>> messageMap = new HashMap<Integer, ArrayList<String>>();
+
+ public void setNotification(int notId, String message){
+ ArrayList<String> messageList = messageMap.get(notId);
+ if(messageList == null) {
+ messageList = new ArrayList<String>();
+ messageMap.put(notId, messageList);
+ }
+
+ if(message.isEmpty()){
+ messageList.clear();
+ }else{
+ messageList.add(message);
+ }
+ }
+
+ public GCMIntentService() {
+ super("GCMIntentService");
+ }
+
+ @Override
+ public void onRegistered(Context context, String regId) {
+
+ Log.v(LOG_TAG, "onRegistered: " + regId);
+
+ try {
+ JSONObject json = new JSONObject().put(REGISTRATION_ID, regId);
+
+ Log.v(LOG_TAG, "onRegistered: " + json.toString());
+
+ PushPlugin.sendEvent( json );
+ }
+ catch(JSONException e) {
+ // No message to the user is sent, JSON failed
+ Log.e(LOG_TAG, "onRegistered: JSON exception");
+ }
+ }
+
+ @Override
+ public void onUnregistered(Context context, String regId) {
+ Log.d(LOG_TAG, "onUnregistered - regId: " + regId);
+ }
+
+ @Override
+ protected void onMessage(Context context, Intent intent) {
+ Log.d(LOG_TAG, "onMessage - context: " + context);
+
+ // Extract the payload from the message
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ // if we are in the foreground, just surface the payload, else post it to the statusbar
+ if (PushPlugin.isInForeground()) {
+ extras.putBoolean(FOREGROUND, true);
+ PushPlugin.sendExtras(extras);
+ }
+ else {
+ extras.putBoolean(FOREGROUND, false);
+
+ // Send a notification if there is a message
+ String message = this.getMessageText(extras);
+ String title = getString(extras, TITLE, "");
+ if ((message != null && message.length() != 0) ||
+ (title != null && title.length() != 0)) {
+ createNotification(context, extras);
+ }
+ }
+ }
+ }
+
+ public void createNotification(Context context, Bundle extras) {
+ NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+ String appName = getAppName(this);
+ String packageName = context.getPackageName();
+ Resources resources = context.getResources();
+
+ int notId = parseInt(NOT_ID, extras);
+ Intent notificationIntent = new Intent(this, PushHandlerActivity.class);
+ notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ notificationIntent.putExtra(PUSH_BUNDLE, extras);
+ notificationIntent.putExtra(NOT_ID, notId);
+
+ int requestCode = new Random().nextInt();
+ PendingIntent contentIntent = PendingIntent.getActivity(this, requestCode, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ NotificationCompat.Builder mBuilder =
+ new NotificationCompat.Builder(context)
+ .setWhen(System.currentTimeMillis())
+ .setContentTitle(getString(extras, TITLE))
+ .setTicker(getString(extras, TITLE))
+ .setContentIntent(contentIntent)
+ .setAutoCancel(true);
+
+ SharedPreferences prefs = context.getSharedPreferences(PushPlugin.COM_ADOBE_PHONEGAP_PUSH, Context.MODE_PRIVATE);
+ String localIcon = prefs.getString(ICON, null);
+ String localIconColor = prefs.getString(ICON_COLOR, null);
+ boolean soundOption = prefs.getBoolean(SOUND, true);
+ boolean vibrateOption = prefs.getBoolean(VIBRATE, true);
+ Log.d(LOG_TAG, "stored icon=" + localIcon);
+ Log.d(LOG_TAG, "stored iconColor=" + localIconColor);
+ Log.d(LOG_TAG, "stored sound=" + soundOption);
+ Log.d(LOG_TAG, "stored vibrate=" + vibrateOption);
+
+ /*
+ * Notification Vibration
+ */
+
+ setNotificationVibration(extras, vibrateOption, mBuilder);
+
+ /*
+ * Notification Icon Color
+ *
+ * Sets the small-icon background color of the notification.
+ * To use, add the `iconColor` key to plugin android options
+ *
+ */
+ setNotificationIconColor(getString(extras,"color"), mBuilder, localIconColor);
+
+ /*
+ * Notification Icon
+ *
+ * Sets the small-icon of the notification.
+ *
+ * - checks the plugin options for `icon` key
+ * - if none, uses the application icon
+ *
+ * The icon value must be a string that maps to a drawable resource.
+ * If no resource is found, falls
+ *
+ */
+ setNotificationSmallIcon(context, extras, packageName, resources, mBuilder, localIcon);
+
+ /*
+ * Notification Large-Icon
+ *
+ * Sets the large-icon of the notification
+ *
+ * - checks the gcm data for the `image` key
+ * - checks to see if remote image, loads it.
+ * - checks to see if assets image, Loads It.
+ * - checks to see if resource image, LOADS IT!
+ * - if none, we don't set the large icon
+ *
+ */
+ setNotificationLargeIcon(extras, packageName, resources, mBuilder);
+
+ /*
+ * Notification Sound
+ */
+ if (soundOption) {
+ setNotificationSound(context, extras, mBuilder);
+ }
+
+ /*
+ * LED Notification
+ */
+ setNotificationLedColor(extras, mBuilder);
+
+ /*
+ * Priority Notification
+ */
+ setNotificationPriority(extras, mBuilder);
+
+ /*
+ * Notification message
+ */
+ setNotificationMessage(notId, extras, mBuilder);
+
+ /*
+ * Notification count
+ */
+ setNotificationCount(extras, mBuilder);
+
+ /*
+ * Notication add actions
+ */
+ createActions(extras, mBuilder, resources, packageName);
+
+ mNotificationManager.notify(appName, notId, mBuilder.build());
+ }
+
+ private void createActions(Bundle extras, NotificationCompat.Builder mBuilder, Resources resources, String packageName) {
+ Log.d(LOG_TAG, "create actions");
+ String actions = getString(extras, ACTIONS);
+ if (actions != null) {
+ try {
+ JSONArray actionsArray = new JSONArray(actions);
+ for (int i=0; i < actionsArray.length(); i++) {
+ Log.d(LOG_TAG, "adding action");
+ JSONObject action = actionsArray.getJSONObject(i);
+ Log.d(LOG_TAG, "adding callback = " + action.getString(CALLBACK));
+ Intent intent = new Intent(this, PushHandlerActivity.class);
+ intent.putExtra(CALLBACK, action.getString(CALLBACK));
+ intent.putExtra(PUSH_BUNDLE, extras);
+ PendingIntent pIntent = PendingIntent.getActivity(this, i, intent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ mBuilder.addAction(resources.getIdentifier(action.getString(ICON), DRAWABLE, packageName),
+ action.getString(TITLE), pIntent);
+ }
+ } catch(JSONException e) {
+ // nope
+ }
+ }
+ }
+
+ private void setNotificationCount(Bundle extras, NotificationCompat.Builder mBuilder) {
+ String msgcnt = getString(extras, MSGCNT);
+ if (msgcnt == null) {
+ msgcnt = getString(extras, BADGE);
+ }
+ if (msgcnt != null) {
+ mBuilder.setNumber(Integer.parseInt(msgcnt));
+ }
+ }
+
+ private void setNotificationVibration(Bundle extras, Boolean vibrateOption, NotificationCompat.Builder mBuilder) {
+ String vibrationPattern = getString(extras, VIBRATION_PATTERN);
+ if (vibrationPattern != null) {
+ String[] items = vibrationPattern.replaceAll("\\[", "").replaceAll("\\]", "").split(",");
+ long[] results = new long[items.length];
+ for (int i = 0; i < items.length; i++) {
+ try {
+ results[i] = Long.parseLong(items[i]);
+ } catch (NumberFormatException nfe) {}
+ }
+ mBuilder.setVibrate(results);
+ } else {
+ if (vibrateOption) {
+ mBuilder.setDefaults(Notification.DEFAULT_VIBRATE);
+ }
+ }
+ }
+
+ private void setNotificationMessage(int notId, Bundle extras, NotificationCompat.Builder mBuilder) {
+ String message = getMessageText(extras);
+
+ String style = getString(extras, STYLE, STYLE_TEXT);
+ if(STYLE_INBOX.equals(style)) {
+ setNotification(notId, message);
+
+ mBuilder.setContentText(message);
+
+ ArrayList<String> messageList = messageMap.get(notId);
+ Integer sizeList = messageList.size();
+ if (sizeList > 1) {
+ String sizeListMessage = sizeList.toString();
+ String stacking = sizeList + " more";
+ if (getString(extras, SUMMARY_TEXT) != null) {
+ stacking = getString(extras, SUMMARY_TEXT);
+ stacking = stacking.replace("%n%", sizeListMessage);
+ }
+ NotificationCompat.InboxStyle notificationInbox = new NotificationCompat.InboxStyle()
+ .setBigContentTitle(getString(extras, TITLE))
+ .setSummaryText(stacking);
+
+ for (int i = messageList.size() - 1; i >= 0; i--) {
+ notificationInbox.addLine(Html.fromHtml(messageList.get(i)));
+ }
+
+ mBuilder.setStyle(notificationInbox);
+ } else {
+ NotificationCompat.BigTextStyle bigText = new NotificationCompat.BigTextStyle();
+ if (message != null) {
+ bigText.bigText(message);
+ bigText.setBigContentTitle(getString(extras, TITLE));
+ mBuilder.setStyle(bigText);
+ }
+ }
+ } else if (STYLE_PICTURE.equals(style)) {
+ setNotification(notId, "");
+
+ NotificationCompat.BigPictureStyle bigPicture = new NotificationCompat.BigPictureStyle();
+ bigPicture.bigPicture(getBitmapFromURL(getString(extras, PICTURE)));
+ bigPicture.setBigContentTitle(getString(extras, TITLE));
+ bigPicture.setSummaryText(getString(extras, SUMMARY_TEXT));
+
+ mBuilder.setContentTitle(getString(extras, TITLE));
+ mBuilder.setContentText(message);
+
+ mBuilder.setStyle(bigPicture);
+ } else {
+ setNotification(notId, "");
+
+ NotificationCompat.BigTextStyle bigText = new NotificationCompat.BigTextStyle();
+
+ if (message != null) {
+ mBuilder.setContentText(Html.fromHtml(message));
+
+ bigText.bigText(message);
+ bigText.setBigContentTitle(getString(extras, TITLE));
+
+ String summaryText = getString(extras, SUMMARY_TEXT);
+ if (summaryText != null) {
+ bigText.setSummaryText(summaryText);
+ }
+
+ mBuilder.setStyle(bigText);
+ }
+ /*
+ else {
+ mBuilder.setContentText("<missing message content>");
+ }
+ */
+ }
+ }
+
+ private String getString(Bundle extras,String key) {
+ String message = extras.getString(key);
+ if (message == null) {
+ message = extras.getString(GCM_NOTIFICATION+"."+key);
+ }
+ return message;
+ }
+
+ private String getString(Bundle extras,String key, String defaultString) {
+ String message = extras.getString(key);
+ if (message == null) {
+ message = extras.getString(GCM_NOTIFICATION+"."+key, defaultString);
+ }
+ return message;
+ }
+
+ private String getMessageText(Bundle extras) {
+ String message = getString(extras, MESSAGE);
+ if (message == null) {
+ message = getString(extras, BODY);
+ }
+ return message;
+ }
+
+ private void setNotificationSound(Context context, Bundle extras, NotificationCompat.Builder mBuilder) {
+ String soundname = getString(extras, SOUNDNAME);
+ if (soundname == null) {
+ soundname = getString(extras, SOUND);
+ }
+ if (soundname != null) {
+ Uri sound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE
+ + "://" + context.getPackageName() + "/raw/" + soundname);
+ Log.d(LOG_TAG, sound.toString());
+ mBuilder.setSound(sound);
+ } else {
+ mBuilder.setSound(android.provider.Settings.System.DEFAULT_NOTIFICATION_URI);
+ }
+ }
+
+ private void setNotificationLedColor(Bundle extras, NotificationCompat.Builder mBuilder) {
+ String ledColor = getString(extras, LED_COLOR);
+ if (ledColor != null) {
+ // Converts parse Int Array from ledColor
+ String[] items = ledColor.replaceAll("\\[", "").replaceAll("\\]", "").split(",");
+ int[] results = new int[items.length];
+ for (int i = 0; i < items.length; i++) {
+ try {
+ results[i] = Integer.parseInt(items[i]);
+ } catch (NumberFormatException nfe) {}
+ }
+ if (results.length == 4) {
+ mBuilder.setLights(Color.argb(results[0], results[1], results[2], results[3]), 500, 500);
+ } else {
+ Log.e(LOG_TAG, "ledColor parameter must be an array of length == 4 (ARGB)");
+ }
+ }
+ }
+
+ private void setNotificationPriority(Bundle extras, NotificationCompat.Builder mBuilder) {
+ String priorityStr = getString(extras, PRIORITY);
+ if (priorityStr != null) {
+ try {
+ Integer priority = Integer.parseInt(priorityStr);
+ if (priority >= NotificationCompat.PRIORITY_MIN && priority <= NotificationCompat.PRIORITY_MAX) {
+ mBuilder.setPriority(priority);
+ } else {
+ Log.e(LOG_TAG, "Priority parameter must be between -2 and 2");
+ }
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ private void setNotificationLargeIcon(Bundle extras, String packageName, Resources resources, NotificationCompat.Builder mBuilder) {
+ String gcmLargeIcon = getString(extras, IMAGE); // from gcm
+ if (gcmLargeIcon != null) {
+ if (gcmLargeIcon.startsWith("http://") || gcmLargeIcon.startsWith("https://")) {
+ mBuilder.setLargeIcon(getBitmapFromURL(gcmLargeIcon));
+ Log.d(LOG_TAG, "using remote large-icon from gcm");
+ } else {
+ AssetManager assetManager = getAssets();
+ InputStream istr;
+ try {
+ istr = assetManager.open(gcmLargeIcon);
+ Bitmap bitmap = BitmapFactory.decodeStream(istr);
+ mBuilder.setLargeIcon(bitmap);
+ Log.d(LOG_TAG, "using assets large-icon from gcm");
+ } catch (IOException e) {
+ int largeIconId = 0;
+ largeIconId = resources.getIdentifier(gcmLargeIcon, DRAWABLE, packageName);
+ if (largeIconId != 0) {
+ Bitmap largeIconBitmap = BitmapFactory.decodeResource(resources, largeIconId);
+ mBuilder.setLargeIcon(largeIconBitmap);
+ Log.d(LOG_TAG, "using resources large-icon from gcm");
+ } else {
+ Log.d(LOG_TAG, "Not setting large icon");
+ }
+ }
+ }
+ }
+ }
+
+ private void setNotificationSmallIcon(Context context, Bundle extras, String packageName, Resources resources, NotificationCompat.Builder mBuilder, String localIcon) {
+ int iconId = 0;
+ String icon = getString(extras, ICON);
+ if (icon != null) {
+ iconId = resources.getIdentifier(icon, DRAWABLE, packageName);
+ Log.d(LOG_TAG, "using icon from plugin options");
+ }
+ else if (localIcon != null) {
+ iconId = resources.getIdentifier(localIcon, DRAWABLE, packageName);
+ Log.d(LOG_TAG, "using icon from plugin options");
+ }
+ if (iconId == 0) {
+ Log.d(LOG_TAG, "no icon resource found - using application icon");
+ iconId = context.getApplicationInfo().icon;
+ }
+ mBuilder.setSmallIcon(iconId);
+ }
+
+ private void setNotificationIconColor(String color, NotificationCompat.Builder mBuilder, String localIconColor) {
+ int iconColor = 0;
+ if (color != null) {
+ try {
+ iconColor = Color.parseColor(color);
+ } catch (IllegalArgumentException e) {
+ Log.e(LOG_TAG, "couldn't parse color from android options");
+ }
+ }
+ else if (localIconColor != null) {
+ try {
+ iconColor = Color.parseColor(localIconColor);
+ } catch (IllegalArgumentException e) {
+ Log.e(LOG_TAG, "couldn't parse color from android options");
+ }
+ }
+ if (iconColor != 0) {
+ mBuilder.setColor(iconColor);
+ }
+ }
+
+ public Bitmap getBitmapFromURL(String strURL) {
+ try {
+ URL url = new URL(strURL);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setDoInput(true);
+ connection.connect();
+ InputStream input = connection.getInputStream();
+ return BitmapFactory.decodeStream(input);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private static String getAppName(Context context) {
+ CharSequence appName = context.getPackageManager().getApplicationLabel(context.getApplicationInfo());
+ return (String)appName;
+ }
+
+ @Override
+ public void onError(Context context, String errorId) {
+ Log.e(LOG_TAG, "onError - errorId: " + errorId);
+ // if we are in the foreground, just send the error
+ if (PushPlugin.isInForeground()) {
+ PushPlugin.sendError(errorId);
+ }
+ }
+
+ private int parseInt(String value, Bundle extras) {
+ int retval = 0;
+
+ try {
+ retval = Integer.parseInt(getString(extras, value));
+ }
+ catch(NumberFormatException e) {
+ Log.e(LOG_TAG, "Number format exception - Error parsing " + value + ": " + e.getMessage());
+ }
+ catch(Exception e) {
+ Log.e(LOG_TAG, "Number format exception - Error parsing " + value + ": " + e.getMessage());
+ }
+
+ return retval;
+ }
+}
diff --git a/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/PushConstants.java b/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/PushConstants.java
new file mode 100644
index 00000000..09d7d4b9
--- /dev/null
+++ b/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/PushConstants.java
@@ -0,0 +1,44 @@
+package com.adobe.phonegap.push;
+
+public interface PushConstants {
+ public static final String COM_ADOBE_PHONEGAP_PUSH = "com.adobe.phonegap.push";
+ public static final String REGISTRATION_ID = "registrationId";
+ public static final String FOREGROUND = "foreground";
+ public static final String TITLE = "title";
+ public static final String NOT_ID = "notId";
+ public static final String PUSH_BUNDLE = "pushBundle";
+ public static final String ICON = "icon";
+ public static final String ICON_COLOR = "iconColor";
+ public static final String SOUND = "sound";
+ public static final String VIBRATE = "vibrate";
+ public static final String ACTIONS = "actions";
+ public static final String CALLBACK = "callback";
+ public static final String DRAWABLE = "drawable";
+ public static final String MSGCNT = "msgcnt";
+ public static final String VIBRATION_PATTERN = "vibrationPattern";
+ public static final String STYLE = "style";
+ public static final String SUMMARY_TEXT = "summaryText";
+ public static final String PICTURE = "picture";
+ public static final String GCM_NOTIFICATION = "gcm.notification";
+ public static final String MESSAGE = "message";
+ public static final String BODY = "body";
+ public static final String SOUNDNAME = "soundname";
+ public static final String LED_COLOR = "ledColor";
+ public static final String PRIORITY = "priority";
+ public static final String IMAGE = "image";
+ public static final String STYLE_INBOX = "inbox";
+ public static final String STYLE_PICTURE = "picture";
+ public static final String STYLE_TEXT = "text";
+ public static final String BADGE = "badge";
+ public static final String INITIALIZE = "init";
+ public static final String UNREGISTER = "unregister";
+ public static final String EXIT = "exit";
+ public static final String ANDROID = "android";
+ public static final String SENDER_ID = "senderID";
+ public static final String CLEAR_NOTIFICATIONS = "clearNotifications";
+ public static final String COLDSTART = "coldstart";
+ public static final String ADDITIONAL_DATA = "additionalData";
+ public static final String COUNT = "count";
+ public static final String FROM = "from";
+ public static final String COLLAPSE_KEY = "collapse_key";
+}
diff --git a/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/PushHandlerActivity.java b/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/PushHandlerActivity.java
new file mode 100644
index 00000000..57d2be84
--- /dev/null
+++ b/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/PushHandlerActivity.java
@@ -0,0 +1,70 @@
+package com.adobe.phonegap.push;
+
+import android.app.Activity;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.util.Log;
+
+public class PushHandlerActivity extends Activity implements PushConstants {
+ private static String LOG_TAG = "PushPlugin_PushHandlerActivity";
+
+ /*
+ * this activity will be started if the user touches a notification that we own.
+ * We send it's data off to the push plugin for processing.
+ * If needed, we boot up the main activity to kickstart the application.
+ * @see android.app.Activity#onCreate(android.os.Bundle)
+ */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ GCMIntentService gcm = new GCMIntentService();
+ gcm.setNotification(getIntent().getIntExtra(NOT_ID, 0), "");
+ super.onCreate(savedInstanceState);
+ Log.v(LOG_TAG, "onCreate");
+
+ boolean isPushPluginActive = PushPlugin.isActive();
+ processPushBundle(isPushPluginActive);
+
+ finish();
+
+ if (!isPushPluginActive) {
+ forceMainActivityReload();
+ }
+ }
+
+ /**
+ * Takes the pushBundle extras from the intent,
+ * and sends it through to the PushPlugin for processing.
+ */
+ private void processPushBundle(boolean isPushPluginActive) {
+ Bundle extras = getIntent().getExtras();
+
+ if (extras != null) {
+ Bundle originalExtras = extras.getBundle(PUSH_BUNDLE);
+
+ originalExtras.putBoolean(FOREGROUND, false);
+ originalExtras.putBoolean(COLDSTART, !isPushPluginActive);
+ originalExtras.putString(CALLBACK, getIntent().getExtras().getString("callback"));
+
+ PushPlugin.sendExtras(originalExtras);
+ }
+ }
+
+ /**
+ * Forces the main activity to re-launch if it's unloaded.
+ */
+ private void forceMainActivityReload() {
+ PackageManager pm = getPackageManager();
+ Intent launchIntent = pm.getLaunchIntentForPackage(getApplicationContext().getPackageName());
+ startActivity(launchIntent);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ final NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.cancelAll();
+ }
+} \ No newline at end of file
diff --git a/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/PushPlugin.java b/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/PushPlugin.java
new file mode 100644
index 00000000..781ed2d1
--- /dev/null
+++ b/plugins/phonegap-plugin-push/src/android/com/adobe/phonegap/push/PushPlugin.java
@@ -0,0 +1,250 @@
+package com.adobe.phonegap.push;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.google.android.gcm.GCMRegistrar;
+
+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.JSONObject;
+
+import java.util.Iterator;
+
+public class PushPlugin extends CordovaPlugin implements PushConstants {
+
+ public static final String LOG_TAG = "PushPlugin";
+
+ private static CallbackContext pushContext;
+ private static CordovaWebView gWebView;
+ private static Bundle gCachedExtras = null;
+ private static boolean gForeground = false;
+
+ /**
+ * Gets the application context from cordova's main activity.
+ * @return the application context
+ */
+ private Context getApplicationContext() {
+ return this.cordova.getActivity().getApplicationContext();
+ }
+
+ @Override
+ public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {
+
+ boolean result = false;
+
+ Log.v(LOG_TAG, "execute: action=" + action);
+
+ if (INITIALIZE.equals(action)) {
+ pushContext = callbackContext;
+ JSONObject jo = null;
+
+ Log.v(LOG_TAG, "execute: data=" + data.toString());
+
+ try {
+ jo = data.getJSONObject(0).getJSONObject(ANDROID);
+
+ gWebView = this.webView;
+ Log.v(LOG_TAG, "execute: jo=" + jo.toString());
+
+ String senderID = jo.getString(SENDER_ID);
+
+ Log.v(LOG_TAG, "execute: senderID=" + senderID);
+
+ GCMRegistrar.register(getApplicationContext(), senderID);
+ result = true;
+ } catch (JSONException e) {
+ Log.e(LOG_TAG, "execute: Got JSON Exception " + e.getMessage());
+ result = false;
+ callbackContext.error(e.getMessage());
+ }
+
+ if (jo != null) {
+ SharedPreferences sharedPref = getApplicationContext().getSharedPreferences(COM_ADOBE_PHONEGAP_PUSH, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ try {
+ editor.putString(ICON, jo.getString(ICON));
+ } catch (JSONException e) {
+ Log.d(LOG_TAG, "no icon option");
+ }
+ try {
+ editor.putString(ICON_COLOR, jo.getString(ICON_COLOR));
+ } catch (JSONException e) {
+ Log.d(LOG_TAG, "no iconColor option");
+ }
+ editor.putBoolean(SOUND, jo.optBoolean(SOUND, true));
+ editor.putBoolean(VIBRATE, jo.optBoolean(VIBRATE, true));
+ editor.putBoolean(CLEAR_NOTIFICATIONS, jo.optBoolean(CLEAR_NOTIFICATIONS, true));
+ editor.commit();
+ }
+
+ if ( gCachedExtras != null) {
+ Log.v(LOG_TAG, "sending cached extras");
+ sendExtras(gCachedExtras);
+ gCachedExtras = null;
+ }
+
+ } else if (UNREGISTER.equals(action)) {
+
+ GCMRegistrar.unregister(getApplicationContext());
+
+ Log.v(LOG_TAG, "UNREGISTER");
+ result = true;
+ callbackContext.success();
+ } else {
+ result = false;
+ Log.e(LOG_TAG, "Invalid action : " + action);
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.INVALID_ACTION));
+ }
+
+ return result;
+ }
+
+ public static void sendEvent(JSONObject _json) {
+ PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, _json);
+ pluginResult.setKeepCallback(true);
+ if (pushContext != null) {
+ pushContext.sendPluginResult(pluginResult);
+ }
+ }
+
+ public static void sendError(String message) {
+ PluginResult pluginResult = new PluginResult(PluginResult.Status.ERROR, message);
+ pluginResult.setKeepCallback(true);
+ if (pushContext != null) {
+ pushContext.sendPluginResult(pluginResult);
+ }
+ }
+
+ /*
+ * Sends the pushbundle extras to the client application.
+ * If the client application isn't currently active, it is cached for later processing.
+ */
+ public static void sendExtras(Bundle extras) {
+ if (extras != null) {
+ if (gWebView != null) {
+ sendEvent(convertBundleToJson(extras));
+ } else {
+ Log.v(LOG_TAG, "sendExtras: caching extras to send at a later time.");
+ gCachedExtras = extras;
+ }
+ }
+ }
+
+ @Override
+ public void initialize(CordovaInterface cordova, CordovaWebView webView) {
+ super.initialize(cordova, webView);
+ gForeground = true;
+ }
+
+ @Override
+ public void onPause(boolean multitasking) {
+ super.onPause(multitasking);
+ gForeground = false;
+
+ SharedPreferences prefs = getApplicationContext().getSharedPreferences(COM_ADOBE_PHONEGAP_PUSH, Context.MODE_PRIVATE);
+ if (prefs.getBoolean(CLEAR_NOTIFICATIONS, true)) {
+ final NotificationManager notificationManager = (NotificationManager) cordova.getActivity().getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.cancelAll();
+ }
+ }
+
+ @Override
+ public void onResume(boolean multitasking) {
+ super.onResume(multitasking);
+ gForeground = true;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ gForeground = false;
+ gWebView = null;
+ }
+
+ /*
+ * serializes a bundle to JSON.
+ */
+ private static JSONObject convertBundleToJson(Bundle extras) {
+ try {
+ JSONObject json = new JSONObject();
+ JSONObject additionalData = new JSONObject();
+ Iterator<String> it = extras.keySet().iterator();
+ while (it.hasNext()) {
+ String key = it.next();
+ Object value = extras.get(key);
+
+ Log.d(LOG_TAG, "key = " + key);
+ if (key.startsWith(GCM_NOTIFICATION)) {
+ key = key.substring(GCM_NOTIFICATION.length()+1, key.length());
+ }
+
+ // System data from Android
+ if (key.equals(FROM) || key.equals(COLLAPSE_KEY)) {
+ additionalData.put(key, value);
+ }
+ else if (key.equals(FOREGROUND)) {
+ additionalData.put(key, extras.getBoolean(FOREGROUND));
+ }
+ else if (key.equals(COLDSTART)){
+ additionalData.put(key, extras.getBoolean(COLDSTART));
+ } else if (key.equals(MESSAGE) || key.equals(BODY)) {
+ json.put(MESSAGE, value);
+ } else if (key.equals(TITLE)) {
+ json.put(TITLE, value);
+ } else if (key.equals(MSGCNT) || key.equals(BADGE)) {
+ json.put(COUNT, value);
+ } else if (key.equals(SOUNDNAME) || key.equals(SOUND)) {
+ json.put(SOUND, value);
+ } else if (key.equals(IMAGE)) {
+ json.put(IMAGE, value);
+ } else if (key.equals(CALLBACK)) {
+ json.put(CALLBACK, value);
+ }
+ else if ( value instanceof String ) {
+ String strValue = (String)value;
+ try {
+ // Try to figure out if the value is another JSON object
+ if (strValue.startsWith("{")) {
+ additionalData.put(key, new JSONObject(strValue));
+ }
+ // Try to figure out if the value is another JSON array
+ else if (strValue.startsWith("[")) {
+ additionalData.put(key, new JSONArray(strValue));
+ }
+ else {
+ additionalData.put(key, value);
+ }
+ } catch (Exception e) {
+ additionalData.put(key, value);
+ }
+ }
+ } // while
+
+ json.put(ADDITIONAL_DATA, additionalData);
+ Log.v(LOG_TAG, "extrasToJSON: " + json.toString());
+
+ return json;
+ }
+ catch( JSONException e) {
+ Log.e(LOG_TAG, "extrasToJSON: JSON exception");
+ }
+ return null;
+ }
+
+ public static boolean isInForeground() {
+ return gForeground;
+ }
+
+ public static boolean isActive() {
+ return gWebView != null;
+ }
+} \ No newline at end of file