diff --git a/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java b/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java index 9045cd886..213c85202 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotification.java @@ -1,5 +1,6 @@ package com.mattermost.rnbeta; +import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.content.SharedPreferences; @@ -66,11 +67,9 @@ public class CustomPushNotification extends PushNotification { notificationsInChannel.remove(channelId); saveNotificationsMap(context, notificationsInChannel); - if (context != null) { - for (final Integer notificationId : notifications) { - final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); - notificationManager.cancel(notificationId); - } + for (final Integer notificationId : notifications) { + final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); + notificationManager.cancel(notificationId); } } } @@ -120,23 +119,32 @@ public class CustomPushNotification extends PushNotification { switch (type) { case PUSH_TYPE_MESSAGE: case PUSH_TYPE_SESSION: + boolean createSummary = type.equals(PUSH_TYPE_MESSAGE); if (!mAppLifecycleFacade.isAppVisible()) { if (type.equals(PUSH_TYPE_MESSAGE)) { if (channelId != null) { Map> notificationsInChannel = loadNotificationsMap(mContext); - synchronized (notificationsInChannel) { - List list = notificationsInChannel.get(channelId); - if (list == null) { - list = Collections.synchronizedList(new ArrayList(0)); - } - - list.add(0, notificationId); - notificationsInChannel.put(channelId, list); - saveNotificationsMap(mContext, notificationsInChannel); + List list = notificationsInChannel.get(channelId); + if (list == null) { + list = Collections.synchronizedList(new ArrayList(0)); } + + list.add(0, notificationId); + if (list.size() > 1) { + createSummary = false; + } + + if (createSummary) { + // Add the summary notification id as well + list.add(0, notificationId + 1); + } + + notificationsInChannel.put(channelId, list); + saveNotificationsMap(mContext, notificationsInChannel); } } - super.postNotification(notificationId); + + buildNotification(notificationId, createSummary); } else { notifyReceivedToJS(); } @@ -173,10 +181,25 @@ public class CustomPushNotification extends PushNotification { } } + private void buildNotification(Integer notificationId, boolean createSummary) { + final PendingIntent pendingIntent = super.getCTAPendingIntent(); + final Notification notification = buildNotification(pendingIntent); + if (createSummary) { + final Notification summary = getNotificationSummaryBuilder(pendingIntent).build(); + super.postNotification(summary, notificationId + 1); + } + super.postNotification(notification, notificationId); + } + @Override protected NotificationCompat.Builder getNotificationBuilder(PendingIntent intent) { Bundle bundle = mNotificationProps.asBundle(); - return CustomPushNotificationHelper.createNotificationBuilder(mContext, intent, bundle); + return CustomPushNotificationHelper.createNotificationBuilder(mContext, intent, bundle, false); + } + + protected NotificationCompat.Builder getNotificationSummaryBuilder(PendingIntent intent) { + Bundle bundle = mNotificationProps.asBundle(); + return CustomPushNotificationHelper.createNotificationBuilder(mContext, intent, bundle, true); } private void notificationReceiptDelivery(String ackId, String postId, String type, boolean isIdLoaded, ResolvePromise promise) { diff --git a/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotificationHelper.java b/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotificationHelper.java index 8a5537c2e..268ed2716 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotificationHelper.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/CustomPushNotificationHelper.java @@ -137,7 +137,7 @@ public class CustomPushNotificationHelper { .addAction(replyAction); } - public static NotificationCompat.Builder createNotificationBuilder(Context context, PendingIntent intent, Bundle bundle) { + public static NotificationCompat.Builder createNotificationBuilder(Context context, PendingIntent intent, Bundle bundle, boolean createSummary) { final NotificationCompat.Builder notification = new NotificationCompat.Builder(context, CHANNEL_HIGH_IMPORTANCE_ID); String channelId = bundle.getString("channel_id"); @@ -148,7 +148,7 @@ public class CustomPushNotificationHelper { addNotificationExtras(notification, bundle); setNotificationIcons(context, notification, bundle); setNotificationMessagingStyle(context, notification, bundle); - setNotificationGroup(notification, channelId); + setNotificationGroup(notification, channelId, createSummary); setNotificationBadgeType(notification); setNotificationSound(notification, notificationPreferences); setNotificationVibrate(notification, notificationPreferences); @@ -373,10 +373,13 @@ public class CustomPushNotificationHelper { notification.setStyle(messagingStyle); } - private static void setNotificationGroup(NotificationCompat.Builder notification, String channelId) { - notification - .setGroup(channelId) - .setGroupSummary(true); + private static void setNotificationGroup(NotificationCompat.Builder notification, String channelId, boolean setAsSummary) { + notification.setGroup(channelId); + + if (setAsSummary) { + // if this is the first notification for the channel then set as summary, otherwise skip + notification.setGroupSummary(true); + } } private static void setNotificationIcons(Context context, NotificationCompat.Builder notification, Bundle bundle) { diff --git a/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java b/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java index 9846bc19d..e6043bb63 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java @@ -4,7 +4,6 @@ import android.content.Context; import android.content.RestrictionsManager; import android.os.Bundle; import android.util.Log; -import java.lang.reflect.InvocationTargetException; import java.io.File; import java.util.HashMap; import java.util.List; @@ -101,7 +100,7 @@ private final ReactNativeHost mReactNativeHost = @Override protected JSIModulePackage getJSIModulePackage() { - return new CustomMMKVJSIModulePackage(); + return (JSIModulePackage) new CustomMMKVJSIModulePackage(); } }; diff --git a/android/app/src/main/java/com/mattermost/rnbeta/NotificationReplyBroadcastReceiver.java b/android/app/src/main/java/com/mattermost/rnbeta/NotificationReplyBroadcastReceiver.java index 471541bc1..c345222d0 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/NotificationReplyBroadcastReceiver.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/NotificationReplyBroadcastReceiver.java @@ -9,11 +9,13 @@ import android.content.Intent; import android.os.Bundle; import android.util.Log; +import androidx.annotation.NonNull; import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationManagerCompat; import androidx.core.app.Person; import java.io.IOException; +import java.util.Objects; import okhttp3.Call; import okhttp3.MediaType; @@ -21,7 +23,6 @@ import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; -import okhttp3.internal.annotations.EverythingIsNonNull; import org.json.JSONObject; import org.json.JSONException; @@ -88,21 +89,19 @@ public class NotificationReplyBroadcastReceiver extends BroadcastReceiver { client.newCall(request).enqueue(new okhttp3.Callback() { @Override - @EverythingIsNonNull - public void onFailure(Call call, IOException e) { + public void onFailure(@NonNull Call call, @NonNull IOException e) { Log.i("ReactNative", String.format("Reply FAILED exception %s", e.getMessage())); onReplyFailed(notificationId); } @Override - @EverythingIsNonNull - public void onResponse(Call call, final Response response) throws IOException { + public void onResponse(@NonNull Call call, @NonNull final Response response) throws IOException { if (response.isSuccessful()) { onReplySuccess(notificationId, message); Log.i("ReactNative", "Reply SUCCESS"); } else { assert response.body() != null; - Log.i("ReactNative", String.format("Reply FAILED status %s BODY %s", response.code(), response.body().string())); + Log.i("ReactNative", String.format("Reply FAILED status %s BODY %s", response.code(), Objects.requireNonNull(response.body()).string())); onReplyFailed(notificationId); } } @@ -133,7 +132,7 @@ public class NotificationReplyBroadcastReceiver extends BroadcastReceiver { final Intent cta = new Intent(mContext, ProxyService.class); final PushNotificationProps notificationProps = new PushNotificationProps(bundle); final PendingIntent pendingIntent = NotificationIntentAdapter.createPendingNotificationIntent(mContext, cta, notificationProps); - NotificationCompat.Builder builder = CustomPushNotificationHelper.createNotificationBuilder(mContext, pendingIntent, bundle); + NotificationCompat.Builder builder = CustomPushNotificationHelper.createNotificationBuilder(mContext, pendingIntent, bundle, false); Notification notification = builder.build(); NotificationCompat.MessagingStyle messagingStyle = NotificationCompat.MessagingStyle.extractMessagingStyleFromNotification(notification); assert messagingStyle != null;