package com.appboy;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import com.appboy.configuration.AppboyConfigurationProvider;
import com.appboy.push.AppboyNotificationActionUtils;
import com.appboy.push.AppboyNotificationUtils;
import com.appboy.support.AppboyLogger;
public final class AppboyAdmReceiver extends BroadcastReceiver {
private static final String TAG = String.format("%s.%s", Constants.APPBOY_LOG_TAG_PREFIX, AppboyAdmReceiver.class.getName());
private static final String ADM_RECEIVE_INTENT_ACTION = "com.amazon.device.messaging.intent.RECEIVE";
private static final String ADM_REGISTRATION_INTENT_ACTION = "com.amazon.device.messaging.intent.REGISTRATION";
private static final String ADM_ERROR_KEY = "error";
private static final String ADM_REGISTRATION_ID_KEY = "registration_id";
private static final String ADM_UNREGISTERED_KEY = "unregistered";
private static final String ADM_MESSAGE_TYPE_KEY = "message_type";
private static final String ADM_DELETED_MESSAGES_KEY = "deleted_messages";
private static final String ADM_NUMBER_OF_MESSAGES_DELETED_KEY = "total_deleted";
public static final String CAMPAIGN_ID_KEY = Constants.APPBOY_PUSH_CAMPAIGN_ID_KEY;
@Override
public void onReceive(Context context, Intent intent) {
AppboyLogger.i(TAG, String.format("Received broadcast message. Message: %s", intent.toString()));
String action = intent.getAction();
if (ADM_REGISTRATION_INTENT_ACTION.equals(action)) {
handleRegistrationEventIfEnabled(new AppboyConfigurationProvider(context), context, intent);
} else if (ADM_RECEIVE_INTENT_ACTION.equals(action)) {
handleAppboyAdmReceiveIntent(context, intent);
} else if (Constants.APPBOY_CANCEL_NOTIFICATION_ACTION.equals(action)) {
AppboyNotificationUtils.handleCancelNotificationAction(context, intent);
} else if (Constants.APPBOY_ACTION_CLICKED_ACTION.equals(action)) {
AppboyNotificationActionUtils.handleNotificationActionClicked(context, intent);
} else if (Constants.APPBOY_PUSH_CLICKED_ACTION.equals(action)) {
AppboyNotificationUtils.handleNotificationOpened(context, intent);
} else {
AppboyLogger.w(TAG, "The ADM receiver received a message not sent from Appboy. Ignoring the message.");
}
}
/**
* Processes the registration/unregistration result returned from the ADM servers. If the
* registration/unregistration is successful, this will store/clear the registration ID from the
* device. Otherwise, it will log an error message and the device will not be able to receive ADM
* messages.
*/
boolean handleRegistrationIntent(Context context, Intent intent) {
String error = intent.getStringExtra(ADM_ERROR_KEY);
String registrationId = intent.getStringExtra(ADM_REGISTRATION_ID_KEY);
String unregistered = intent.getStringExtra(ADM_UNREGISTERED_KEY);
if (error != null) {
AppboyLogger.e(TAG, "Error during ADM registration: " + error);
} else if (registrationId != null) {
AppboyLogger.i(TAG, "Registering for ADM messages with registrationId: " + registrationId);
Appboy.getInstance(context).registerAppboyPushMessages(registrationId);
} else if (unregistered != null) {
AppboyLogger.w(TAG, "The device was un-registered from ADM: " + unregistered);
} else {
AppboyLogger.w(TAG, "The ADM registration intent is missing error information, registration id, and unregistration "
+ "confirmation. Ignoring.");
return false;
}
return true;
}
/**
* Handles both Appboy data push ADM messages and notification messages. Notification messages are
* posted to the notification center if the ADM message contains a title and body and the payload
* is sent to the application via an Intent. Data push messages do not post to the notification
* center, although the payload is forwarded to the application via an Intent as well.
*/
boolean handleAppboyAdmMessage(Context context, Intent intent) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
String messageType = intent.getStringExtra(ADM_MESSAGE_TYPE_KEY);
if (ADM_DELETED_MESSAGES_KEY.equals(messageType)) {
int totalDeleted = intent.getIntExtra(ADM_NUMBER_OF_MESSAGES_DELETED_KEY, -1);
if (totalDeleted == -1) {
AppboyLogger.e(TAG, String.format("Unable to parse ADM message. Intent: %s", intent.toString()));
} else {
AppboyLogger.i(TAG, String.format("ADM deleted %d messages. Fetch them from Appboy.", totalDeleted));
}
return false;
} else {
Bundle admExtras = intent.getExtras();
AppboyLogger.d(TAG, String.format("Push message payload received: %s", admExtras));
// Parsing the Appboy data extras (data push).
Bundle appboyExtras = AppboyNotificationUtils.getAppboyExtrasWithoutPreprocessing(admExtras);
admExtras.putBundle(Constants.APPBOY_PUSH_EXTRAS_KEY, appboyExtras);
if (AppboyNotificationUtils.isNotificationMessage(intent)) {
int notificationId = AppboyNotificationUtils.getNotificationId(admExtras);
admExtras.putInt(Constants.APPBOY_PUSH_NOTIFICATION_ID, notificationId);
AppboyConfigurationProvider appConfigurationProvider = new AppboyConfigurationProvider(context);
IAppboyNotificationFactory appboyNotificationFactory = AppboyNotificationUtils.getActiveNotificationFactory();
Notification notification = appboyNotificationFactory.createNotification(appConfigurationProvider, context, admExtras, appboyExtras);
if (notification == null) {
AppboyLogger.d(TAG, "Notification created by notification factory was null. Not displaying notification.");
return false;
}
notificationManager.notify(Constants.APPBOY_PUSH_NOTIFICATION_TAG, notificationId, notification);
AppboyNotificationUtils.sendPushMessageReceivedBroadcast(context, admExtras);
// Since we have received a notification, we want to wake the device screen.
AppboyNotificationUtils.wakeScreenIfHasPermission(context, admExtras);
// Set a custom duration for this notification.
if (admExtras.containsKey(Constants.APPBOY_PUSH_NOTIFICATION_DURATION_KEY)) {
int durationInMillis = Integer.parseInt(admExtras.getString(Constants.APPBOY_PUSH_NOTIFICATION_DURATION_KEY));
AppboyNotificationUtils.setNotificationDurationAlarm(context, this.getClass(), notificationId, durationInMillis);
}
return true;
} else {
AppboyNotificationUtils.sendPushMessageReceivedBroadcast(context, admExtras);
AppboyNotificationUtils.requestGeofenceRefreshIfAppropriate(context, admExtras);
return false;
}
}
}
/**
* Runs the handleAppboyAdmMessage method in a background thread in case of an image push
* notification, which cannot be downloaded on the main thread.
*/
public class HandleAppboyAdmMessageTask extends AsyncTask<Void, Void, Void> {
private final Context mContext;
private final Intent mIntent;
public HandleAppboyAdmMessageTask(Context context, Intent intent) {
mContext = context;
mIntent = intent;
execute();
}
@Override
protected Void doInBackground(Void... voids) {
try {
handleAppboyAdmMessage(mContext, mIntent);
} catch (Exception e) {
AppboyLogger.e(TAG, "Failed to create and display notification.", e);
}
return null;
}
}
void handleAppboyAdmReceiveIntent(Context context, Intent intent) {
if (AppboyNotificationUtils.isAppboyPushMessage(intent)) {
new HandleAppboyAdmMessageTask(context, intent);
}
}
boolean handleRegistrationEventIfEnabled(AppboyConfigurationProvider appConfigurationProvider, Context context, Intent intent) {
AppboyLogger.i(TAG, String.format("Received ADM registration. Message: %s", intent.toString()));
// Only handle ADM registration events if ADM registration handling is turned on in the
// configuration file.
if (appConfigurationProvider.isAdmMessagingRegistrationEnabled()) {
AppboyLogger.d(TAG, "ADM enabled in appboy.xml. Continuing to process ADM registration intent.");
handleRegistrationIntent(context, intent);
return true;
}
AppboyLogger.w(TAG, "ADM not enabled in appboy.xml. Ignoring ADM registration intent. Note: you must set "
+ "com_appboy_push_adm_messaging_registration_enabled to true in your appboy.xml to enable ADM.");
return false;
}
}