mirror of
https://github.com/Novaloop-AG/element-x-android.git
synced 2026-11-03 16:10:00 +00:00
Merge pull request #7360 from hayaksi1/fix/7253-skip-other-account-notifications
Do not notify about an event sent by another account on the same device
This commit is contained in:
+21
-1
@@ -56,6 +56,7 @@ import io.element.android.libraries.push.impl.db.PushRequest
|
|||||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent
|
import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent
|
||||||
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@@ -94,6 +95,7 @@ class DefaultNotifiableEventResolver(
|
|||||||
private val callNotificationEventResolver: CallNotificationEventResolver,
|
private val callNotificationEventResolver: CallNotificationEventResolver,
|
||||||
private val fallbackNotificationFactory: FallbackNotificationFactory,
|
private val fallbackNotificationFactory: FallbackNotificationFactory,
|
||||||
private val featureFlagService: FeatureFlagService,
|
private val featureFlagService: FeatureFlagService,
|
||||||
|
private val sessionStore: SessionStore,
|
||||||
) : NotifiableEventResolver {
|
) : NotifiableEventResolver {
|
||||||
override suspend fun resolveEvents(
|
override suspend fun resolveEvents(
|
||||||
sessionId: SessionId,
|
sessionId: SessionId,
|
||||||
@@ -117,10 +119,15 @@ class DefaultNotifiableEventResolver(
|
|||||||
return Result.failure(exception ?: NotificationResolverException.UnknownError("Unknown error while fetching notifications"))
|
return Result.failure(exception ?: NotificationResolverException.UnknownError("Unknown error while fetching notifications"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val otherSessionUserIds = sessionStore.getAllSessions()
|
||||||
|
.map { UserId(it.userId) }
|
||||||
|
.minus(sessionId)
|
||||||
|
.toSet()
|
||||||
|
|
||||||
// The null check is done above
|
// The null check is done above
|
||||||
val notificationDataMap = notificationsResult.getOrNull()!!.mapValues { (_, notificationData) ->
|
val notificationDataMap = notificationsResult.getOrNull()!!.mapValues { (_, notificationData) ->
|
||||||
notificationData.flatMap { data ->
|
notificationData.flatMap { data ->
|
||||||
data.asNotifiableEvent(client, sessionId)
|
data.asNotifiableEvent(client, sessionId, otherSessionUserIds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,10 +143,23 @@ class DefaultNotifiableEventResolver(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun NotificationContent.senderIdOrNull(): UserId? = when (this) {
|
||||||
|
is NotificationContent.MessageLike.RoomMessage -> senderId
|
||||||
|
is NotificationContent.MessageLike.Poll -> senderId
|
||||||
|
is NotificationContent.MessageLike.CallInvite -> senderId
|
||||||
|
is NotificationContent.MessageLike.RtcNotification -> senderId
|
||||||
|
is NotificationContent.Invite -> senderId
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun NotificationData.asNotifiableEvent(
|
private suspend fun NotificationData.asNotifiableEvent(
|
||||||
client: MatrixClient,
|
client: MatrixClient,
|
||||||
userId: SessionId,
|
userId: SessionId,
|
||||||
|
otherSessionUserIds: Set<UserId>,
|
||||||
): Result<ResolvedPushEvent> = runCatchingExceptions {
|
): Result<ResolvedPushEvent> = runCatchingExceptions {
|
||||||
|
if (content.senderIdOrNull() in otherSessionUserIds) {
|
||||||
|
throw NotificationResolverException.EventFilteredOut
|
||||||
|
}
|
||||||
when (val content = this.content) {
|
when (val content = this.content) {
|
||||||
is NotificationContent.MessageLike.RoomMessage -> {
|
is NotificationContent.MessageLike.RoomMessage -> {
|
||||||
val showMediaPreview = client.mediaPreviewService.getMediaPreviewValue().isPreviewEnabled(roomJoinRule)
|
val showMediaPreview = client.mediaPreviewService.getMediaPreviewValue().isPreviewEnabled(roomJoinRule)
|
||||||
|
|||||||
+111
@@ -39,6 +39,7 @@ import io.element.android.libraries.matrix.test.A_REDACTION_REASON
|
|||||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||||
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
import io.element.android.libraries.matrix.test.A_ROOM_NAME
|
||||||
import io.element.android.libraries.matrix.test.A_SESSION_ID
|
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_SPACE_NAME
|
import io.element.android.libraries.matrix.test.A_SPACE_NAME
|
||||||
import io.element.android.libraries.matrix.test.A_TIMESTAMP
|
import io.element.android.libraries.matrix.test.A_TIMESTAMP
|
||||||
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
import io.element.android.libraries.matrix.test.A_USER_ID_2
|
||||||
@@ -56,6 +57,9 @@ import io.element.android.libraries.push.impl.notifications.model.FallbackNotifi
|
|||||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
||||||
import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent
|
import io.element.android.libraries.push.impl.notifications.model.ResolvedPushEvent
|
||||||
|
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||||
|
import io.element.android.libraries.sessionstorage.test.InMemorySessionStore
|
||||||
|
import io.element.android.libraries.sessionstorage.test.aSessionData
|
||||||
import io.element.android.services.toolbox.impl.strings.AndroidStringProvider
|
import io.element.android.services.toolbox.impl.strings.AndroidStringProvider
|
||||||
import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
|
import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP
|
||||||
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
|
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
|
||||||
@@ -836,6 +840,111 @@ class DefaultNotifiableEventResolverTest : RobolectricTest() {
|
|||||||
assertThat(result.getEvent(request)?.getOrNull()).isNull()
|
assertThat(result.getEvent(request)?.getOrNull()).isNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `resolve RoomMessage sent by another session on the same device is filtered out`() = runTest {
|
||||||
|
val sut = createDefaultNotifiableEventResolver(
|
||||||
|
notificationResult = Result.success(
|
||||||
|
mapOf(
|
||||||
|
AN_EVENT_ID to Result.success(
|
||||||
|
aNotificationData(
|
||||||
|
content = NotificationContent.MessageLike.RoomMessage(
|
||||||
|
senderId = A_SESSION_ID_2,
|
||||||
|
messageType = TextMessageType("Hello world", null),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
sessionStore = InMemorySessionStore(
|
||||||
|
listOf(
|
||||||
|
aSessionData(sessionId = A_SESSION_ID.value),
|
||||||
|
aSessionData(sessionId = A_SESSION_ID_2.value),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase")
|
||||||
|
val result = sut.resolveEvents(A_SESSION_ID, listOf(request))
|
||||||
|
assertThat(result.getEvent(request)?.exceptionOrNull()).isEqualTo(NotificationResolverException.EventFilteredOut)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `resolve RtcNotification sent by another session on the same device is filtered out`() = runTest {
|
||||||
|
val sut = createDefaultNotifiableEventResolver(
|
||||||
|
notificationResult = Result.success(
|
||||||
|
mapOf(
|
||||||
|
AN_EVENT_ID to Result.success(
|
||||||
|
aNotificationData(
|
||||||
|
content = NotificationContent.MessageLike.RtcNotification(
|
||||||
|
senderId = A_SESSION_ID_2,
|
||||||
|
type = RtcNotificationType.RING,
|
||||||
|
callIntent = CallIntent.AUDIO,
|
||||||
|
expirationTimestampMillis = 0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
sessionStore = InMemorySessionStore(
|
||||||
|
listOf(
|
||||||
|
aSessionData(sessionId = A_SESSION_ID.value),
|
||||||
|
aSessionData(sessionId = A_SESSION_ID_2.value),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase")
|
||||||
|
val result = sut.resolveEvents(A_SESSION_ID, listOf(request))
|
||||||
|
assertThat(result.getEvent(request)?.exceptionOrNull()).isEqualTo(NotificationResolverException.EventFilteredOut)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `resolve RoomMessage sent by a user who is not logged in is not filtered out`() = runTest {
|
||||||
|
val sut = createDefaultNotifiableEventResolver(
|
||||||
|
notificationResult = Result.success(
|
||||||
|
mapOf(
|
||||||
|
AN_EVENT_ID to Result.success(
|
||||||
|
aNotificationData(
|
||||||
|
content = NotificationContent.MessageLike.RoomMessage(
|
||||||
|
senderId = A_SESSION_ID_2,
|
||||||
|
messageType = TextMessageType("Hello world", null),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
sessionStore = InMemorySessionStore(listOf(aSessionData(sessionId = A_SESSION_ID.value))),
|
||||||
|
)
|
||||||
|
val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase")
|
||||||
|
val result = sut.resolveEvents(A_SESSION_ID, listOf(request))
|
||||||
|
assertThat(result.getEvent(request)?.isSuccess).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `resolve RoomMessage sent by the receiving session itself is not filtered out`() = runTest {
|
||||||
|
val sut = createDefaultNotifiableEventResolver(
|
||||||
|
notificationResult = Result.success(
|
||||||
|
mapOf(
|
||||||
|
AN_EVENT_ID to Result.success(
|
||||||
|
aNotificationData(
|
||||||
|
content = NotificationContent.MessageLike.RoomMessage(
|
||||||
|
senderId = A_SESSION_ID,
|
||||||
|
messageType = TextMessageType("Hello world", null),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
sessionStore = InMemorySessionStore(
|
||||||
|
listOf(
|
||||||
|
aSessionData(sessionId = A_SESSION_ID.value),
|
||||||
|
aSessionData(sessionId = A_SESSION_ID_2.value),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val request = aPushRequest(A_SESSION_ID, A_ROOM_ID, AN_EVENT_ID, "firebase")
|
||||||
|
val result = sut.resolveEvents(A_SESSION_ID, listOf(request))
|
||||||
|
assertThat(result.getEvent(request)?.isSuccess).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `resolve null cases`() {
|
fun `resolve null cases`() {
|
||||||
testNoResults(NotificationContent.MessageLike.CallAnswer)
|
testNoResults(NotificationContent.MessageLike.CallAnswer)
|
||||||
@@ -893,6 +1002,7 @@ class DefaultNotifiableEventResolverTest : RobolectricTest() {
|
|||||||
notificationService: FakeNotificationService? = FakeNotificationService(),
|
notificationService: FakeNotificationService? = FakeNotificationService(),
|
||||||
notificationResult: Result<Map<EventId, Result<NotificationData>>> = Result.success(emptyMap()),
|
notificationResult: Result<Map<EventId, Result<NotificationData>>> = Result.success(emptyMap()),
|
||||||
callNotificationEventResolver: FakeCallNotificationEventResolver = FakeCallNotificationEventResolver(),
|
callNotificationEventResolver: FakeCallNotificationEventResolver = FakeCallNotificationEventResolver(),
|
||||||
|
sessionStore: SessionStore = InMemorySessionStore(),
|
||||||
): DefaultNotifiableEventResolver {
|
): DefaultNotifiableEventResolver {
|
||||||
val context = RuntimeEnvironment.getApplication() as Context
|
val context = RuntimeEnvironment.getApplication() as Context
|
||||||
notificationService?.givenGetNotificationsResult(notificationResult)
|
notificationService?.givenGetNotificationsResult(notificationResult)
|
||||||
@@ -917,6 +1027,7 @@ class DefaultNotifiableEventResolverTest : RobolectricTest() {
|
|||||||
clock = FakeSystemClock(),
|
clock = FakeSystemClock(),
|
||||||
),
|
),
|
||||||
featureFlagService = FakeFeatureFlagService(),
|
featureFlagService = FakeFeatureFlagService(),
|
||||||
|
sessionStore = sessionStore,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user