diff options
| author | Arjun Roychowdhury <pliablepixels@gmail.com> | 2015-10-18 20:27:36 -0400 |
|---|---|---|
| committer | Arjun Roychowdhury <pliablepixels@gmail.com> | 2015-10-18 20:27:36 -0400 |
| commit | ced14a385a8606319e5d7d604f65c7a33c8e1476 (patch) | |
| tree | a146b48048b31fd36c6a0336052ee5d2c34093b4 /plugins/phonegap-plugin-push/src/android | |
| parent | 50f2e00b5be8c0e13e5790c11cc2dc234577d447 (diff) | |
switched to new push plugin that works with JSON payloads
Diffstat (limited to 'plugins/phonegap-plugin-push/src/android')
6 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 diff --git a/plugins/phonegap-plugin-push/src/android/libs/gcm.jar b/plugins/phonegap-plugin-push/src/android/libs/gcm.jar Binary files differnew file mode 100644 index 00000000..ac109a83 --- /dev/null +++ b/plugins/phonegap-plugin-push/src/android/libs/gcm.jar |
