Skip to content

Commit ea170fc

Browse files
authored
Merge pull request #8941 from element-hq/feature/bma/elementCall
Element call incoming call
2 parents 7051c0c + 12adddb commit ea170fc

File tree

15 files changed

+319
-7
lines changed

15 files changed

+319
-7
lines changed

changelog.d/8938.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Indicate when calls are unsupported in the timeline/notifications

library/ui-strings/src/main/res/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2939,6 +2939,9 @@
29392939

29402940
<string name="call_slide_to_end_conference">Slide to end the call</string>
29412941

2942+
<string name="call_unsupported">Unsupported call</string>
2943+
<string name="call_unsupported_matrix_rtc_call">Unsupported call. The new Element X app is needed to join this call.</string>
2944+
29422945
<string name="re_authentication_activity_title">Re-Authentication Needed</string>
29432946
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->
29442947
<string name="re_authentication_default_confirm_text">${app_name} requires you to enter your credentials to perform this action.</string>

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/Event.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,11 @@ fun Event.getPollContent(): MessagePollContent? {
499499
}
500500

501501
fun Event.supportsNotification() =
502-
this.getClearType() in EventType.MESSAGE + EventType.POLL_START.values + EventType.POLL_END.values + EventType.STATE_ROOM_BEACON_INFO.values
502+
this.getClearType() in EventType.MESSAGE +
503+
EventType.POLL_START.values +
504+
EventType.POLL_END.values +
505+
EventType.STATE_ROOM_BEACON_INFO.values +
506+
EventType.ELEMENT_CALL_NOTIFY.values
503507

504508
fun Event.isContentReportable() =
505509
this.getClearType() in EventType.MESSAGE + EventType.STATE_ROOM_BEACON_INFO.values

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/events/model/EventType.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ object EventType {
8787
// This type is not processed by the client, just sent to the server
8888
const val CALL_REPLACES = "m.call.replaces"
8989

90+
// Element Call
91+
val ELEMENT_CALL_NOTIFY = StableUnstableId(stable = "m.call.notify", unstable = "org.matrix.msc4075.call.notify")
92+
9093
// Key share events
9194
const val ROOM_KEY_REQUEST = "m.room_key_request"
9295
const val FORWARDED_ROOM_KEY = "m.forwarded_room_key"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2024 The Matrix.org Foundation C.I.C.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.matrix.android.sdk.api.session.room.model.message
18+
19+
import com.squareup.moshi.Json
20+
import com.squareup.moshi.JsonClass
21+
22+
@JsonClass(generateAdapter = true)
23+
data class ElementCallNotifyContent(
24+
@Json(name = "application") val application: String? = null,
25+
@Json(name = "call_id") val callId: String? = null,
26+
@Json(name = "m.mentions") val mentions: Mentions? = null,
27+
@Json(name = "notify_type") val notifyType: String? = null,
28+
)
29+
30+
@JsonClass(generateAdapter = true)
31+
data class Mentions(
32+
@Json(name = "room") val room: Boolean? = null,
33+
@Json(name = "user_ids") val userIds: List<String>? = null,
34+
)
35+
36+
fun ElementCallNotifyContent.isUserMentioned(userId: String): Boolean {
37+
return mentions?.room == true ||
38+
mentions?.userIds?.contains(userId) == true
39+
}

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/pushrules/ProcessEventForPushTask.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ internal class DefaultProcessEventForPushTask @Inject constructor(
6161
in EventType.POLL_START.values,
6262
in EventType.POLL_END.values,
6363
in EventType.STATE_ROOM_BEACON_INFO.values,
64+
in EventType.ELEMENT_CALL_NOTIFY.values,
6465
EventType.MESSAGE,
6566
EventType.REDACTION,
6667
EventType.ENCRYPTED,

vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,9 @@ class MessageActionsViewModel @AssistedInject constructor(
214214
in EventType.POLL_END.values -> {
215215
stringProvider.getString(CommonStrings.message_reply_to_ended_poll_preview)
216216
}
217+
in EventType.ELEMENT_CALL_NOTIFY.values -> {
218+
stringProvider.getString(CommonStrings.call_unsupported)
219+
}
217220
else -> null
218221
}
219222
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2024 New Vector Ltd.
3+
*
4+
* SPDX-License-Identifier: AGPL-3.0-only
5+
* Please see LICENSE in the repository root for full details.
6+
*/
7+
package im.vector.app.features.home.room.detail.timeline.factory
8+
9+
import im.vector.app.core.epoxy.VectorEpoxyModel
10+
import im.vector.app.core.resources.UserPreferencesProvider
11+
import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
12+
import im.vector.app.features.home.room.detail.timeline.TimelineEventController
13+
import im.vector.app.features.home.room.detail.timeline.helper.AvatarSizeProvider
14+
import im.vector.app.features.home.room.detail.timeline.helper.MessageInformationDataFactory
15+
import im.vector.app.features.home.room.detail.timeline.helper.MessageItemAttributesFactory
16+
import im.vector.app.features.home.room.detail.timeline.item.ElementCallTileTimelineItem
17+
import im.vector.app.features.home.room.detail.timeline.item.ElementCallTileTimelineItem_
18+
import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
19+
import im.vector.app.features.home.room.detail.timeline.item.ReactionsSummaryEvents
20+
import org.matrix.android.sdk.api.session.Session
21+
import org.matrix.android.sdk.api.session.events.model.EventType
22+
import org.matrix.android.sdk.api.session.events.model.toModel
23+
import org.matrix.android.sdk.api.session.room.model.RoomSummary
24+
import org.matrix.android.sdk.api.session.room.model.message.ElementCallNotifyContent
25+
import org.matrix.android.sdk.api.util.toMatrixItem
26+
import javax.inject.Inject
27+
28+
class ElementCallItemFactory @Inject constructor(
29+
private val session: Session,
30+
private val userPreferencesProvider: UserPreferencesProvider,
31+
private val messageColorProvider: MessageColorProvider,
32+
private val messageInformationDataFactory: MessageInformationDataFactory,
33+
private val messageItemAttributesFactory: MessageItemAttributesFactory,
34+
private val avatarSizeProvider: AvatarSizeProvider,
35+
private val noticeItemFactory: NoticeItemFactory
36+
) {
37+
38+
fun create(params: TimelineItemFactoryParams): VectorEpoxyModel<*>? {
39+
val event = params.event
40+
if (event.root.eventId == null) return null
41+
val showHiddenEvents = userPreferencesProvider.shouldShowHiddenEvents()
42+
val roomSummary = params.partialState.roomSummary ?: return null
43+
val informationData = messageInformationDataFactory.create(params)
44+
val callItem = when (event.root.getClearType()) {
45+
in EventType.ELEMENT_CALL_NOTIFY.values -> {
46+
val notifyContent: ElementCallNotifyContent = event.root.content.toModel() ?: return null
47+
createElementCallTileTimelineItem(
48+
roomSummary = roomSummary,
49+
callId = notifyContent.callId.orEmpty(),
50+
callStatus = ElementCallTileTimelineItem.CallStatus.INVITED,
51+
callKind = ElementCallTileTimelineItem.CallKind.VIDEO,
52+
callback = params.callback,
53+
highlight = params.isHighlighted,
54+
informationData = informationData,
55+
reactionsSummaryEvents = params.reactionsSummaryEvents
56+
)
57+
}
58+
else -> null
59+
}
60+
return if (callItem == null && showHiddenEvents) {
61+
// Fallback to notice item for showing hidden events
62+
noticeItemFactory.create(params)
63+
} else {
64+
callItem
65+
}
66+
}
67+
68+
private fun createElementCallTileTimelineItem(
69+
roomSummary: RoomSummary,
70+
callId: String,
71+
callKind: ElementCallTileTimelineItem.CallKind,
72+
callStatus: ElementCallTileTimelineItem.CallStatus,
73+
informationData: MessageInformationData,
74+
highlight: Boolean,
75+
callback: TimelineEventController.Callback?,
76+
reactionsSummaryEvents: ReactionsSummaryEvents?
77+
): ElementCallTileTimelineItem? {
78+
val userOfInterest = roomSummary.toMatrixItem()
79+
val attributes = messageItemAttributesFactory.create(null, informationData, callback, reactionsSummaryEvents).let {
80+
ElementCallTileTimelineItem.Attributes(
81+
callId = callId,
82+
callKind = callKind,
83+
callStatus = callStatus,
84+
informationData = informationData,
85+
avatarRenderer = it.avatarRenderer,
86+
messageColorProvider = messageColorProvider,
87+
itemClickListener = it.itemClickListener,
88+
itemLongClickListener = it.itemLongClickListener,
89+
reactionPillCallback = it.reactionPillCallback,
90+
readReceiptsCallback = it.readReceiptsCallback,
91+
userOfInterest = userOfInterest,
92+
callback = callback,
93+
reactionsSummaryEvents = reactionsSummaryEvents
94+
)
95+
}
96+
return ElementCallTileTimelineItem_()
97+
.attributes(attributes)
98+
.highlighted(highlight)
99+
.leftGuideline(avatarSizeProvider.leftGuideline)
100+
}
101+
}

vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineItemFactory.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class TimelineItemFactory @Inject constructor(
3232
private val widgetItemFactory: WidgetItemFactory,
3333
private val verificationConclusionItemFactory: VerificationItemFactory,
3434
private val callItemFactory: CallItemFactory,
35+
private val elementCallItemFactory: ElementCallItemFactory,
3536
private val decryptionFailureTracker: DecryptionFailureTracker,
3637
private val timelineEventVisibilityHelper: TimelineEventVisibilityHelper,
3738
private val session: Session,
@@ -119,6 +120,8 @@ class TimelineItemFactory @Inject constructor(
119120
noticeItemFactory.create(params)
120121
}
121122
}
123+
// Element Call
124+
in EventType.ELEMENT_CALL_NOTIFY.values -> elementCallItemFactory.create(params)
122125
// Calls
123126
EventType.CALL_INVITE,
124127
EventType.CALL_HANGUP,

vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ class DisplayableEventFormatter @Inject constructor(
142142
in EventType.STATE_ROOM_BEACON_INFO.values -> {
143143
simpleFormat(senderName, stringProvider.getString(CommonStrings.sent_live_location), appendAuthor)
144144
}
145+
in EventType.ELEMENT_CALL_NOTIFY.values -> {
146+
simpleFormat(senderName, stringProvider.getString(CommonStrings.call_unsupported), appendAuthor)
147+
}
145148
VoiceBroadcastConstants.STATE_ROOM_VOICE_BROADCAST_INFO -> {
146149
formatVoiceBroadcastEvent(timelineEvent.root, isDm, senderName)
147150
}
@@ -243,6 +246,9 @@ class DisplayableEventFormatter @Inject constructor(
243246
in EventType.STATE_ROOM_BEACON_INFO.values -> {
244247
stringProvider.getString(CommonStrings.sent_live_location)
245248
}
249+
in EventType.ELEMENT_CALL_NOTIFY.values -> {
250+
stringProvider.getString(CommonStrings.call_unsupported)
251+
}
246252
else -> {
247253
span {
248254
}

0 commit comments

Comments
 (0)