/*
* Created by Itzik Braun on 12/3/2015.
* Copyright (c) 2015 deluge. All rights reserved.
*
* Last Modification at: 3/12/15 4:35 PM
*/
package com.braunster.androidchatsdk.firebaseplugin.firebase.backendless;
import android.content.Context;
import android.content.Intent;
import com.backendless.push.BackendlessBroadcastReceiver;
import com.braunster.androidchatsdk.firebaseplugin.R;
import com.braunster.androidchatsdk.firebaseplugin.firebase.wrappers.BThreadWrapper;
import com.braunster.androidchatsdk.firebaseplugin.firebase.wrappers.BUserWrapper;
import com.braunster.chatsdk.Utils.Debug;
import com.braunster.chatsdk.Utils.NotificationUtils;
import com.braunster.chatsdk.Utils.helper.ChatSDKUiHelper;
import com.braunster.chatsdk.dao.BMessage;
import com.braunster.chatsdk.dao.BThread;
import com.braunster.chatsdk.dao.BUser;
import com.braunster.chatsdk.dao.core.DaoCore;
import com.braunster.chatsdk.network.BDefines;
import com.braunster.chatsdk.network.BNetworkManager;
import com.braunster.chatsdk.object.BError;
import com.google.firebase.auth.FirebaseAuth;
import org.jdeferred.DoneCallback;
import org.jdeferred.FailCallback;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Date;
import timber.log.Timber;
/**
*
* The receiver is the sole object to handle push notification from backendless server.
*
* The receiver will only notify for the currentUserModel() incoming messages any message for other user will be <b>ignored</b>.
* This behavior is due to multiple connection from the same phone.
*
* Then the receiver will check to see if the message is already on the db, if the message exist it will be <b>ignored</b>.
* This behavior prevents notifying the user for a message that is already seen by the user while the push was on its way.
*
* Then the receiver will parse the message data from the push json. After that it will validate, build and save the message to the db.
*
* Then the receiver will check if the user is authenticated, If he his the notification will lead him to the ChatActivity else he will be directed to the LoginActivity.
*
*/
public class ChatSDKReceiver extends BackendlessBroadcastReceiver {
private static final String TAG = ChatSDKReceiver.class.getSimpleName();
private static final boolean DEBUG = Debug.ChatSDKReceiver;
public static final String ACTION_MESSAGE = "com.braunster.chatsdk.parse.MESSAGE_RECEIVED";
public static final String ACTION_FOLLOWER_ADDED = "com.braunster.chatsdk.parse.FOLLOWER_ADDED";
@Override
public boolean onMessage(final Context context, Intent intent) {
if (!BNetworkManager.preferences.getBoolean(BDefines.Prefs.PushEnabled, BNetworkManager.PushEnabledDefaultValue))
return false;
try {
final JSONObject json = new JSONObject(intent.getExtras().getString("message"));
String action = json.getString(BDefines.Keys.ACTION);
if (action.equals(ACTION_MESSAGE))
{
// Getting the push channel used.
String channel = json.getString(BDefines.Keys.Channel);
if (DEBUG) Timber.d("got action: %s, on channel: %s ", action , channel);
createMessageNotification(context, intent, channel);
}
// Follower added action
else if (action.equals(ACTION_FOLLOWER_ADDED))
{
createFollowerNotification(context, intent);
}
} catch (JSONException e) {
if (DEBUG) Timber.e(e.getCause(), "JSONException: %s", e.getMessage());
}
return false;
}
@SuppressWarnings("all")// For supressing the BMessasge setType(int type) warning.
private void createMessageNotification(final Context context, Intent intent, String channel){
if(DEBUG) Timber.v("receiver create message notification");
try {
if (DEBUG) Timber.v("onReceive");
// The data saved for this push message.
final JSONObject json = new JSONObject(intent.getExtras().getString("message"));
// If the push is not for the current user we ignore it.
if (BNetworkManager.sharedManager().getNetworkAdapter() != null) {
BUser user = BNetworkManager.sharedManager().getNetworkAdapter().currentUserModel();
if (user != null && !channel.equals(user.getPushChannel()))
return;
}
// Extracting the message data from the push json.
String entityID = json.getString(BDefines.Keys.MESSAGE_ENTITY_ID);
final String threadEntityID = json.getString(BDefines.Keys.THREAD_ENTITY_ID);
final String senderEntityId = json.getString(BDefines.Keys.MESSAGE_SENDER_ENTITY_ID);
// Getting the sender and the thread.
BUser sender = DaoCore.fetchEntityWithEntityID(BUser.class, senderEntityId);
final BThread thread = DaoCore.fetchEntityWithEntityID(BThread.class, threadEntityID);
final Long dateLong =json.getLong(BDefines.Keys.MESSAGE_DATE);
final Date date = new Date(dateLong);
final Integer type = json.getInt(BDefines.Keys.MESSAGE_TYPE);
final String messagePayload = (json.getString(BDefines.Keys.MESSAGE_PAYLOAD));
if (DEBUG) Timber.d("Pushed message entity id: %s", entityID);
if (DEBUG) Timber.d("Pushed message thread entity id: %s", threadEntityID);
BMessage message = DaoCore.fetchEntityWithEntityID(BMessage.class, entityID);
// If the message isn't null that means the user already got notification for this message,
// So we are ignoring it.
if (message != null)
{
if (DEBUG) Timber.d("Message already exist");
return;
}
// Creating the new message.
message = new BMessage();
message.setDate(date);
message.setType(type);
message.setText(messagePayload);
message.setEntityID(entityID);
message.setIsRead(false);
// If we dont have the sender and thread we wont open the
// chat activity when the notification is pressed.
// Else we are setting the thread and sender to the message.
if (sender != null && thread != null)
{
// Marking the thread as not deleted.
thread.setDeleted(false);
DaoCore.updateEntity(thread);
message.setBUserSender(sender);
message.setThread(thread);
message = DaoCore.createEntity(message);
postMessageNotification(context, json, thread, message, true);
} else {
if (DEBUG) Timber.d("Entity is null,Is null? Sender: %s, Thread: %s", sender== null, thread==null);
// Getting the user and the thread from firebase
final BMessage finalMessage = message;
BUserWrapper.initWithEntityId(senderEntityId)
.once()
.then(new DoneCallback<BUser>() {
@Override
public void onDone(final BUser bUser) {
// Adding the user as the sender.
finalMessage.setBUserSender(bUser);
if (thread == null)
{
final BThreadWrapper threadWrapper =
new BThreadWrapper(threadEntityID);
threadWrapper
.on()
.then(new DoneCallback<BThread>() {
@Override
public void onDone(BThread bThread) {
BUser currentUser = BNetworkManager.sharedManager().getNetworkAdapter().currentUserModel();
// Add the current user to the thread if needed.
if (!threadWrapper.getModel().hasUser(currentUser)) {
threadWrapper.addUser(BUserWrapper.initWithModel(currentUser));
// Connecting both users to the thread.
DaoCore.connectUserAndThread(currentUser, threadWrapper.getModel());
DaoCore.connectUserAndThread(bUser, threadWrapper.getModel());
}
// Adding the thread to the message.
finalMessage.setThread(bThread);
// posting the notification. Also creating the new updated message.
postMessageNotification(context, json, bThread, DaoCore.createEntity(finalMessage), true);
threadWrapper.off();
}
})
.fail(new FailCallback() {
@Override
public void onFail(Object o) {
if (DEBUG) Timber.d("Failed to get thread.");
postMessageNotification(context, json, thread, finalMessage, false);
threadWrapper.off();
}
});
}
else postMessageNotification(context, json, thread, finalMessage, true);
}
}, new FailCallback<BError>() {
@Override
public void onFail(BError error) {
if (DEBUG) Timber.d("Failed to get user.");
postMessageNotification(context, json, thread, finalMessage, false);
}
});
}
} catch (JSONException e) {
if (DEBUG) Timber.e(e.getCause(), "JSONException: %s", e.getMessage());
}
}
private void postMessageNotification(Context context, JSONObject json, BThread thread, BMessage message, boolean messageIsValid){
Timber.v("receiver postmessage notification");
if (DEBUG) Timber.v("postMessageNotification: messageIsValid: %s", messageIsValid);
Intent resultIntent;
// If the user isn't authenticated press on the push will lead him to the
// Login activity.
if (FirebaseAuth.getInstance().getCurrentUser() == null)
{
if (DEBUG) Timber.d("no auth user");
resultIntent = new Intent(context, ChatSDKUiHelper.getInstance().loginActivity);
// Posting the notification.
try {
NotificationUtils.createAlertNotification(context, BDefines.MESSAGE_NOTIFICATION_ID, resultIntent,
NotificationUtils.getDataBundle(context.getString(R.string.not_message_title),
context.getString(R.string.not_message_ticker), json.getString(BDefines.Keys.CONTENT)));
} catch (JSONException e) {
if (DEBUG) Timber.e(e.getCause(), "JSONException: %s", e.getMessage());
}
}
else
{
if (DEBUG) Timber.i("user is authenticated");
// If the message is valid(Sender and Thread exist in the db)
// we should lead the user to the chat.
if (messageIsValid)
{
NotificationUtils.createMessageNotification(context, message);
return;
}
// Open main activity
else resultIntent = new Intent(context, ChatSDKUiHelper.getInstance().mainActivity);
// Posting the notification.
try {
NotificationUtils.createAlertNotification(context, BDefines.MESSAGE_NOTIFICATION_ID, resultIntent,
NotificationUtils.getDataBundle(context.getString(R.string.not_message_title),
context.getString(R.string.not_message_ticker), json.getString(BDefines.Keys.CONTENT)));
} catch (JSONException e) {
if (DEBUG) Timber.e(e.getCause(), "JSONException: %s", e.getMessage());
}
}
}
private void createFollowerNotification(Context context, Intent intent){
if(DEBUG) Timber.v("receiver create follower notification");
final JSONObject json;
try {
json = new JSONObject(intent.getExtras().getString("message"));
Intent resultIntent = new Intent(context, ChatSDKUiHelper.getInstance().mainActivity);
NotificationUtils.createAlertNotification(context, BDefines.FOLLOWER_NOTIFICATION_ID, resultIntent,
NotificationUtils.getDataBundle(context.getString(R.string.not_follower_title), context.getString(R.string.not_follower_ticker),
json.getString(BDefines.Keys.CONTENT)));
} catch (JSONException e) {
if (DEBUG) Timber.e(e.getCause(), "JSONException: %s", e.getMessage());
}
}
}