Page MenuHomePhabricator

D13167.id43726.diff
No OneTemporary

D13167.id43726.diff

diff --git a/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java b/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java
--- a/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java
+++ b/native/android/app/src/main/java/app/comm/android/notifications/CommNotificationsHandler.java
@@ -68,6 +68,8 @@
private static final String MMKV_KEY_SEPARATOR = ".";
private static final String MMKV_KEYSERVER_PREFIX = "KEYSERVER";
private static final String MMKV_UNREAD_COUNT_SUFFIX = "UNREAD_COUNT";
+ private static final String MMKV_UNREAD_THICK_THREADS =
+ "NOTIFS.UNREAD_THICK_THREADS";
private Bitmap displayableNotificationLargeIcon;
private NotificationManager notificationManager;
private LocalBroadcastManager localBroadcastManager;
@@ -244,13 +246,22 @@
for (StatusBarNotification notification :
notificationManager.getActiveNotifications()) {
String tag = notification.getTag();
+ Bundle data = notification.getNotification().extras;
+
+ boolean thinThreadRescind =
+ tag != null && rescindID != null && tag.equals(rescindID);
+
+ boolean thickThreadRescind = tag != null && data != null &&
+ threadID.equals(data.getString("threadID"));
+
boolean isGroupMember =
threadID.equals(notification.getNotification().getGroup());
+
boolean isGroupSummary =
(notification.getNotification().flags &
Notification.FLAG_GROUP_SUMMARY) == Notification.FLAG_GROUP_SUMMARY;
- if (tag != null && tag.equals(rescindID)) {
+ if (thinThreadRescind || thickThreadRescind) {
notificationManager.cancel(notification.getTag(), notification.getId());
} else if (
isGroupMember && isGroupSummary && StaffUtils.isStaffRelease()) {
@@ -271,30 +282,38 @@
}
private void handleUnreadCountUpdate(RemoteMessage message) {
- if (message.getData().get(KEYSERVER_ID_KEY) == null) {
- return;
- }
+ if (message.getData().get(KEYSERVER_ID_KEY) != null &&
+ message.getData().get(BADGE_KEY) != null) {
+ String badge = message.getData().get(BADGE_KEY);
+ String senderKeyserverID = message.getData().get(KEYSERVER_ID_KEY);
+ String senderKeyserverUnreadCountKey = String.join(
+ MMKV_KEY_SEPARATOR,
+ MMKV_KEYSERVER_PREFIX,
+ senderKeyserverID,
+ MMKV_UNREAD_COUNT_SUFFIX);
- String badge = message.getData().get(BADGE_KEY);
- if (badge == null) {
- return;
+ int senderKeyserverUnreadCount;
+ try {
+ senderKeyserverUnreadCount = Integer.parseInt(badge);
+ } catch (NumberFormatException e) {
+ Log.w("COMM", "Invalid badge count", e);
+ return;
+ }
+ CommMMKV.setInt(
+ senderKeyserverUnreadCountKey, senderKeyserverUnreadCount);
}
- String senderKeyserverID = message.getData().get(KEYSERVER_ID_KEY);
- String senderKeyserverUnreadCountKey = String.join(
- MMKV_KEY_SEPARATOR,
- MMKV_KEYSERVER_PREFIX,
- senderKeyserverID,
- MMKV_UNREAD_COUNT_SUFFIX);
-
- int senderKeyserverUnreadCount;
- try {
- senderKeyserverUnreadCount = Integer.parseInt(badge);
- } catch (NumberFormatException e) {
- Log.w("COMM", "Invalid badge count", e);
- return;
+ if (message.getData().get(SENDER_DEVICE_ID_KEY) != null &&
+ message.getData().get(THREAD_ID_KEY) != null &&
+ message.getData().get(RESCIND_KEY) != null) {
+ CommMMKV.removeElementFromStringSet(
+ MMKV_UNREAD_THICK_THREADS, message.getData().get(THREAD_ID_KEY));
+ } else if (
+ message.getData().get(SENDER_DEVICE_ID_KEY) != null &&
+ message.getData().get(THREAD_ID_KEY) != null) {
+ CommMMKV.addElementToStringSet(
+ MMKV_UNREAD_THICK_THREADS, message.getData().get(THREAD_ID_KEY));
}
- CommMMKV.setInt(senderKeyserverUnreadCountKey, senderKeyserverUnreadCount);
int totalUnreadCount = 0;
String[] allKeys = CommMMKV.getAllKeys();
@@ -313,6 +332,8 @@
totalUnreadCount += unreadCount;
}
+ totalUnreadCount += CommMMKV.getStringSet(MMKV_UNREAD_THICK_THREADS).length;
+
if (totalUnreadCount > 0) {
ShortcutBadger.applyCount(this, totalUnreadCount);
} else {
diff --git a/native/ios/NotificationService/NotificationService.mm b/native/ios/NotificationService/NotificationService.mm
--- a/native/ios/NotificationService/NotificationService.mm
+++ b/native/ios/NotificationService/NotificationService.mm
@@ -12,6 +12,7 @@
NSString *const backgroundNotificationTypeKey = @"backgroundNotifType";
NSString *const messageInfosKey = @"messageInfos";
+NSString *const threadIDKey = @"threadID";
NSString *const encryptedPayloadKey = @"encryptedPayload";
NSString *const encryptionFailedKey = @"encryptionFailed";
NSString *const collapseIDKey = @"collapseID";
@@ -28,6 +29,7 @@
const std::string mmkvKeySeparator = ".";
const std::string mmkvKeyserverPrefix = "KEYSERVER";
const std::string mmkvUnreadCountSuffix = "UNREAD_COUNT";
+const std::string unreadThickThreads = "NOTIFS.UNREAD_THICK_THREADS";
// The context for this constant can be found here:
// https://linear.app/comm/issue/ENG-3074#comment-bd2f5e28
@@ -177,27 +179,25 @@
}
// Step 3: Cumulative unread count calculation
- if (content.badge) {
- std::string unreadCountCalculationError;
- try {
- @try {
- [self calculateTotalUnreadCountInPlace:content];
- } @catch (NSException *e) {
- unreadCountCalculationError =
- "Obj-C exception: " + std::string([e.name UTF8String]) +
- " during unread count calculation.";
- }
- } catch (const std::exception &e) {
- unreadCountCalculationError = "C++ exception: " + std::string(e.what()) +
+ std::string unreadCountCalculationError;
+ try {
+ @try {
+ [self calculateTotalUnreadCountInPlace:content];
+ } @catch (NSException *e) {
+ unreadCountCalculationError =
+ "Obj-C exception: " + std::string([e.name UTF8String]) +
" during unread count calculation.";
}
+ } catch (const std::exception &e) {
+ unreadCountCalculationError = "C++ exception: " + std::string(e.what()) +
+ " during unread count calculation.";
+ }
- if (unreadCountCalculationError.size() &&
- comm::StaffUtils::isStaffRelease()) {
- [errorMessages
- addObject:[NSString stringWithUTF8String:unreadCountCalculationError
- .c_str()]];
- }
+ if (unreadCountCalculationError.size() &&
+ comm::StaffUtils::isStaffRelease()) {
+ [errorMessages
+ addObject:[NSString stringWithUTF8String:unreadCountCalculationError
+ .c_str()]];
}
// Step 4: (optional) rescind read notifications
@@ -208,11 +208,21 @@
std::string rescindErrorMessage;
try {
@try {
- [self removeNotificationsWithCondition:^BOOL(
- UNNotification *_Nonnull notif) {
- return [content.userInfo[@"notificationId"]
- isEqualToString:notif.request.content.userInfo[@"id"]];
- }];
+ if (content.userInfo[@"notificationId"]) {
+ // thin thread rescind
+ [self removeNotificationsWithCondition:^BOOL(
+ UNNotification *_Nonnull notif) {
+ return [content.userInfo[@"notificationId"]
+ isEqualToString:notif.request.content.userInfo[@"id"]];
+ }];
+ } else if (content.userInfo[threadIDKey]) {
+ // thick thread rescind
+ [self removeNotificationsWithCondition:^BOOL(
+ UNNotification *_Nonnull notif) {
+ return [content.userInfo[threadIDKey]
+ isEqualToString:notif.request.content.userInfo[threadIDKey]];
+ }];
+ }
} @catch (NSException *e) {
rescindErrorMessage =
"Obj-C exception: " + std::string([e.name UTF8String]) +
@@ -505,20 +515,32 @@
- (void)calculateTotalUnreadCountInPlace:
(UNMutableNotificationContent *)content {
- if (!content.userInfo[keyserverIDKey]) {
- return;
- }
- std::string senderKeyserverID =
- std::string([content.userInfo[keyserverIDKey] UTF8String]);
- std::string senderKeyserverUnreadCountKey = joinStrings(
- mmkvKeySeparator,
- {mmkvKeyserverPrefix, senderKeyserverID, mmkvUnreadCountSuffix});
+ if (content.userInfo[keyserverIDKey] && content.badge) {
+ std::string senderKeyserverID =
+ std::string([content.userInfo[keyserverIDKey] UTF8String]);
+ std::string senderKeyserverUnreadCountKey = joinStrings(
+ mmkvKeySeparator,
+ {mmkvKeyserverPrefix, senderKeyserverID, mmkvUnreadCountSuffix});
+
+ int senderKeyserverUnreadCount = [content.badge intValue];
+ comm::CommMMKV::setInt(
+ senderKeyserverUnreadCountKey, senderKeyserverUnreadCount);
+ }
- int senderKeyserverUnreadCount = [content.badge intValue];
- comm::CommMMKV::setInt(
- senderKeyserverUnreadCountKey, senderKeyserverUnreadCount);
+ if (content.userInfo[senderDeviceIDKey] && content.userInfo[threadIDKey] &&
+ [self isRescind:content.userInfo]) {
+ comm::CommMMKV::removeElementFromStringSet(
+ unreadThickThreads,
+ std::string([content.userInfo[threadIDKey] UTF8String]));
+ } else if (
+ content.userInfo[senderDeviceIDKey] && content.userInfo[threadIDKey]) {
+ comm::CommMMKV::addElementToStringSet(
+ unreadThickThreads,
+ std::string([content.userInfo[threadIDKey] UTF8String]));
+ }
+ // calculate unread counts from keyservers
int totalUnreadCount = 0;
std::vector<std::string> allKeys = comm::CommMMKV::getAllKeys();
for (const auto &key : allKeys) {
@@ -539,6 +561,9 @@
totalUnreadCount += unreadCount.value();
}
+ // calculate unread counts from thick threads
+ totalUnreadCount += comm::CommMMKV::getStringSet(unreadThickThreads).size();
+
content.badge = @(totalUnreadCount);
}
@@ -658,10 +683,10 @@
mutableUserInfo[needsSilentBadgeUpdateKey] = @(YES);
}
- NSString *threadID = decryptedPayload[@"threadID"];
+ NSString *threadID = decryptedPayload[threadIDKey];
if (threadID) {
content.threadIdentifier = threadID;
- mutableUserInfo[@"threadID"] = threadID;
+ mutableUserInfo[threadIDKey] = threadID;
if (mutableAps) {
mutableAps[@"thread-id"] = threadID;
}
@@ -678,7 +703,7 @@
// The rest have been already decrypted and handled.
static NSArray<NSString *> *handledKeys =
- @[ @"merged", @"badge", @"threadID" ];
+ @[ @"merged", @"badge", threadIDKey ];
for (NSString *payloadKey in decryptedPayload) {
if ([handledKeys containsObject:payloadKey]) {

File Metadata

Mime Type
text/plain
Expires
Sat, Dec 21, 9:00 PM (20 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2689065
Default Alt Text
D13167.id43726.diff (10 KB)

Event Timeline