Skip to content
This repository has been archived by the owner on Sep 4, 2020. It is now read-only.

✨ Support messaging style for notifications #2743

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
154 changes: 152 additions & 2 deletions docs/PAYLOAD.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
- [Sound](#sound)
- [Stacking](#stacking)
- [Inbox Stacking](#inbox-stacking)
- [Messaging Stacking](#messaging-stacking)
- [Action Buttons](#action-buttons)
- [In Line Replies](#in-line-replies)
- [Led in Notifications](#led-in-notifications)
Expand Down Expand Up @@ -966,6 +967,155 @@ You will get an inbox view so you can display multiple notifications in a single

If you use `%n%` in the `summaryText` of the JSON coming down from FCM it will be replaced by the number of messages that are currently in the queue.

## Messaging Stacking

When developing messaging apps, a better alternative to stacking your notifications is to use the messaging style. The style is similar to the inbox stacking, but it also defines a sender name to be displayed next to each message. If the sender name is empty or not provided, no sender will be displayed (this is useful for private conversations). In this If you send the following JSON from FCM:

```json
{
"registration_ids": ["my device id"],
"data": {
"title": "John Smith",
"message": "My first message",
"style": "messaging",
"image": "https://randomuser.me/api/portraits/men/79.jpg",
"image-type": "circle"
}
}
```

Here is an example using fcm-node that sends the above JSON:

```javascript
const FCM = require('fcm-node');
// Replace these with your own values.
const apiKey = 'replace with API key';
const deviceID = 'my device id';
const fcm = new FCM(apiKey);

const message = {
to: deviceID,
data: {
title: 'John Smith',
message: 'My first message',
style: 'messaging',
image: 'https://randomuser.me/api/portraits/men/79.jpg',
'image-type': 'circle'
}
};

fcm.send(message, (err, response) => {
if (err) {
console.log(err);
console.log('Something has gone wrong!');
} else {
console.log('Successfully sent with response: ', response);
}
});
```

It will produce a notification for an individual conversation:

![2019-04-16 11 15 00](https://user-images.githubusercontent.com/7590321/56197310-d933da80-6038-11e9-887c-edeea100fcc5.png)

The result looks similar to inbox stacking, with the difference that messages won't be truncated to a single line.

If you follow it up with subsequent notifications like:

```json
{
"registration_ids": ["my device id"],
"data": {
"title": "John Smith",
"message": "My second message",
"style": "messaging",
"image": "https://randomuser.me/api/portraits/men/79.jpg",
"image-type": "circle"
}
}
```

Here is an example using fcm-node that sends the above JSON:

```javascript
const FCM = require('fcm-node');
// Replace these with your own values.
const apiKey = 'replace with API key';
const deviceID = 'my device id';
const fcm = new FCM(apiKey);

const message = {
to: deviceID,
data: {
title: 'John Smith',
message: 'My second message',
style: 'messaging',
image: 'https://randomuser.me/api/portraits/men/79.jpg',
'image-type': 'circle'
}
};

fcm.send(message, (err, response) => {
if (err) {
console.log(err);
console.log('Something has gone wrong!');
} else {
console.log('Successfully sent with response: ', response);
}
});
```

The new message will be added to the current notification.

![2019-04-16 11 15 00](https://user-images.githubusercontent.com/7590321/56197352-f1a3f500-6038-11e9-8616-77f499126914.png)

If you also specify the name of the user that sent the message, it will be displayed next to the message. This is useful for group conversations. If you send the following JSON from FCM:

```json
{
"registration_ids": ["my device id"],
"data": {
"title": "My Group",
"message": "My first message",
"style": "messaging",
"sender": "John Smith"
}
}
```

Here is an example using fcm-node that sends the above JSON:

```javascript
const FCM = require('fcm-node');
// Replace these with your own values.
const apiKey = 'replace with API key';
const deviceID = 'my device id';
const fcm = new FCM(apiKey);

const message = {
to: deviceID,
data: {
title: 'My Group',
message: 'My first message',
style: 'messaging',
sender: 'John Smith'
}
};

fcm.send(message, (err, response) => {
if (err) {
console.log(err);
console.log('Something has gone wrong!');
} else {
console.log('Successfully sent with response: ', response);
}
});
```

It will produce a notification for a group conversation:

![2019-04-16 11 15 00](https://user-images.githubusercontent.com/7590321/56197398-08e2e280-6039-11e9-8119-7be98822bf44.png)

## Action Buttons

Your notification can include a maximum of three action buttons. You register the event callback name for each of your actions, then when a user clicks on one of notification's buttons, the event corresponding to that button is fired and the listener you have registered is invoked. For instance, here is a setup with two actions `emailGuests` and `snooze`.
Expand Down Expand Up @@ -2128,12 +2278,12 @@ On iOS, using the FCM app server protocol, if you are trying to send a silent pu
"custom_var_2:" "custom value here" /* Retrieved on app as data.additionalData.custom_var_2 */
},
/* Forces FCM silent push notifications to be triggered in the foreground of your iOS device. */
"content_available": true
"content_available": true
}
```
*Doc modification came in response to @andreszs - Issue [#2449](https://github.com/phonegap/phonegap-plugin-push/issues/2449).

** IMPORTANT: When using the content_available field, Android payload issues may occur. [Read here](../docs/PAYLOAD.md#user-content-use-of-content_available-true) Make sure you separate your Android/iOS server payloads to mitigate any problems that may arise.
** IMPORTANT: When using the content_available field, Android payload issues may occur. [Read here](../docs/PAYLOAD.md#user-content-use-of-content_available-true) Make sure you separate your Android/iOS server payloads to mitigate any problems that may arise.

More information on how to send push notifications using the FCM HTTP protocol and payload details can be found here:

Expand Down
64 changes: 63 additions & 1 deletion src/android/com/adobe/phonegap/push/FCMService.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import android.text.Html;
import android.text.Spanned;
import android.util.Log;
import android.service.notification.StatusBarNotification;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
Expand Down Expand Up @@ -660,7 +661,47 @@ private void setNotificationOngoing(Bundle extras, NotificationCompat.Builder mB
private void setNotificationMessage(int notId, Bundle extras, NotificationCompat.Builder mBuilder) {
String message = extras.getString(MESSAGE);
String style = extras.getString(STYLE, STYLE_TEXT);
if (STYLE_INBOX.equals(style)) {

if (STYLE_MESSAGING.equals(style)) {
NotificationCompat.MessagingStyle msgStyle;
String title = extras.getString(TITLE);

// Find if there is a notification already displayed with this ID.
Notification notification = findActiveNotification(getApplicationContext(), notId);

if (notification) {
// Notification already displayed. Extract the MessagingStyle to add the message.
msgStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(notification);
} else {
// There is no notification, create a new style.
msgStyle = new NotificationCompat.MessagingStyle("");
}

// Add the new message to the style.
msgStyle.addMessage(message, System.currentTimeMillis(), extras.getString(SENDER, ""));

// Add the count of messages to the title if there is more than 1.
Integer sizeList = msgStyle.getMessages().size();

if (sizeList > 1) {
String stacking = "(" + sizeList + ")"; // Default value.

if (extras.getString(SUMMARY_TEXT) != null) {
stacking = extras.getString(SUMMARY_TEXT);
stacking = stacking.replace("%n%", sizeList);
}

if (!stacking.trim().equals("")) {
title += " " + stacking;
}
}

msgStyle.setConversationTitle(title);

// Use the style.
mBuilder.setStyle(msgStyle);

} else if (STYLE_INBOX.equals(style)) {
setNotification(notId, message);

mBuilder.setContentText(fromHtml(message));
Expand Down Expand Up @@ -728,6 +769,27 @@ private void setNotificationMessage(int notId, Bundle extras, NotificationCompat
}
}

/**
* Find an active notification with a certain ID.
*
* @param context Context.
* @param notId Notification ID to find.
* @return Notification The active notification, null if not found.
*/
private Notification findActiveNotification(Context context, Integer notId) {
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
StatusBarNotification[] notifications = mNotificationManager.getActiveNotifications();

// Find the notification.
for (int i = 0; i < notifications.length; i++) {
if (notifications[i].getId() == notId) {
return notifications[i].getNotification();
}
}

return null;
}

private void setNotificationSound(Context context, Bundle extras, NotificationCompat.Builder mBuilder) {
String soundname = extras.getString(SOUNDNAME);
if (soundname == null) {
Expand Down
2 changes: 2 additions & 0 deletions src/android/com/adobe/phonegap/push/PushConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public interface PushConstants {
public static final String ALERT = "alert";
public static final String MESSAGE = "message";
public static final String BODY = "body";
public static final String SENDER = "sender";
public static final String SOUNDNAME = "soundname";
public static final String COLOR = "color";
public static final String LED_COLOR = "ledColor";
Expand All @@ -39,6 +40,7 @@ public interface PushConstants {
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 STYLE_MESSAGING = "messaging";
public static final String BADGE = "badge";
public static final String INITIALIZE = "init";
public static final String SUBSCRIBE = "subscribe";
Expand Down