Merge pull request #7584 from element-hq/feature/bma/fixSilentNotification

Ensure that noisy notifications are still noisy when the app has a PIN code.
This commit is contained in:
Benoit Marty
2026-08-27 20:02:51 +02:00
committed by GitHub
13 changed files with 362 additions and 15 deletions
@@ -30,6 +30,7 @@ fun aNotificationData(
senderIsNameAmbiguous: Boolean = false,
roomDisplayName: String? = A_ROOM_NAME,
roomJoinRule: JoinRule? = null,
isNoisy: Boolean = false,
): NotificationData {
return NotificationData(
sessionId = A_SESSION_ID,
@@ -45,7 +46,7 @@ fun aNotificationData(
isDm = false,
isSpace = isSpace,
isEncrypted = false,
isNoisy = false,
isNoisy = isNoisy,
timestamp = timestamp,
content = content,
hasMention = hasMention,
@@ -298,6 +298,7 @@ class DefaultNotifiableEventResolver(
roomId = roomId,
eventId = eventId,
cause = "Unable to decrypt event content",
noisy = isNoisy,
)
ResolvedPushEvent.Event(fallbackNotifiableEvent)
}
@@ -274,6 +274,12 @@ private fun NotifiableEvent.toFallbackNotifiableEvent(): FallbackNotifiableEvent
is FallbackNotifiableEvent -> timestamp
is NotifiableRingingCallEvent -> return null
}
val noisy = when (this) {
is NotifiableMessageEvent -> noisy
is InviteNotifiableEvent -> noisy
is SimpleNotifiableEvent -> noisy
is FallbackNotifiableEvent -> noisy
}
return FallbackNotifiableEvent(
sessionId = sessionId,
roomId = roomId,
@@ -283,6 +289,7 @@ private fun NotifiableEvent.toFallbackNotifiableEvent(): FallbackNotifiableEvent
canBeReplaced = false,
isRedacted = false,
isUpdated = false,
noisy = noisy,
timestamp = timestamp,
cause = null,
)
@@ -24,6 +24,7 @@ class FallbackNotificationFactory(
roomId: RoomId,
eventId: EventId,
cause: String?,
noisy: Boolean,
): FallbackNotifiableEvent = FallbackNotifiableEvent(
sessionId = sessionId,
roomId = roomId,
@@ -32,6 +33,7 @@ class FallbackNotificationFactory(
canBeReplaced = true,
isRedacted = false,
isUpdated = false,
noisy = noisy,
timestamp = clock.epochMillis(),
description = "",
cause = cause,
@@ -170,6 +170,7 @@ class DefaultNotificationResultProcessor(
roomId = RoomId(request.roomId),
eventId = EventId(request.eventId),
cause = exception.message,
noisy = false,
)
)
}
@@ -317,7 +317,7 @@ class DefaultNotificationCreator(
val fallbackNotifiableEvent = fallbackNotifiableEvents.first()
val channelId = notificationChannels.getChannelIdForMessage(
sessionId = fallbackNotifiableEvent.sessionId,
noisy = false,
noisy = fallbackNotifiableEvents.any { it.noisy },
)
val existingCounter = existingNotification
?.extras
@@ -25,6 +25,7 @@ data class FallbackNotifiableEvent(
override val canBeReplaced: Boolean,
override val isRedacted: Boolean,
override val isUpdated: Boolean,
val noisy: Boolean,
val timestamp: Long,
val cause: String?,
) : NotifiableEvent
@@ -712,6 +712,41 @@ class DefaultNotifiableEventResolverTest : RobolectricTest() {
canBeReplaced = true,
isRedacted = false,
isUpdated = false,
noisy = false,
timestamp = A_FAKE_TIMESTAMP,
cause = "Unable to decrypt event content",
)
)
assertThat(result.getEvent(request)).isEqualTo(Result.success(expectedResult))
}
@Test
fun `resolve RoomEncrypted noisy`() = runTest {
val sut = createDefaultNotifiableEventResolver(
notificationResult = Result.success(
mapOf(
AN_EVENT_ID to Result.success(
aNotificationData(
content = NotificationContent.MessageLike.RoomEncrypted,
isNoisy = true,
)
)
)
)
)
val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase")
val result = sut.resolveEvents(A_SESSION_ID, listOf(request))
val expectedResult = ResolvedPushEvent.Event(
FallbackNotifiableEvent(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
eventId = AN_EVENT_ID,
editedEventId = null,
description = "",
canBeReplaced = true,
isRedacted = false,
isUpdated = false,
noisy = true,
timestamp = A_FAKE_TIMESTAMP,
cause = "Unable to decrypt event content",
)
@@ -15,28 +15,35 @@ import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.features.enterprise.test.FakeEnterpriseService
import io.element.android.features.lockscreen.api.LockScreenService
import io.element.android.features.lockscreen.test.FakeLockScreenService
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_ROOM_ID_2
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID_2
import io.element.android.libraries.matrix.test.A_THREAD_ID
import io.element.android.libraries.matrix.test.A_THREAD_ID_2
import io.element.android.libraries.matrix.test.A_TIMESTAMP
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.FakeMatrixClientProvider
import io.element.android.libraries.matrix.ui.components.aMatrixUser
import io.element.android.libraries.matrix.ui.media.test.FakeImageLoaderHolder
import io.element.android.libraries.push.api.notifications.NotificationIdProvider
import io.element.android.libraries.push.impl.notifications.factories.NotificationAccountParams
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
import io.element.android.libraries.push.impl.notifications.factories.aNotificationAccountParams
import io.element.android.libraries.push.impl.notifications.fake.FakeActiveNotificationsProvider
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationCreator
import io.element.android.libraries.push.impl.notifications.fake.FakeNotificationDisplayer
import io.element.android.libraries.push.impl.notifications.fake.FakeRoomGroupMessageCreator
import io.element.android.libraries.push.impl.notifications.fake.FakeSummaryGroupMessageCreator
import io.element.android.libraries.push.impl.notifications.fixtures.A_NOTIFICATION
import io.element.android.libraries.push.impl.notifications.fixtures.aFallbackNotifiableEvent
import io.element.android.libraries.push.impl.notifications.fixtures.aNotifiableMessageEvent
import io.element.android.libraries.push.impl.notifications.fixtures.aSimpleNotifiableEvent
import io.element.android.libraries.push.impl.notifications.fixtures.anInviteNotifiableEvent
import io.element.android.libraries.push.impl.notifications.model.FallbackNotifiableEvent
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
import io.element.android.libraries.sessionstorage.api.SessionStore
import io.element.android.libraries.sessionstorage.api.observer.SessionObserver
@@ -48,6 +55,8 @@ import io.element.android.services.appnavstate.api.AppNavigationStateService
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
import io.element.android.services.appnavstate.test.aNavigationState
import io.element.android.services.appnavstate.test.anAppNavigationState
import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
import io.element.android.tests.testutils.lambda.LambdaThreeParamsRecorder
import io.element.android.tests.testutils.lambda.any
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value
@@ -472,6 +481,137 @@ class DefaultNotificationDrawerManagerTest {
extraInvocationsForNotificationSummary = 1,
)
@Test
fun `when the app is locked, a noisy message event produces a noisy fallback notification`() = testAppLockedNotifiableEventReceived(
notifiableEvent = aNotifiableMessageEvent(noisy = true),
expectedFallbackEvent = anExpectedFallbackNotifiableEvent(noisy = true, timestamp = A_TIMESTAMP),
)
@Test
fun `when the app is locked, a silent message event produces a silent fallback notification`() = testAppLockedNotifiableEventReceived(
notifiableEvent = aNotifiableMessageEvent(noisy = false),
expectedFallbackEvent = anExpectedFallbackNotifiableEvent(noisy = false, timestamp = A_TIMESTAMP),
)
@Test
fun `when the app is locked, a noisy invite event produces a noisy fallback notification`() = testAppLockedNotifiableEventReceived(
notifiableEvent = anInviteNotifiableEvent(noisy = true),
expectedFallbackEvent = anExpectedFallbackNotifiableEvent(noisy = true, timestamp = 0),
)
@Test
fun `when the app is locked, a silent invite event produces a silent fallback notification`() = testAppLockedNotifiableEventReceived(
notifiableEvent = anInviteNotifiableEvent(noisy = false),
expectedFallbackEvent = anExpectedFallbackNotifiableEvent(noisy = false, timestamp = 0),
)
@Test
fun `when the app is locked, a noisy simple event produces a noisy fallback notification`() = testAppLockedNotifiableEventReceived(
notifiableEvent = aSimpleNotifiableEvent(noisy = true),
expectedFallbackEvent = anExpectedFallbackNotifiableEvent(noisy = true, timestamp = 0),
)
@Test
fun `when the app is locked, a silent simple event produces a silent fallback notification`() = testAppLockedNotifiableEventReceived(
notifiableEvent = aSimpleNotifiableEvent(noisy = false),
expectedFallbackEvent = anExpectedFallbackNotifiableEvent(noisy = false, timestamp = 0),
)
@Test
fun `when the app is locked, a noisy fallback event stays noisy`() = testAppLockedNotifiableEventReceived(
notifiableEvent = aFallbackNotifiableEvent(noisy = true),
expectedFallbackEvent = anExpectedFallbackNotifiableEvent(noisy = true, timestamp = A_FAKE_TIMESTAMP),
)
@Test
fun `when the app is locked, a silent fallback event stays silent`() = testAppLockedNotifiableEventReceived(
notifiableEvent = aFallbackNotifiableEvent(noisy = false),
expectedFallbackEvent = anExpectedFallbackNotifiableEvent(noisy = false, timestamp = A_FAKE_TIMESTAMP),
)
@Test
fun `when the app is locked, all the events are grouped into a single fallback notification`() = runTest {
val createFallbackNotificationResult = aCreateFallbackNotificationRecorder()
val sut = createAppLockedNotificationDrawerManager(createFallbackNotificationResult)
sut.onNotifiableEventsReceived(
listOf(
aNotifiableMessageEvent(noisy = false),
aNotifiableMessageEvent(eventId = AN_EVENT_ID_2, noisy = true),
)
)
createFallbackNotificationResult.assertions()
.isCalledOnce()
.with(
value(null),
any(),
value(
listOf(
anExpectedFallbackNotifiableEvent(noisy = false, timestamp = A_TIMESTAMP),
anExpectedFallbackNotifiableEvent(eventId = AN_EVENT_ID_2, noisy = true, timestamp = A_TIMESTAMP),
)
),
)
}
@Test
fun `when the app is not locked, no fallback notification is created`() = runTest {
val createFallbackNotificationResult = aCreateFallbackNotificationRecorder()
val sut = createDefaultNotificationDrawerManager(
appNavigationStateService = FakeAppNavigationStateService(
initialAppNavigationState = anAppNavigationState(isInForeground = false),
),
notificationCreator = FakeNotificationCreator(
createFallbackNotificationResult = createFallbackNotificationResult,
),
lockScreenService = FakeLockScreenService().apply { setIsPinSetup(false) },
)
sut.onNotifiableEventsReceived(listOf(aNotifiableMessageEvent(noisy = true)))
createFallbackNotificationResult.assertions().isNeverCalled()
}
/**
* The content of the original event must be stripped, only the noisy flag, the ids and the timestamp are kept.
*/
private fun anExpectedFallbackNotifiableEvent(
eventId: EventId = AN_EVENT_ID,
noisy: Boolean,
timestamp: Long,
) = aFallbackNotifiableEvent(
eventId = eventId,
description = null,
canBeReplaced = false,
noisy = noisy,
timestamp = timestamp,
cause = null,
)
private fun aCreateFallbackNotificationRecorder() =
lambdaRecorder<Notification?, NotificationAccountParams, List<FallbackNotifiableEvent>, Notification> { _, _, _ -> A_NOTIFICATION }
private fun TestScope.createAppLockedNotificationDrawerManager(
createFallbackNotificationResult: LambdaThreeParamsRecorder<Notification?, NotificationAccountParams, List<FallbackNotifiableEvent>, Notification>,
) = createDefaultNotificationDrawerManager(
appNavigationStateService = FakeAppNavigationStateService(
initialAppNavigationState = anAppNavigationState(isInForeground = false),
),
notificationCreator = FakeNotificationCreator(
createFallbackNotificationResult = createFallbackNotificationResult,
),
lockScreenService = FakeLockScreenService().apply { setIsPinSetup(true) },
)
private fun testAppLockedNotifiableEventReceived(
notifiableEvent: NotifiableEvent,
expectedFallbackEvent: FallbackNotifiableEvent,
) = runTest {
val createFallbackNotificationResult = aCreateFallbackNotificationRecorder()
val sut = createAppLockedNotificationDrawerManager(createFallbackNotificationResult)
sut.onNotifiableEventsReceived(listOf(notifiableEvent))
createFallbackNotificationResult.assertions()
.isCalledOnce()
.with(value(null), any(), value(listOf(expectedFallbackEvent)))
}
private fun testOnNotifiableEventReceived(
appNavigationState: AppNavigationState,
notifiableEvents: List<NotifiableEvent>,
@@ -503,6 +643,7 @@ class DefaultNotificationDrawerManagerTest {
fun TestScope.createDefaultNotificationDrawerManager(
notificationDisplayer: NotificationDisplayer = FakeNotificationDisplayer(),
notificationRenderer: NotificationRenderer? = null,
notificationCreator: NotificationCreator = FakeNotificationCreator(),
appNavigationStateService: AppNavigationStateService = FakeAppNavigationStateService(),
roomGroupMessageCreator: RoomGroupMessageCreator = FakeRoomGroupMessageCreator(),
summaryGroupMessageCreator: SummaryGroupMessageCreator = FakeSummaryGroupMessageCreator(),
@@ -519,7 +660,7 @@ fun TestScope.createDefaultNotificationDrawerManager(
notificationRenderer = notificationRenderer ?: NotificationRenderer(
notificationDisplayer = notificationDisplayer,
notificationDataFactory = DefaultNotificationDataFactory(
notificationCreator = FakeNotificationCreator(),
notificationCreator = notificationCreator,
roomGroupMessageCreator = roomGroupMessageCreator,
summaryGroupMessageCreator = summaryGroupMessageCreator,
activeNotificationsProvider = activeNotificationsProvider,
@@ -267,6 +267,42 @@ class DefaultNotificationResultProcessorTest {
assertThat(receivedFallbackEvent).isTrue()
}
@Test
fun `when an event cannot be resolved, the generated fallback event is silent`() = runTest {
val onNotifiableEventsReceived = lambdaRecorder<List<NotifiableEvent>, Unit> {}
val onPushReceivedResult = lambdaRecorder<String, EventId?, RoomId?, SessionId?, Boolean, Boolean, String?, Unit> { _, _, _, _, _, _, _ -> }
val processor = createDefaultNotificationResultProcessor(
mutableBatteryOptimizationStore = FakeMutableBatteryOptimizationStore(
showBatteryOptimizationBannerResult = lambdaRecorder<Unit> {},
),
pushHistoryService = FakePushHistoryService(
onPushReceivedResult = onPushReceivedResult,
),
onNotifiableEventsReceived = onNotifiableEventsReceived,
)
runningProcessor(processor) {
emit(mapOf(aPushRequest() to Result.failure(NotificationResolverException.UnknownError("Unable to resolve event"))))
}
advanceTimeBy(300.milliseconds)
onNotifiableEventsReceived.assertions()
.isCalledOnce()
.with(
value(
listOf(
aFallbackNotifiableEvent(
description = "",
canBeReplaced = true,
noisy = false,
cause = "Unable to resolve event",
)
)
)
)
}
private suspend fun TestScope.runningProcessor(processor: NotificationResultProcessor, block: suspend NotificationResultProcessor.() -> Unit) {
processor.start()
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2026 Element Creations Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.push.impl.notifications
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.A_ROOM_ID
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.push.impl.notifications.fixtures.aFallbackNotifiableEvent
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
import org.junit.Test
class FallbackNotificationFactoryTest {
@Test
fun `create silent event`() {
val sut = FallbackNotificationFactory(FakeSystemClock())
val result = sut.create(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
eventId = AN_EVENT_ID,
cause = "A cause",
noisy = false,
)
assertThat(result).isEqualTo(
aFallbackNotifiableEvent(
description = "",
canBeReplaced = true,
noisy = false,
cause = "A cause",
)
)
}
@Test
fun `create noisy event`() {
val sut = FallbackNotificationFactory(FakeSystemClock())
val result = sut.create(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
eventId = AN_EVENT_ID,
cause = "A cause",
noisy = true,
)
assertThat(result).isEqualTo(
aFallbackNotifiableEvent(
description = "",
canBeReplaced = true,
noisy = true,
cause = "A cause",
)
)
}
}
@@ -18,6 +18,7 @@ import io.element.android.appconfig.NotificationConfig
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.features.enterprise.test.FakeEnterpriseService
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.test.AN_EVENT_ID
import io.element.android.libraries.matrix.test.AN_EVENT_ID_2
import io.element.android.libraries.matrix.test.A_COLOR_INT
@@ -33,6 +34,7 @@ import io.element.android.libraries.push.impl.notifications.DefaultNotificationB
import io.element.android.libraries.push.impl.notifications.NotificationActionIds
import io.element.android.libraries.push.impl.notifications.RoomEventGroupInfo
import io.element.android.libraries.push.impl.notifications.channels.DefaultNotificationChannels
import io.element.android.libraries.push.impl.notifications.channels.FakeNotificationChannels
import io.element.android.libraries.push.impl.notifications.channels.NotificationChannels
import io.element.android.libraries.push.impl.notifications.factories.action.AcceptInvitationActionFactory
import io.element.android.libraries.push.impl.notifications.factories.action.MarkAsReadActionFactory
@@ -47,6 +49,8 @@ import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvid
import io.element.android.services.toolbox.test.strings.FakeStringProvider
import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value
import io.element.android.tests.testutils.robolectric.RobolectricTest
import kotlinx.coroutines.test.runTest
import org.junit.Test
@@ -82,7 +86,10 @@ class DefaultNotificationCreatorTest : RobolectricTest() {
@Test
fun `test createFallbackNotification`() {
val sut = createNotificationCreator()
val channelIdForMessage = lambdaRecorder<SessionId, Boolean, String> { _, _ -> A_CHANNEL_ID }
val sut = createNotificationCreator(
notificationChannels = FakeNotificationChannels(channelIdForMessage = channelIdForMessage),
)
val result = sut.createFallbackNotification(
existingNotification = null,
notificationAccountParams = aNotificationAccountParams(),
@@ -93,6 +100,50 @@ class DefaultNotificationCreatorTest : RobolectricTest() {
result.commonAssertions(
expectedCategory = null,
)
assertThat(result.channelId).isEqualTo(A_CHANNEL_ID)
// The notification must be posted on the silent channel.
channelIdForMessage.assertions().isCalledOnce().with(value(A_SESSION_ID), value(false))
}
@Test
fun `test createFallbackNotification noisy`() {
val channelIdForMessage = lambdaRecorder<SessionId, Boolean, String> { _, _ -> A_CHANNEL_ID }
val sut = createNotificationCreator(
notificationChannels = FakeNotificationChannels(channelIdForMessage = channelIdForMessage),
)
val result = sut.createFallbackNotification(
existingNotification = null,
notificationAccountParams = aNotificationAccountParams(),
fallbackNotifiableEvents = listOf(
aFallbackNotifiableEvent(noisy = true),
)
)
result.commonAssertions(
expectedCategory = null,
)
assertThat(result.channelId).isEqualTo(A_CHANNEL_ID)
// The notification must be posted on the noisy channel.
channelIdForMessage.assertions().isCalledOnce().with(value(A_SESSION_ID), value(true))
}
@Test
fun `test createFallbackNotification is noisy when at least one event is noisy`() {
val channelIdForMessage = lambdaRecorder<SessionId, Boolean, String> { _, _ -> A_CHANNEL_ID }
val sut = createNotificationCreator(
notificationChannels = FakeNotificationChannels(channelIdForMessage = channelIdForMessage),
)
val result = sut.createFallbackNotification(
existingNotification = null,
notificationAccountParams = aNotificationAccountParams(),
fallbackNotifiableEvents = listOf(
aFallbackNotifiableEvent(noisy = false),
aFallbackNotifiableEvent(eventId = AN_EVENT_ID_2, noisy = true),
)
)
result.commonAssertions(
expectedCategory = null,
)
channelIdForMessage.assertions().isCalledOnce().with(value(A_SESSION_ID), value(true))
}
@Test
@@ -389,6 +440,8 @@ class DefaultNotificationCreatorTest : RobolectricTest() {
}
}
private const val A_CHANNEL_ID = "aChannelId"
const val MARK_AS_READ_ACTION_TITLE = "MarkAsReadAction"
const val QUICK_REPLY_ACTION_TITLE = "QuickReplyAction"
const val ACCEPT_INVITATION_ACTION_TITLE = "AcceptInvitationAction"
@@ -39,13 +39,14 @@ fun aSimpleNotifiableEvent(
type: String? = null,
isRedacted: Boolean = false,
canBeReplaced: Boolean = false,
editedEventId: EventId? = null
editedEventId: EventId? = null,
noisy: Boolean = false,
) = SimpleNotifiableEvent(
sessionId = sessionId,
roomId = roomId,
eventId = eventId,
editedEventId = editedEventId,
noisy = false,
noisy = noisy,
title = "title",
description = "description",
type = type,
@@ -59,14 +60,15 @@ fun anInviteNotifiableEvent(
sessionId: SessionId = A_SESSION_ID,
roomId: RoomId = A_ROOM_ID,
eventId: EventId = AN_EVENT_ID,
isRedacted: Boolean = false
isRedacted: Boolean = false,
noisy: Boolean = false,
) = InviteNotifiableEvent(
sessionId = sessionId,
eventId = eventId,
roomId = roomId,
roomName = A_ROOM_NAME,
editedEventId = null,
noisy = false,
noisy = noisy,
title = "title",
description = "description",
type = null,
@@ -89,11 +91,12 @@ fun aNotifiableMessageEvent(
senderId: UserId = A_USER_ID_2,
senderDisambiguatedDisplayName: String = A_USER_NAME_2,
roomName: String? = A_ROOM_NAME,
noisy: Boolean = false,
) = NotifiableMessageEvent(
sessionId = sessionId,
eventId = eventId,
editedEventId = null,
noisy = false,
noisy = noisy,
timestamp = timestamp,
senderDisambiguatedDisplayName = senderDisambiguatedDisplayName,
senderId = senderId,
@@ -149,15 +152,23 @@ fun aNotifiableCallEvent(
fun aFallbackNotifiableEvent(
sessionId: SessionId = A_SESSION_ID,
roomId: RoomId = A_ROOM_ID,
eventId: EventId = AN_EVENT_ID,
description: String? = "A fallback notification",
canBeReplaced: Boolean = false,
noisy: Boolean = false,
timestamp: Long = A_FAKE_TIMESTAMP,
cause: String? = "Unable to decrypt event",
) = FallbackNotifiableEvent(
sessionId = sessionId,
roomId = A_ROOM_ID,
eventId = AN_EVENT_ID,
roomId = roomId,
eventId = eventId,
editedEventId = null,
description = "A fallback notification",
canBeReplaced = false,
description = description,
canBeReplaced = canBeReplaced,
isRedacted = false,
isUpdated = false,
timestamp = A_FAKE_TIMESTAMP,
cause = "Unable to decrypt event",
noisy = noisy,
timestamp = timestamp,
cause = cause,
)