From ba4b33be79924994e98b4ddb6b58d8f71bf8b5cf Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 13 Jun 2020 00:33:26 +0200 Subject: [PATCH 1/8] split notification channel groups from notification group namespace --- .../securesms/notifications/NotificationCenter.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java index 4eaa2ba85..60a73516e 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java @@ -129,7 +129,12 @@ public class NotificationCenter { // Groups and Notification channel groups // -------------------------------------------------------------------------------------------- - public static final String GRP_MSG = "chgrp_msg"; + // this is just to further organize the appearance of channels in the settings UI + private static final String CH_GRP_MSG = "chgrp_msg"; + + // this is to group together notifications as such, maybe including a summary, + // ^see https://developer.android.com/training/notify-user/group.html + private static final String GRP_MSG = "grp_msg"; // Notification IDs @@ -202,8 +207,8 @@ public class NotificationCenter { } private String getNotificationChannelGroup(NotificationManagerCompat notificationManager) { - if (notificationChannelsSupported() && notificationManager.getNotificationChannelGroup(GRP_MSG) == null) { - NotificationChannelGroup chGrp = new NotificationChannelGroup(GRP_MSG, context.getString(R.string.pref_chats)); + if (notificationChannelsSupported() && notificationManager.getNotificationChannelGroup(CH_GRP_MSG) == null) { + NotificationChannelGroup chGrp = new NotificationChannelGroup(CH_GRP_MSG, context.getString(R.string.pref_chats)); notificationManager.createNotificationChannelGroup(chGrp); } return GRP_MSG; From 56e083cc40219dbeb0208f85f3af71a023b6aef2 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 13 Jun 2020 15:17:06 +0200 Subject: [PATCH 2/8] fixup --- .../securesms/notifications/NotificationCenter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java index 60a73516e..d1d7b1b90 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java @@ -133,7 +133,7 @@ public class NotificationCenter { private static final String CH_GRP_MSG = "chgrp_msg"; // this is to group together notifications as such, maybe including a summary, - // ^see https://developer.android.com/training/notify-user/group.html + // see https://developer.android.com/training/notify-user/group.html private static final String GRP_MSG = "grp_msg"; From 974364fc4d7426027e9143296386ada0ec07a603 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 13 Jun 2020 02:05:36 +0200 Subject: [PATCH 3/8] add a basic summary to help android7+ grouping --- .../notifications/NotificationCenter.java | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java index d1d7b1b90..c0d89f4bb 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java @@ -140,8 +140,9 @@ public class NotificationCenter { // Notification IDs // -------------------------------------------------------------------------------------------- - public static final int ID_PERMANTENT = 1; - public static final int ID_MSG_OFFSET = 0; // msgId is added - as msgId start at 10, there are no conflicts with lower numbers + public static final int ID_PERMANTENT = 1; + public static final int ID_MSG_SUMMARY = 2; + public static final int ID_MSG_OFFSET = 0; // msgId is added - as msgId start at 10, there are no conflicts with lower numbers // Notification channels @@ -341,7 +342,8 @@ public class NotificationCenter { // even without a name or message displayed, // it makes sense to use separate notification channels and to open the respective chat directly - // the user may eg. have chosen a different sound - NotificationCompat.Builder builder = new NotificationCompat.Builder(context, getNotificationChannel(notificationManager, dcChat)) + String notificationChannel = getNotificationChannel(notificationManager, dcChat); + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, notificationChannel) .setSmallIcon(R.drawable.icon_notification) .setColor(context.getResources().getColor(R.color.delta_primary)) .setPriority(Prefs.getNotificationPriority(context)) @@ -349,6 +351,7 @@ public class NotificationCenter { .setGroup(GRP_MSG) .setOnlyAlertOnce(!signal) .setContentText(line) + .setDeleteIntent(getDeleteIntent()) .setContentIntent(getOpenChatIntent(chatId)); if (privacy.isDisplayContact()) { builder.setContentTitle(dcChat.getName()); @@ -472,6 +475,19 @@ public class NotificationCenter { // add notification, we use one notification per chat, // esp. older android are not that great at grouping notificationManager.notify(ID_MSG_OFFSET + chatId, builder.build()); + + // group notifications together in a summary + if (Build.VERSION.SDK_INT >= 23) { + NotificationCompat.Builder summary = new NotificationCompat.Builder(context, notificationChannel) + .setGroup(GRP_MSG) + .setGroupSummary(true) + .setSmallIcon(R.drawable.icon_notification) + .setColor(context.getResources().getColor(R.color.delta_primary)) + .setCategory(NotificationCompat.CATEGORY_MESSAGE) + .setContentTitle("summary title") + .setContentText("summary text"); + notificationManager.notify(ID_MSG_SUMMARY, summary.build()); + } }); } From 2caaa1e097c56df50a027164006d9fb26f1cd03f Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 13 Jun 2020 16:01:01 +0200 Subject: [PATCH 4/8] manually remove summary-notification; this is needed when we cancel the other notifications from within the app --- AndroidManifest.xml | 3 ++- .../notifications/MarkReadReceiver.java | 11 ++++++---- .../notifications/NotificationCenter.java | 20 +++++++++++++------ 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index ad500c2e8..89a1c6008 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -285,7 +285,8 @@ android:enabled="true" android:exported="false"> - + + diff --git a/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java b/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java index add98df8b..71a199816 100644 --- a/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java +++ b/src/org/thoughtcrime/securesms/notifications/MarkReadReceiver.java @@ -11,13 +11,14 @@ import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.util.Util; public class MarkReadReceiver extends BroadcastReceiver { - - public static final String CLEAR_ACTION = "org.thoughtcrime.securesms.notifications.CLEAR"; + public static final String MARK_NOTICED_ACTION = "org.thoughtcrime.securesms.notifications.MARK_NOTICED"; + public static final String CANCEL_ACTION = "org.thoughtcrime.securesms.notifications.CANCEL"; public static final String CHAT_ID_EXTRA = "chat_id"; @Override public void onReceive(final Context context, Intent intent) { - if (!CLEAR_ACTION.equals(intent.getAction())) { + boolean markNoticed = MARK_NOTICED_ACTION.equals(intent.getAction()); + if (!markNoticed && !CANCEL_ACTION.equals(intent.getAction())) { return; } @@ -30,7 +31,9 @@ public class MarkReadReceiver extends BroadcastReceiver { Util.runOnAnyBackgroundThread(() -> { dcContext.notificationCenter.removeNotifications(chatId); - dcContext.marknoticedChat(chatId); + if (markNoticed) { + dcContext.marknoticedChat(chatId); + } }); } } diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java index c0d89f4bb..bb0f47825 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java @@ -116,8 +116,8 @@ public class NotificationCenter { return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); } - private PendingIntent getMarkAsReadIntent(int chatId) { - Intent intent = new Intent(MarkReadReceiver.CLEAR_ACTION); + private PendingIntent getMarkAsReadIntent(int chatId, boolean markNoticed) { + Intent intent = new Intent(markNoticed? MarkReadReceiver.MARK_NOTICED_ACTION : MarkReadReceiver.CANCEL_ACTION); intent.setClass(context, MarkReadReceiver.class); intent.setData((Uri.parse("custom://"+System.currentTimeMillis()))); intent.putExtra(MarkReadReceiver.CHAT_ID_EXTRA, chatId); @@ -351,7 +351,7 @@ public class NotificationCenter { .setGroup(GRP_MSG) .setOnlyAlertOnce(!signal) .setContentText(line) - .setDeleteIntent(getDeleteIntent()) + .setDeleteIntent(getMarkAsReadIntent(chatId, false)) .setContentIntent(getOpenChatIntent(chatId)); if (privacy.isDisplayContact()) { builder.setContentTitle(dcChat.getName()); @@ -417,7 +417,7 @@ public class NotificationCenter { && !Prefs.isScreenLockEnabled(context)) { try { PendingIntent inNotificationReplyIntent = getRemoteReplyIntent(chatId); - PendingIntent markReadIntent = getMarkAsReadIntent(chatId); + PendingIntent markReadIntent = getMarkAsReadIntent(chatId, true); NotificationCompat.Action markAsReadAction = new NotificationCompat.Action(R.drawable.check, context.getString(R.string.notify_mark_read), @@ -492,11 +492,19 @@ public class NotificationCenter { } public void removeNotifications(int chatId) { + boolean removeSummary = false; synchronized (inboxes) { inboxes.remove(chatId); + removeSummary = inboxes.isEmpty(); } - NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); - notificationManager.cancel(ID_MSG_OFFSET + chatId); + + try { + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); + notificationManager.cancel(ID_MSG_OFFSET + chatId); + if (removeSummary) { + notificationManager.cancel(ID_MSG_SUMMARY); + } + } catch (Exception e) { Log.w(TAG, e); } } public void removeAllNotifiations() { From ce88b4cd71c09bde78846ccf33485a977fbf9d0e Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 13 Jun 2020 17:38:06 +0200 Subject: [PATCH 5/8] open chatlist on summary-click, remove all notifications in this case --- .../securesms/ConversationListActivity.java | 5 +++++ .../securesms/notifications/NotificationCenter.java | 12 ++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/org/thoughtcrime/securesms/ConversationListActivity.java b/src/org/thoughtcrime/securesms/ConversationListActivity.java index c45e24f35..9983def02 100644 --- a/src/org/thoughtcrime/securesms/ConversationListActivity.java +++ b/src/org/thoughtcrime/securesms/ConversationListActivity.java @@ -64,6 +64,7 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit @SuppressWarnings("unused") private static final String TAG = ConversationListActivity.class.getSimpleName(); private static final String OPENPGP4FPR = "openpgp4fpr"; + public static final String CLEAR_NOTIFICATIONS = "clear_notifications"; private final DynamicTheme dynamicTheme = new DynamicNoActionBarTheme(); private final DynamicLanguage dynamicLanguage = new DynamicLanguage(); @@ -128,6 +129,10 @@ public class ConversationListActivity extends PassphraseRequiredActionBarActivit getSupportActionBar().setDisplayHomeAsUpEnabled(false); } handleOpenpgp4fpr(); + + if (getIntent().getBooleanExtra(CLEAR_NOTIFICATIONS, false)) { + DcHelper.getContext(this).notificationCenter.removeAllNotifiations(); + } } @Override diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java index bb0f47825..38ae6a71f 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java @@ -28,6 +28,7 @@ import com.b44t.messenger.DcMsg; import com.bumptech.glide.load.engine.DiskCacheStrategy; import org.thoughtcrime.securesms.ConversationActivity; +import org.thoughtcrime.securesms.ConversationListActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.connect.ApplicationDcContext; import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; @@ -97,7 +98,13 @@ public class NotificationCenter { } return argb; } - + + private PendingIntent getOpenChatlistIntent() { + Intent intent = new Intent(context, ConversationListActivity.class); + intent.putExtra(ConversationListActivity.CLEAR_NOTIFICATIONS, true); + return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); + } + private PendingIntent getOpenChatIntent(int chatId) { Intent intent = new Intent(context, ConversationActivity.class); intent.putExtra(ConversationActivity.CHAT_ID_EXTRA, chatId); @@ -485,7 +492,8 @@ public class NotificationCenter { .setColor(context.getResources().getColor(R.color.delta_primary)) .setCategory(NotificationCompat.CATEGORY_MESSAGE) .setContentTitle("summary title") - .setContentText("summary text"); + .setContentText("summary text") + .setContentIntent(getOpenChatlistIntent()); notificationManager.notify(ID_MSG_SUMMARY, summary.build()); } }); From ede1dd60f4beedddfc58f6cd883b5b267d642299 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 13 Jun 2020 17:49:28 +0200 Subject: [PATCH 6/8] use correct SDK for grouping summary --- .../securesms/notifications/NotificationCenter.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java index 38ae6a71f..4ca1a1ebd 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java @@ -483,16 +483,18 @@ public class NotificationCenter { // esp. older android are not that great at grouping notificationManager.notify(ID_MSG_OFFSET + chatId, builder.build()); - // group notifications together in a summary - if (Build.VERSION.SDK_INT >= 23) { + // group notifications together in a summary, this is possible since SDK 24 (Android 7) + // https://developer.android.com/training/notify-user/group.html + // in theory, this won't be needed due to setGroup(), however, in practise, it is needed up to at least Android 10. + if (Build.VERSION.SDK_INT >= 24) { NotificationCompat.Builder summary = new NotificationCompat.Builder(context, notificationChannel) .setGroup(GRP_MSG) .setGroupSummary(true) .setSmallIcon(R.drawable.icon_notification) .setColor(context.getResources().getColor(R.color.delta_primary)) .setCategory(NotificationCompat.CATEGORY_MESSAGE) - .setContentTitle("summary title") - .setContentText("summary text") + .setContentTitle("Delta Chat") // content title would only be used on SDK <24 + .setContentText("New messages") // content text would only be used on SDK <24 .setContentIntent(getOpenChatlistIntent()); notificationManager.notify(ID_MSG_SUMMARY, summary.build()); } From 2b26d4709e8a356c770a0adbb8d1bad6a22f4e8b Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 13 Jun 2020 21:30:03 +0200 Subject: [PATCH 7/8] use longer excerpt, 100 characters is easily too few eg. on tables, also this allows the system to expand the notification text --- .../securesms/notifications/NotificationCenter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java index 4ca1a1ebd..c4e8fa351 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java @@ -333,7 +333,7 @@ public class NotificationCenter { NotificationPrivacyPreference privacy = Prefs.getNotificationPrivacy(context); DcMsg dcMsg = dcContext.getMsg(msgId); - String line = privacy.isDisplayMessage()? dcMsg.getSummarytext(100) : context.getString(R.string.notify_new_message); + String line = privacy.isDisplayMessage()? dcMsg.getSummarytext(2000) : context.getString(R.string.notify_new_message); if (dcChat.isGroup() && privacy.isDisplayContact()) { line = dcContext.getContact(dcMsg.getFromId()).getFirstName() + ": " + line; } From 7c2e6af32d20a3126784cbc8dd9eb24affec5bbf Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 15 Jun 2020 16:26:11 +0200 Subject: [PATCH 8/8] fix 'NotificationChannelGroup does not exist error', thanks @Hocuri --- .../securesms/notifications/NotificationCenter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java index c4e8fa351..4b94e8be6 100644 --- a/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java +++ b/src/org/thoughtcrime/securesms/notifications/NotificationCenter.java @@ -219,7 +219,7 @@ public class NotificationCenter { NotificationChannelGroup chGrp = new NotificationChannelGroup(CH_GRP_MSG, context.getString(R.string.pref_chats)); notificationManager.createNotificationChannelGroup(chGrp); } - return GRP_MSG; + return CH_GRP_MSG; } private String getNotificationChannel(NotificationManagerCompat notificationManager, DcChat dcChat) {