@@ -13,6 +13,7 @@ import 'package:http/testing.dart' as http_testing;
13
13
import 'package:zulip/api/model/model.dart' ;
14
14
import 'package:zulip/api/notifications.dart' ;
15
15
import 'package:zulip/host/android_notifications.dart' ;
16
+ import 'package:zulip/model/binding.dart' ;
16
17
import 'package:zulip/model/localizations.dart' ;
17
18
import 'package:zulip/model/narrow.dart' ;
18
19
import 'package:zulip/model/store.dart' ;
@@ -129,7 +130,8 @@ void main() {
129
130
..name.equals ('Messages' )
130
131
..importance.equals (NotificationImportance .high)
131
132
..lightsEnabled.equals (true )
132
- ..soundUrl.isNull ()
133
+ ..soundUrl.equals (testBinding.androidNotificationHost.fakeStoredNotificationSoundUrl (
134
+ NotificationChannelManager .kDefaultNotificationSound.resourceName))
133
135
..vibrationPattern.isNotNull ().deepEquals (
134
136
NotificationChannelManager .kVibrationPattern)
135
137
;
@@ -209,6 +211,158 @@ void main() {
209
211
..vibrationPattern.isNotNull ().deepEquals (
210
212
NotificationChannelManager .kVibrationPattern);
211
213
});
214
+
215
+ test ('on Android 28 (and lower) resource file is used for notification sound' , () async {
216
+ addTearDown (testBinding.reset);
217
+ final androidNotificationHost = testBinding.androidNotificationHost;
218
+
219
+ // Override android version
220
+ testBinding.deviceInfoResult =
221
+ const AndroidDeviceInfo (sdkInt: 28 , release: '10' );
222
+
223
+ // Ensure that on Android 10, notification sounds aren't being copied to
224
+ // the media store, and resource file is used directly.
225
+ await NotificationChannelManager .ensureChannel ();
226
+ check (androidNotificationHost.takeCopySoundResourceToMediaStoreCalls ()).length.equals (0 );
227
+
228
+ final defaultSoundResourceName =
229
+ NotificationChannelManager .kDefaultNotificationSound.resourceName;
230
+ final soundUrl =
231
+ 'android.resource://com.zulip.flutter/raw/$defaultSoundResourceName ' ;
232
+ check (androidNotificationHost.takeCreatedChannels ()).single
233
+ ..id.equals (NotificationChannelManager .kChannelId)
234
+ ..name.equals ('Messages' )
235
+ ..importance.equals (NotificationImportance .high)
236
+ ..lightsEnabled.equals (true )
237
+ ..soundUrl.equals (soundUrl)
238
+ ..vibrationPattern.isNotNull ().deepEquals (
239
+ NotificationChannelManager .kVibrationPattern);
240
+ });
241
+
242
+ test ('notification sound resource files are being copied to the media store' , () async {
243
+ addTearDown (testBinding.reset);
244
+ final androidNotificationHost = testBinding.androidNotificationHost;
245
+
246
+ await NotificationChannelManager .ensureChannel ();
247
+ check (androidNotificationHost.takeCopySoundResourceToMediaStoreCalls ())
248
+ .deepEquals (NotificationSound .values.map ((e) => (
249
+ sourceResourceName: e.resourceName,
250
+ targetFileDisplayName: e.fileDisplayName),
251
+ ));
252
+
253
+ // Ensure the default source URL points to a file in the media store,
254
+ // rather than a resource file.
255
+ final defaultSoundResourceName =
256
+ NotificationChannelManager .kDefaultNotificationSound.resourceName;
257
+ final soundUrl =
258
+ androidNotificationHost.fakeStoredNotificationSoundUrl (defaultSoundResourceName);
259
+ check (androidNotificationHost.takeCreatedChannels ()).single
260
+ ..id.equals (NotificationChannelManager .kChannelId)
261
+ ..name.equals ('Messages' )
262
+ ..importance.equals (NotificationImportance .high)
263
+ ..lightsEnabled.equals (true )
264
+ ..soundUrl.equals (soundUrl)
265
+ ..vibrationPattern.isNotNull ().deepEquals (
266
+ NotificationChannelManager .kVibrationPattern);
267
+ });
268
+
269
+ test ('notification sounds are not copied again if they were previously copied' , () async {
270
+ addTearDown (testBinding.reset);
271
+ final androidNotificationHost = testBinding.androidNotificationHost;
272
+
273
+ // Emulate that all notifications sounds are already in the media store.
274
+ androidNotificationHost.setupStoredNotificationSounds (
275
+ NotificationSound .values.map ((e) => StoredNotificationSound (
276
+ fileName: e.fileDisplayName,
277
+ isOwned: true ,
278
+ contentUrl: androidNotificationHost.fakeStoredNotificationSoundUrl (e.resourceName)),
279
+ ).toList (),
280
+ );
281
+
282
+ await NotificationChannelManager .ensureChannel ();
283
+ check (androidNotificationHost.takeCopySoundResourceToMediaStoreCalls ()).length.equals (0 );
284
+
285
+ final defaultSoundResourceName =
286
+ NotificationChannelManager .kDefaultNotificationSound.resourceName;
287
+ final soundUrl =
288
+ androidNotificationHost.fakeStoredNotificationSoundUrl (defaultSoundResourceName);
289
+ check (androidNotificationHost.takeCreatedChannels ()).single
290
+ ..id.equals (NotificationChannelManager .kChannelId)
291
+ ..name.equals ('Messages' )
292
+ ..importance.equals (NotificationImportance .high)
293
+ ..lightsEnabled.equals (true )
294
+ ..soundUrl.equals (soundUrl)
295
+ ..vibrationPattern.isNotNull ().deepEquals (
296
+ NotificationChannelManager .kVibrationPattern);
297
+ });
298
+
299
+ test ('new notifications sounds are copied to media store' , () async {
300
+ addTearDown (testBinding.reset);
301
+ final androidNotificationHost = testBinding.androidNotificationHost;
302
+
303
+ // Emulate that except one sound, all other sounds are already in
304
+ // media store.
305
+ androidNotificationHost.setupStoredNotificationSounds (
306
+ NotificationSound .values.map ((e) => StoredNotificationSound (
307
+ fileName: e.fileDisplayName,
308
+ isOwned: true ,
309
+ contentUrl: androidNotificationHost.fakeStoredNotificationSoundUrl (e.resourceName)),
310
+ ).skip (1 ).toList ()
311
+ );
312
+
313
+ await NotificationChannelManager .ensureChannel ();
314
+ final firstSound = NotificationSound .values.first;
315
+ check (androidNotificationHost.takeCopySoundResourceToMediaStoreCalls ())
316
+ .single
317
+ ..sourceResourceName.equals (firstSound.resourceName)
318
+ ..targetFileDisplayName.equals (firstSound.fileDisplayName);
319
+
320
+ final defaultSoundResourceName =
321
+ NotificationChannelManager .kDefaultNotificationSound.resourceName;
322
+ final soundUrl =
323
+ androidNotificationHost.fakeStoredNotificationSoundUrl (defaultSoundResourceName);
324
+ check (androidNotificationHost.takeCreatedChannels ()).single
325
+ ..id.equals (NotificationChannelManager .kChannelId)
326
+ ..name.equals ('Messages' )
327
+ ..importance.equals (NotificationImportance .high)
328
+ ..lightsEnabled.equals (true )
329
+ ..soundUrl.equals (soundUrl)
330
+ ..vibrationPattern.isNotNull ().deepEquals (
331
+ NotificationChannelManager .kVibrationPattern);
332
+ });
333
+
334
+ test ('no recopying of existing notification sounds in the media store; default sound URL points to resource file' , () async {
335
+ addTearDown (testBinding.reset);
336
+ final androidNotificationHost = testBinding.androidNotificationHost;
337
+
338
+ androidNotificationHost.setupStoredNotificationSounds (
339
+ NotificationSound .values.map ((e) => StoredNotificationSound (
340
+ fileName: e.fileDisplayName,
341
+ isOwned: false ,
342
+ contentUrl: androidNotificationHost.fakeStoredNotificationSoundUrl (e.resourceName)),
343
+ ).toList ()
344
+ );
345
+
346
+ // Ensure that if a notification sound with the same name already exists
347
+ // in the media store, but it wasn't copied by us, no recopying should
348
+ // happen. Additionally, the default sound URL should point to the
349
+ // resource file, not the version in the media store.
350
+ await NotificationChannelManager .ensureChannel ();
351
+ check (androidNotificationHost.takeCopySoundResourceToMediaStoreCalls ()).length.equals (0 );
352
+
353
+ final defaultSoundResourceName =
354
+ NotificationChannelManager .kDefaultNotificationSound.resourceName;
355
+ final soundUrl =
356
+ 'android.resource://com.zulip.flutter/raw/$defaultSoundResourceName ' ;
357
+ check (androidNotificationHost.takeCreatedChannels ()).single
358
+ ..id.equals (NotificationChannelManager .kChannelId)
359
+ ..name.equals ('Messages' )
360
+ ..importance.equals (NotificationImportance .high)
361
+ ..lightsEnabled.equals (true )
362
+ ..soundUrl.equals (soundUrl)
363
+ ..vibrationPattern.isNotNull ().deepEquals (
364
+ NotificationChannelManager .kVibrationPattern);
365
+ });
212
366
});
213
367
214
368
group ('NotificationDisplayManager show' , () {
@@ -1182,6 +1336,11 @@ void main() {
1182
1336
});
1183
1337
}
1184
1338
1339
+ extension on Subject <CopySoundResourceToMediaStoreCall > {
1340
+ Subject <String > get targetFileDisplayName => has ((x) => x.targetFileDisplayName, 'targetFileDisplayName' );
1341
+ Subject <String > get sourceResourceName => has ((x) => x.sourceResourceName, 'sourceResourceName' );
1342
+ }
1343
+
1185
1344
extension NotificationChannelChecks on Subject <NotificationChannel > {
1186
1345
Subject <String > get id => has ((x) => x.id, 'id' );
1187
1346
Subject <int > get importance => has ((x) => x.importance, 'importance' );
0 commit comments