Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import io.element.android.libraries.matrix.api.media.isPreviewEnabled
import io.element.android.libraries.matrix.api.notification.NotificationContent
import io.element.android.libraries.matrix.api.notification.NotificationData
import io.element.android.libraries.matrix.api.permalink.PermalinkParser
import io.element.android.libraries.matrix.api.room.RoomMembershipState
import io.element.android.libraries.matrix.api.room.join.JoinRule
import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.EmoteMessageType
Expand Down Expand Up @@ -319,6 +320,29 @@ class DefaultNotifiableEventResolver(
Timber.tag(loggerTag.value).d("Ignoring notification for sticker")
throw NotificationResolverException.EventFilteredOut
}
is NotificationContent.StateEvent.RoomMemberContent -> {
// MSC4506: the homeserver pushes knocks to users who can act on them.
if (content.membershipState == RoomMembershipState.KNOCK) {
val notifiableMessageEvent = buildNotifiableMessageEvent(
sessionId = userId,
senderId = content.userId,
roomId = roomId,
eventId = eventId,
noisy = isNoisy,
timestamp = this.timestamp,
senderDisambiguatedDisplayName = getDisambiguatedDisplayName(content.userId),
body = stringProvider.getString(R.string.notification_knock_request_body),
roomName = roomDisplayName,
roomIsDm = isDm,
roomAvatarPath = roomAvatarUrl,
senderAvatarPath = senderAvatarUrl,
)
ResolvedPushEvent.Event(notifiableMessageEvent)
} else {
Timber.tag(loggerTag.value).d("Ignoring notification for membership ${content.membershipState}")
throw NotificationResolverException.EventFilteredOut
}
}
NotificationContent.MessageLike.Beacon -> {
Timber.tag(loggerTag.value).d("Ignoring notification for beacon")
throw NotificationResolverException.EventFilteredOut
Expand All @@ -341,7 +365,6 @@ class DefaultNotifiableEventResolver(
)
ResolvedPushEvent.Event(notifiableEventMessage)
}
is NotificationContent.StateEvent.RoomMemberContent,
NotificationContent.StateEvent.PolicyRuleRoom,
NotificationContent.StateEvent.PolicyRuleServer,
NotificationContent.StateEvent.PolicyRuleUser,
Expand Down
11 changes: 11 additions & 0 deletions libraries/push/impl/src/main/res/values/temporary.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ 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.
-->

<resources>
<!-- Body of the notification shown to users who can act on a knock (MSC4506 knock push rule). -->
<string name="notification_knock_request_body">"Requested to join"</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,28 @@ class DefaultNotifiableEventResolverTest : RobolectricTest() {
assertThat(result.getEvent(request)).isEqualTo(Result.success(expectedResult))
}

@Test
fun `resolve RoomMemberContent knock`() = runTest {
val sut = createDefaultNotifiableEventResolver(
notificationResult = Result.success(
mapOf(
AN_EVENT_ID to Result.success(aNotificationData(
content = NotificationContent.StateEvent.RoomMemberContent(
userId = A_USER_ID_2,
membershipState = RoomMembershipState.KNOCK
)
))
)
)
)
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(
aNotifiableMessageEvent(body = "Requested to join")
)
assertThat(result.getEvent(request)).isEqualTo(Result.success(expectedResult))
}

@Test
fun `resolve RoomMemberContent other`() = runTest {
val sut = createDefaultNotifiableEventResolver(
Expand Down
Loading