/*
* Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.amazon.cordova.plugin;
import org.apache.cordova.CordovaActivity;
import org.json.JSONObject;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.Html;
import android.text.TextUtils;
import android.util.Log;
import android.app.Notification.Builder;
import com.amazon.device.messaging.ADMMessageHandlerBase;
import com.amazon.device.messaging.ADMMessageReceiver;
/**
* The ADMMessageHandler class receives messages sent by ADM via the receiver.
*/
public class ADMMessageHandler extends ADMMessageHandlerBase {
private static final String ERROR_EVENT = "error";
public static final String PUSH_BUNDLE = "pushBundle";
public static final String ERROR_MSG = "msg";
private static final String SHOW_MESSAGE_PREF = "showmessageinnotification";
private static final String DEFAULT_MESSAGE_PREF = "defaultnotificationmessage";
private static boolean shouldShowOfflineMessage = false;
private static String defaultOfflineMessage = null;
private static final String PREFS_NAME = "PushPluginPrefs";
private static final String DEFAULT_MESSAGE_TEXT = "You have a new message.";
// An identifier for ADM notification unique within your application
// It allows you to update the same notification later on
public static final int NOTIFICATION_ID = 519;
static Intent notificationIntent = null;
/**
* Class constructor.
*/
public ADMMessageHandler() {
super(ADMMessageHandler.class.getName());
}
/**
* Class constructor, including the className argument.
*
* @param className
* The name of the class.
*/
public ADMMessageHandler(final String className) {
super(className);
}
/**
* The Receiver class listens for messages from ADM and forwards them to the ADMMessageHandler class.
*/
public static class Receiver extends ADMMessageReceiver {
public Receiver() {
super(ADMMessageHandler.class);
}
// Nothing else is required here; your broadcast receiver automatically
// forwards intents to your service for processing.
}
/** {@inheritDoc} */
@Override
protected void onRegistered(final String newRegistrationId) {
// You start the registration process by calling startRegister() in your Main Activity.
// When the registration ID is ready, ADM calls onRegistered()
// on your app. Transmit the passed-in registration ID to your server, so
// your server can send messages to this app instance. onRegistered() is also
// called if your registration ID is rotated or changed for any reason;
// your app should pass the new registration ID to your server if this occurs.
// we fire the register event in the web app, register handler should
// fire to send the registration ID to your server via a header key/value pair over HTTP.(AJAX)
PushPlugin.sendRegistrationIdWithEvent(PushPlugin.REGISTER_EVENT,
newRegistrationId);
}
/** {@inheritDoc} */
@Override
protected void onUnregistered(final String registrationId) {
// If your app is unregistered on this device, inform your server that
// this app instance is no longer a valid target for messages.
PushPlugin.sendRegistrationIdWithEvent(PushPlugin.UNREGISTER_EVENT,
registrationId);
}
/** {@inheritDoc} */
@Override
protected void onRegistrationError(final String errorId) {
// You should consider a registration error fatal. In response, your app
// may degrade gracefully, or you may wish to notify the user that this part
// of your app's functionality is not available.
try {
JSONObject json;
json = new JSONObject().put(PushPlugin.EVENT, ERROR_EVENT);
json.put(ADMMessageHandler.ERROR_MSG, errorId);
PushPlugin.sendJavascript(json);
} catch (Exception e) {
Log.getStackTraceString(e);
}
}
/** {@inheritDoc} */
@Override
protected void onMessage(final Intent intent) {
// Extract the message content from the set of extras attached to
// the com.amazon.device.messaging.intent.RECEIVE intent.
// Extract the payload from the message
Bundle extras = intent.getExtras();
if (extras != null && (extras.getString(PushPlugin.MESSAGE) != null)) {
// if we are in the foreground, just surface the payload, else post
// it to the statusbar
if (PushPlugin.isInForeground()) {
extras.putBoolean(PushPlugin.FOREGROUND, true);
PushPlugin.sendExtras(extras);
} else {
extras.putBoolean(PushPlugin.FOREGROUND, false);
createNotification(this, extras);
}
}
}
/**
* Creates a notification when app is not running or is not in foreground. It puts the message info into the Intent
* extra
*
* @param context
* @param extras
*/
public void createNotification(Context context, Bundle extras) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String appName = getAppName(this);
// reuse the intent so that we can combine multiple messages into extra
if (notificationIntent == null) {
notificationIntent = new Intent(this, ADMHandlerActivity.class);
}
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
notificationIntent.putExtra("pushBundle", extras);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
final Builder notificationBuilder = new Notification.Builder(context);
notificationBuilder.setSmallIcon(context.getApplicationInfo().icon)
.setWhen(System.currentTimeMillis())
.setContentIntent(contentIntent);
if (this.shouldShowMessageInNotification()) {
String message = extras.getString(PushPlugin.MESSAGE);
notificationBuilder.setContentText(Html.fromHtml(message).toString());
} else {
notificationBuilder.setContentText(this.defaultMessageTextInNotification());
}
String title = appName;
notificationBuilder.setContentTitle(title).setTicker(title);
notificationBuilder.setAutoCancel(true);
// Because the ID remains unchanged, the existing notification is updated.
notificationManager.notify((String) appName, NOTIFICATION_ID,
notificationBuilder.getNotification());
}
public static void cancelNotification(Context context) {
NotificationManager mNotificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.cancel((String) getAppName(context),
NOTIFICATION_ID);
}
private static String getAppName(Context context) {
CharSequence appName = context.getPackageManager().getApplicationLabel(
context.getApplicationInfo());
return (String) appName;
}
// clean up the message in the intent
static void cleanupNotificationIntent() {
if (notificationIntent != null) {
Bundle pushBundle = notificationIntent.getExtras().getBundle(
PUSH_BUNDLE);
if (pushBundle != null) {
pushBundle.clear();
}
}
}
public static Bundle getOfflineMessage() {
Bundle pushBundle = null;
if (notificationIntent != null) {
pushBundle = notificationIntent.getExtras().getBundle(PUSH_BUNDLE);
if (pushBundle.isEmpty()) {
pushBundle = null;
}
}
return pushBundle;
}
/**
* Reads "shownotificationmessage" & "defaultnotificationmessage" config options
* If this is first-time it saves them to sharedPreferences so they can be read
* when app is forced-stop or killed
*/
public static void saveConfigOptions(Context context) {
if (context != null && TextUtils.isEmpty(defaultOfflineMessage)) {
// read config options from config.xml
shouldShowOfflineMessage = ((CordovaActivity) context)
.getBooleanProperty(SHOW_MESSAGE_PREF, false);
defaultOfflineMessage = ((CordovaActivity) context)
.getStringProperty(DEFAULT_MESSAGE_PREF, null);
// save them to sharedPreferences if necessary
SharedPreferences config = context.getApplicationContext().getSharedPreferences(PREFS_NAME, 0);
SharedPreferences.Editor editor = config.edit();
editor.putBoolean(SHOW_MESSAGE_PREF, shouldShowOfflineMessage);
editor.putString(DEFAULT_MESSAGE_PREF, defaultOfflineMessage);
// save prefs to disk
editor.commit();
}
}
/**
* Gets "shownotificationmessage" config option
*
* @return returns boolean- true is shownotificationmessage is set to true in config.xml/sharedPreferences otherwise false
*/
private boolean shouldShowMessageInNotification() {
//check if have cached copy of this option
if (TextUtils.isEmpty(defaultOfflineMessage)) {
//need to read it from sharedPreferences
SharedPreferences config = this.getApplicationContext().getSharedPreferences(PREFS_NAME,0);
if (config != null) {
shouldShowOfflineMessage = config.getBoolean(SHOW_MESSAGE_PREF, true);
}
}
return shouldShowOfflineMessage;
}
/**
* Gets "defaultnotificationmessage" config option
*
* @return returns default message provided by user in cofing.xml/sharedPreferences
*/
private String defaultMessageTextInNotification() {
//check if have cached copy of this option
if (TextUtils.isEmpty(defaultOfflineMessage)) {
SharedPreferences config = this.getApplicationContext().getSharedPreferences(PREFS_NAME,0);
if (config != null) {
defaultOfflineMessage = config.getString(DEFAULT_MESSAGE_PREF, DEFAULT_MESSAGE_TEXT);
}
}
return defaultOfflineMessage;
}
}