Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3507481
D13167.id43726.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D13167.id43726.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D13167: Implement thick thread badge updates and rescinds handling in native notifs code
Attached
Detach File
Event Timeline
Log In to Comment