Skip to content

Commit b5a7933

Browse files
notif: Use the same notification ID for every notification
Matching the `requestCode` is no longer necessary due to the removal of `pakcage:flutter_local_notifications`, which required it.
1 parent 65d280f commit b5a7933

File tree

2 files changed

+15
-29
lines changed

2 files changed

+15
-29
lines changed

lib/notifications/display.dart

+11-23
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import 'dart:async';
2-
import 'dart:convert';
32
import 'dart:io';
43

54
import 'package:http/http.dart' as http;
65
import 'package:collection/collection.dart';
7-
import 'package:crypto/crypto.dart';
86
import 'package:flutter_gen/gen_l10n/zulip_localizations.dart';
97
import 'package:flutter/foundation.dart';
108
import 'package:flutter/widgets.dart' hide Notification;
@@ -170,9 +168,7 @@ class NotificationDisplayManager {
170168
}).buildUrl();
171169

172170
await _androidHost.notify(
173-
// TODO the notification ID can be constant, instead of matching requestCode
174-
// (This is a legacy of `flutter_local_notifications`.)
175-
id: notificationIdAsHashOf(conversationKey),
171+
id: kNotificationId,
176172
tag: conversationKey,
177173
channelId: NotificationChannelManager.kChannelId,
178174
groupKey: groupKey,
@@ -215,7 +211,7 @@ class NotificationDisplayManager {
215211
);
216212

217213
await _androidHost.notify(
218-
id: notificationIdAsHashOf(groupKey),
214+
id: kNotificationId,
219215
tag: groupKey,
220216
channelId: NotificationChannelManager.kChannelId,
221217
groupKey: groupKey,
@@ -300,11 +296,18 @@ class NotificationDisplayManager {
300296
// Even though we enable the `autoCancel` flag for summary notification
301297
// during creation, the summary notification doesn't get auto canceled if
302298
// child notifications are canceled programatically as done above.
303-
await _androidHost.cancel(
304-
tag: groupKey, id: notificationIdAsHashOf(groupKey));
299+
await _androidHost.cancel(tag: groupKey, id: kNotificationId);
305300
}
306301
}
307302

303+
/// The constant numeric "ID" we use for all non-test notifications,
304+
/// along with unique tags.
305+
///
306+
/// Because we construct a unique string "tag" for each distinct
307+
/// notification, and Android notifications are identified by the
308+
/// pair (tag, ID), it's simplest to leave these numeric IDs all the same.
309+
static const kNotificationId = 0x00C0FFEE;
310+
308311
/// A key we use in [Notification.extras] for the [Message.id] of the
309312
/// latest Zulip message in the notification's conversation.
310313
///
@@ -313,21 +316,6 @@ class NotificationDisplayManager {
313316
@visibleForTesting
314317
static const kExtraLastZulipMessageId = 'lastZulipMessageId';
315318

316-
/// A notification ID, derived as a hash of the given string key.
317-
///
318-
/// The result fits in 31 bits, the size of a nonnegative Java `int`,
319-
/// so that it can be used as an Android notification ID. (It's possible
320-
/// negative values would work too, which would add one bit.)
321-
///
322-
/// This is a cryptographic hash, meaning that collisions are about as
323-
/// unlikely as one could hope for given the size of the hash.
324-
@visibleForTesting
325-
static int notificationIdAsHashOf(String key) {
326-
final bytes = sha256.convert(utf8.encode(key)).bytes;
327-
return bytes[0] | (bytes[1] << 8) | (bytes[2] << 16)
328-
| ((bytes[3] & 0x7f) << 24);
329-
}
330-
331319
static String _conversationKey(MessageFcmMessage data, String groupKey) {
332320
final conversation = switch (data.recipient) {
333321
FcmMessageChannelRecipient(:var streamId, :var topic) => 'stream:$streamId:$topic',

test/notifications/display_test.dart

+4-6
Original file line numberDiff line numberDiff line change
@@ -223,8 +223,6 @@ void main() {
223223

224224
final expectedTag = '${data.realmUrl}|${data.userId}|$expectedTagComponent';
225225
final expectedGroupKey = '${data.realmUrl}|${data.userId}';
226-
final expectedId =
227-
NotificationDisplayManager.notificationIdAsHashOf(expectedTag);
228226
const expectedPendingIntentFlags = PendingIntentFlag.immutable;
229227
const expectedIntentFlags = IntentFlag.activityClearTop | IntentFlag.activityNewTask;
230228
final expectedSelfUserKey = '${data.realmUrl}|${data.userId}';
@@ -256,7 +254,7 @@ void main() {
256254
check(testBinding.androidNotificationHost.takeNotifyCalls())
257255
.deepEquals(<Condition<Object?>>[
258256
(it) => it.isA<AndroidNotificationHostApiNotifyCall>()
259-
..id.equals(expectedId)
257+
..id.equals(NotificationDisplayManager.kNotificationId)
260258
..tag.equals(expectedTag)
261259
..channelId.equals(NotificationChannelManager.kChannelId)
262260
..contentTitle.isNull()
@@ -288,7 +286,7 @@ void main() {
288286
..dataUrl.equals(expectedIntentDataUrl.toString())
289287
..flags.equals(expectedIntentFlags))),
290288
(it) => it.isA<AndroidNotificationHostApiNotifyCall>()
291-
..id.equals(NotificationDisplayManager.notificationIdAsHashOf(expectedGroupKey))
289+
..id.equals(NotificationDisplayManager.kNotificationId)
292290
..tag.equals(expectedGroupKey)
293291
..channelId.equals(NotificationChannelManager.kChannelId)
294292
..contentTitle.isNull()
@@ -344,7 +342,7 @@ void main() {
344342
final expectedGroupKey = '${data.realmUrl}|${data.userId}';
345343
final expectedTag = '$expectedGroupKey|$tagComponent';
346344
return (it) => it.isA<StatusBarNotification>()
347-
..id.equals(NotificationDisplayManager.notificationIdAsHashOf(expectedTag))
345+
..id.equals(NotificationDisplayManager.kNotificationId)
348346
..notification.which((it) => it
349347
..group.equals(expectedGroupKey)
350348
..extras.deepEquals(<String, String>{
@@ -355,7 +353,7 @@ void main() {
355353

356354
Condition<Object?> conditionSummaryActiveNotif(String expectedGroupKey) {
357355
return (it) => it.isA<StatusBarNotification>()
358-
..id.equals(NotificationDisplayManager.notificationIdAsHashOf(expectedGroupKey))
356+
..id.equals(NotificationDisplayManager.kNotificationId)
359357
..notification.which((it) => it
360358
..group.equals(expectedGroupKey)
361359
..extras.isEmpty())

0 commit comments

Comments
 (0)