Skip to content

Commit 717b928

Browse files
authored
Merge pull request #6177 from element-hq/feature/bma/notificationCustomSound
Let enterprise build be able to use a different notification channel for noisy notification.
2 parents 3a565e6 + 4b1bffa commit 717b928

File tree

17 files changed

+135
-26
lines changed

17 files changed

+135
-26
lines changed

enterprise

features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ interface EnterpriseService {
3535

3636
fun bugReportUrlFlow(sessionId: SessionId?): Flow<BugReportUrl>
3737

38+
/**
39+
* Gets Notification Channel to use for the noisy notifications of the provided session.
40+
*/
41+
fun getNoisyNotificationChannelId(sessionId: SessionId): String?
42+
3843
companion object {
3944
const val ANY_ACCOUNT_PROVIDER = "*"
4045
}

features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,6 @@ class DefaultEnterpriseService : EnterpriseService {
4343
override fun bugReportUrlFlow(sessionId: SessionId?): Flow<BugReportUrl> {
4444
return flowOf(BugReportUrl.UseDefault)
4545
}
46+
47+
override fun getNoisyNotificationChannelId(sessionId: SessionId): String? = null
4648
}

features/enterprise/impl-foss/src/test/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseServiceTest.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,10 @@ class DefaultEnterpriseServiceTest {
9898
awaitComplete()
9999
}
100100
}
101+
102+
@Test
103+
fun `getNoisyNotificationChannelId returns null`() = runTest {
104+
val defaultEnterpriseService = DefaultEnterpriseService()
105+
assertThat(defaultEnterpriseService.getNoisyNotificationChannelId(A_SESSION_ID)).isNull()
106+
}
101107
}

features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class FakeEnterpriseService(
2929
private val overrideBrandColorResult: (SessionId?, String?) -> Unit = { _, _ -> lambdaError() },
3030
private val firebasePushGatewayResult: () -> String? = { lambdaError() },
3131
private val unifiedPushDefaultPushGatewayResult: () -> String? = { lambdaError() },
32+
private val getNoisyNotificationChannelIdResult: (SessionId?) -> String? = { lambdaError() },
3233
) : EnterpriseService {
3334
private val brandColorState = MutableStateFlow(initialBrandColor)
3435
private val semanticColorsState = MutableStateFlow(initialSemanticColors)
@@ -69,4 +70,8 @@ class FakeEnterpriseService(
6970
override fun bugReportUrlFlow(sessionId: SessionId?): Flow<BugReportUrl> {
7071
return bugReportUrlMutableFlow.asStateFlow()
7172
}
73+
74+
override fun getNoisyNotificationChannelId(sessionId: SessionId): String? {
75+
return getNoisyNotificationChannelIdResult(sessionId)
76+
}
7277
}
-8.48 KB
Binary file not shown.

libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/channels/NotificationChannels.kt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ import dev.zacsweers.metro.AppScope
2323
import dev.zacsweers.metro.ContributesBinding
2424
import dev.zacsweers.metro.SingleIn
2525
import io.element.android.appconfig.NotificationConfig
26+
import io.element.android.features.enterprise.api.EnterpriseService
2627
import io.element.android.libraries.di.annotations.ApplicationContext
28+
import io.element.android.libraries.matrix.api.core.SessionId
2729
import io.element.android.libraries.push.impl.R
2830
import io.element.android.services.toolbox.api.strings.StringProvider
2931

@@ -47,9 +49,10 @@ interface NotificationChannels {
4749

4850
/**
4951
* Get the channel for messages.
52+
* @param sessionId the session the message belongs to.
5053
* @param noisy true if the notification should have sound and vibration.
5154
*/
52-
fun getChannelIdForMessage(noisy: Boolean): String
55+
fun getChannelIdForMessage(sessionId: SessionId, noisy: Boolean): String
5356

5457
/**
5558
* Get the channel for test notifications.
@@ -67,6 +70,7 @@ class DefaultNotificationChannels(
6770
private val stringProvider: StringProvider,
6871
@ApplicationContext
6972
private val context: Context,
73+
private val enterpriseService: EnterpriseService,
7074
) : NotificationChannels {
7175
init {
7276
createNotificationChannels()
@@ -115,7 +119,7 @@ class DefaultNotificationChannels(
115119
.setSound(
116120
Uri.Builder()
117121
.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
118-
// Strangely wwe have to provide a "//" before the package name
122+
// Strangely we have to provide a "//" before the package name
119123
.path("//" + context.packageName + "/" + R.raw.message)
120124
.build(),
121125
AudioAttributes.Builder()
@@ -186,8 +190,13 @@ class DefaultNotificationChannels(
186190
return if (ring) RINGING_CALL_NOTIFICATION_CHANNEL_ID else CALL_NOTIFICATION_CHANNEL_ID
187191
}
188192

189-
override fun getChannelIdForMessage(noisy: Boolean): String {
190-
return if (noisy) NOISY_NOTIFICATION_CHANNEL_ID else SILENT_NOTIFICATION_CHANNEL_ID
193+
override fun getChannelIdForMessage(sessionId: SessionId, noisy: Boolean): String {
194+
return if (noisy) {
195+
enterpriseService.getNoisyNotificationChannelId(sessionId)
196+
?: NOISY_NOTIFICATION_CHANNEL_ID
197+
} else {
198+
SILENT_NOTIFICATION_CHANNEL_ID
199+
}
191200
}
192201

193202
override fun getChannelIdForTest(): String = NOISY_NOTIFICATION_CHANNEL_ID

libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/factories/NotificationCreator.kt

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,10 @@ class DefaultNotificationCreator(
152152
val channelId = if (containsMissedCall) {
153153
notificationChannels.getChannelForIncomingCall(false)
154154
} else {
155-
notificationChannels.getChannelIdForMessage(noisy = roomInfo.shouldBing)
155+
notificationChannels.getChannelIdForMessage(
156+
sessionId = roomInfo.sessionId,
157+
noisy = roomInfo.shouldBing,
158+
)
156159
}
157160
// A category allows groups of notifications to be ranked and filtered – per user or system settings.
158161
// For example, alarm notifications should display before promo notifications, or message from known contact
@@ -231,7 +234,10 @@ class DefaultNotificationCreator(
231234
notificationAccountParams: NotificationAccountParams,
232235
inviteNotifiableEvent: InviteNotifiableEvent,
233236
): Notification {
234-
val channelId = notificationChannels.getChannelIdForMessage(inviteNotifiableEvent.noisy)
237+
val channelId = notificationChannels.getChannelIdForMessage(
238+
sessionId = inviteNotifiableEvent.sessionId,
239+
noisy = inviteNotifiableEvent.noisy,
240+
)
235241
return NotificationCompat.Builder(context, channelId)
236242
.setOnlyAlertOnce(true)
237243
.setContentTitle((inviteNotifiableEvent.roomName ?: buildMeta.applicationName).annotateForDebug(5))
@@ -271,7 +277,10 @@ class DefaultNotificationCreator(
271277
notificationAccountParams: NotificationAccountParams,
272278
simpleNotifiableEvent: SimpleNotifiableEvent,
273279
): Notification {
274-
val channelId = notificationChannels.getChannelIdForMessage(simpleNotifiableEvent.noisy)
280+
val channelId = notificationChannels.getChannelIdForMessage(
281+
sessionId = simpleNotifiableEvent.sessionId,
282+
noisy = simpleNotifiableEvent.noisy,
283+
)
275284
return NotificationCompat.Builder(context, channelId)
276285
.setOnlyAlertOnce(true)
277286
.setContentTitle(buildMeta.applicationName.annotateForDebug(7))
@@ -304,13 +313,16 @@ class DefaultNotificationCreator(
304313
notificationAccountParams: NotificationAccountParams,
305314
fallbackNotifiableEvents: List<FallbackNotifiableEvent>,
306315
): Notification {
307-
val channelId = notificationChannels.getChannelIdForMessage(false)
316+
val fallbackNotifiableEvent = fallbackNotifiableEvents.first()
317+
val channelId = notificationChannels.getChannelIdForMessage(
318+
sessionId = fallbackNotifiableEvent.sessionId,
319+
noisy = false,
320+
)
308321
val existingCounter = existingNotification
309322
?.extras
310323
?.getInt(FALLBACK_COUNTER_EXTRA)
311324
?: 0
312325
val counter = existingCounter + fallbackNotifiableEvents.size
313-
val fallbackNotifiableEvent = fallbackNotifiableEvents.first()
314326
return NotificationCompat.Builder(context, channelId)
315327
.setOnlyAlertOnce(true)
316328
.setContentTitle(buildMeta.applicationName.annotateForDebug(7))
@@ -342,8 +354,11 @@ class DefaultNotificationCreator(
342354
noisy: Boolean,
343355
lastMessageTimestamp: Long,
344356
): Notification {
345-
val channelId = notificationChannels.getChannelIdForMessage(noisy)
346357
val userId = notificationAccountParams.user.userId
358+
val channelId = notificationChannels.getChannelIdForMessage(
359+
sessionId = userId,
360+
noisy = noisy,
361+
)
347362
return NotificationCompat.Builder(context, channelId)
348363
.setOnlyAlertOnce(true)
349364
// used in compat < N, after summary is built based on child notifications

libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultBaseRoomGroupMessageCreatorTest.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import android.os.Build
1313
import androidx.core.app.NotificationCompat
1414
import com.google.common.truth.Truth.assertThat
1515
import io.element.android.appconfig.NotificationConfig
16+
import io.element.android.features.enterprise.api.EnterpriseService
17+
import io.element.android.features.enterprise.test.FakeEnterpriseService
1618
import io.element.android.libraries.matrix.api.media.MediaSource
1719
import io.element.android.libraries.matrix.test.A_ROOM_ID
1820
import io.element.android.libraries.matrix.test.A_TIMESTAMP
@@ -66,7 +68,11 @@ class DefaultBaseRoomGroupMessageCreatorTest {
6668

6769
@Test
6870
fun `test createRoomMessage with one noisy Event`() = runTest {
69-
val sut = createRoomGroupMessageCreator()
71+
val sut = createRoomGroupMessageCreator(
72+
enterpriseService = FakeEnterpriseService(
73+
getNoisyNotificationChannelIdResult = { null }
74+
)
75+
)
7076
val fakeImageLoader = FakeImageLoader()
7177
val result = sut.createRoomMessage(
7278
notificationAccountParams = aNotificationAccountParams(),
@@ -228,6 +234,7 @@ class DefaultBaseRoomGroupMessageCreatorTest {
228234

229235
fun createRoomGroupMessageCreator(
230236
sdkIntProvider: BuildVersionSdkIntProvider = FakeBuildVersionSdkIntProvider(Build.VERSION_CODES.O),
237+
enterpriseService: EnterpriseService = FakeEnterpriseService(),
231238
): RoomGroupMessageCreator {
232239
val context = RuntimeEnvironment.getApplication() as Context
233240
val bitmapLoader = DefaultNotificationBitmapLoader(
@@ -236,7 +243,10 @@ fun createRoomGroupMessageCreator(
236243
initialsAvatarBitmapGenerator = FakeInitialsAvatarBitmapGenerator(),
237244
)
238245
return DefaultRoomGroupMessageCreator(
239-
notificationCreator = createNotificationCreator(bitmapLoader = bitmapLoader),
246+
notificationCreator = createNotificationCreator(
247+
bitmapLoader = bitmapLoader,
248+
enterpriseService = enterpriseService,
249+
),
240250
bitmapLoader = bitmapLoader,
241251
stringProvider = AndroidStringProvider(context.resources)
242252
)

libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/channels/FakeNotificationChannels.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@
88

99
package io.element.android.libraries.push.impl.notifications.channels
1010

11+
import io.element.android.libraries.matrix.api.core.SessionId
12+
1113
class FakeNotificationChannels(
1214
var channelForIncomingCall: (ring: Boolean) -> String = { _ -> "" },
13-
var channelIdForMessage: (noisy: Boolean) -> String = { _ -> "" },
15+
var channelIdForMessage: (sessionId: SessionId, noisy: Boolean) -> String = { _, _ -> "" },
1416
var channelIdForTest: () -> String = { "" }
1517
) : NotificationChannels {
1618
override fun getChannelForIncomingCall(ring: Boolean): String {
1719
return channelForIncomingCall(ring)
1820
}
1921

20-
override fun getChannelIdForMessage(noisy: Boolean): String {
21-
return channelIdForMessage(noisy)
22+
override fun getChannelIdForMessage(sessionId: SessionId, noisy: Boolean): String {
23+
return channelIdForMessage(sessionId, noisy)
2224
}
2325

2426
override fun getChannelIdForTest(): String {

0 commit comments

Comments
 (0)