Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,40 @@
import android.app.NotificationManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuffXfermode;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
Comment thread
jasperhuangg marked this conversation as resolved.
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.app.Person;
import androidx.core.graphics.drawable.IconCompat;

import com.urbanairship.AirshipConfigOptions;
import com.urbanairship.json.JsonMap;
import com.urbanairship.json.JsonValue;
import com.urbanairship.push.PushMessage;
import com.urbanairship.push.notifications.NotificationArguments;
import com.urbanairship.reactnative.ReactNotificationProvider;
import com.urbanairship.util.ImageUtils;

import java.net.MalformedURLException;
import java.net.URL;
import java.sql.Timestamp;
import java.time.Instant;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
Expand All @@ -63,8 +67,6 @@ public class CustomNotificationProvider extends ReactNotificationProvider {

// Conversation JSON keys
private static final String PAYLOAD_KEY = "payload";
private static final String TYPE_KEY = "type";
private static final String REPORT_COMMENT_TYPE = "reportComment";

private final ExecutorService executorService = Executors.newCachedThreadPool();
public final HashMap<Integer, NotificationCache> cache = new HashMap<>();
Expand Down Expand Up @@ -92,16 +94,17 @@ protected NotificationCompat.Builder onExtendBuilder(@NonNull Context context, @
builder.setPriority(PRIORITY_MAX);
}

// Attempt to parse data and apply custom notification styling
if (message.containsKey(PAYLOAD_KEY)) {
try {
JsonMap payload = JsonValue.parseString(message.getExtra(PAYLOAD_KEY)).optMap();

// Apply message style only for report comments
if (REPORT_COMMENT_TYPE.equals(payload.get(TYPE_KEY).getString())) {
// Apply message style using onyxData from the notification payload
if (payload.get("onyxData").getList().size() > 0) {
applyMessageStyle(context, builder, payload, arguments.getNotificationId());
}
} catch (Exception e) {
Log.e(TAG, "Failed to parse conversation. SendID=" + message.getSendId(), e);
Log.e(TAG, "Failed to parse conversation, falling back to default notification style. SendID=" + message.getSendId(), e);
}
}

Expand Down Expand Up @@ -150,7 +153,7 @@ public Bitmap getCroppedBitmap(Bitmap bitmap) {

/**
* Applies the message style to the notification builder. It also takes advantage of the
* notification cache to build conversations.
* notification cache to build conversations style notifications.
*
* @param builder Notification builder that will receive the message style
* @param payload Notification payload, which contains all the data we need to build the notifications.
Expand All @@ -163,59 +166,82 @@ private void applyMessageStyle(@NonNull Context context, NotificationCompat.Buil
}

NotificationCache notificationCache = findOrCreateNotificationCache(reportID);
JsonMap reportAction = payload.get("reportAction").getMap();
String name = reportAction.get("person").getList().get(0).getMap().get("text").getString();
String avatar = reportAction.get("avatar").getString();
String accountID = Integer.toString(reportAction.get("actorAccountID").getInt(-1));
String message = reportAction.get("message").getList().get(0).getMap().get("text").getString();
long time = Timestamp.valueOf(reportAction.get("created").getString(Instant.now().toString())).getTime();
String roomName = payload.get("roomName") == null ? "" : payload.get("roomName").getString("");
String conversationTitle = roomName.isEmpty() ? "Chat with " + name : roomName;

// Retrieve or create the Person object who sent the latest report comment
Person person = notificationCache.people.get(accountID);
if (person == null) {
IconCompat iconCompat = fetchIcon(context, avatar);
person = new Person.Builder()
.setIcon(iconCompat)
.setKey(accountID)
.setName(name)
.build();

notificationCache.people.put(accountID, person);
}

// Store the latest report comment in the local conversation history
notificationCache.messages.add(new NotificationCache.Message(person, message, time));

// Create the messaging style notification builder for this notification.
// Associate the notification with the person who sent the report comment.
// If this conversation has 2 participants or more and there's no room name, we should mark
// it as a group conversation.
// Also set the conversation title.
NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(person)
.setGroupConversation(notificationCache.people.size() > 2 || !roomName.isEmpty())
.setConversationTitle(conversationTitle);

// Add all conversation messages to the notification, including the last one we just received.
for (NotificationCache.Message cachedMessage : notificationCache.messages) {
messagingStyle.addMessage(cachedMessage.text, cachedMessage.time, cachedMessage.person);
}
try {
JsonMap reportMap = payload.get("onyxData").getList().get(1).getMap().get("value").getMap();
String reportId = reportMap.keySet().iterator().next();
JsonMap messageData = reportMap.get(reportId).getMap();

String name = messageData.get("person").getList().get(0).getMap().get("text").getString();
String avatar = messageData.get("avatar").getString();
String accountID = Integer.toString(messageData.get("actorAccountID").getInt(-1));
String message = messageData.get("message").getList().get(0).getMap().get("text").getString();

String roomName = payload.get("roomName") == null ? "" : payload.get("roomName").getString("");
String conversationTitle = roomName.isEmpty() ? "Chat with " + name : roomName;

// Retrieve or create the Person object who sent the latest report comment
Person person = notificationCache.people.get(accountID);
if (person == null) {
IconCompat iconCompat = fetchIcon(context, avatar);
person = new Person.Builder()
.setIcon(iconCompat)
.setKey(accountID)
.setName(name)
.build();

notificationCache.people.put(accountID, person);
}

// Clear the previous notification associated to this conversation so it looks like we are
// replacing them with this new one we just built.
if (notificationCache.prevNotificationID != -1) {
NotificationManagerCompat.from(context).cancel(notificationCache.prevNotificationID);
}
// Store the latest report comment in the local conversation history
long createdTimeInMillis = getMessageTimeInMillis(messageData.get("created").getString(""));
notificationCache.messages.add(new NotificationCache.Message(person, message, createdTimeInMillis));

// Create the messaging style notification builder for this notification, associating the
// notification with the person who sent the report comment.
NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(person)
.setGroupConversation(notificationCache.people.size() > 2 || !roomName.isEmpty())
.setConversationTitle(conversationTitle);

// Apply the messaging style to the notification builder
builder.setStyle(messagingStyle);
// Add all conversation messages to the notification, including the last one we just received.
for (NotificationCache.Message cachedMessage : notificationCache.messages) {
messagingStyle.addMessage(cachedMessage.text, cachedMessage.time, cachedMessage.person);
}

// Clear the previous notification associated to this conversation so it looks like we are
// replacing them with this new one we just built.
if (notificationCache.prevNotificationID != -1) {
NotificationManagerCompat.from(context).cancel(notificationCache.prevNotificationID);
}

// Apply the messaging style to the notification builder
builder.setStyle(messagingStyle);

} catch (Exception e) {
e.printStackTrace();
}

// Store the new notification ID so we can replace the notification if this conversation
// receives more messages
notificationCache.prevNotificationID = notificationID;
}

/**
* Safely retrieve the message time in milliseconds
*/
private long getMessageTimeInMillis(String createdTime) {
if (!createdTime.isEmpty()) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
return sdf.parse(createdTime).getTime();
} catch (Exception e) {
Log.e(TAG, "error parsing createdTime: " + createdTime);
e.printStackTrace();
}
}
return Calendar.getInstance().getTimeInMillis();
}

/**
* Check if we are showing a notification related to a reportID.
* If not, create a new NotificationCache so we can build a conversation notification
Expand Down