Support incoming audio only calls
This commit is contained in:
@@ -58,6 +58,7 @@ class DefaultElementCallEntryPoint(
|
||||
expirationTimestamp = expirationTimestamp,
|
||||
notificationChannelId = notificationChannelId,
|
||||
textContent = textContent,
|
||||
audioOnly = callType.voiceIntent
|
||||
)
|
||||
activeCallManager.registerIncomingCall(notificationData = incomingCallNotificationData)
|
||||
}
|
||||
|
||||
@@ -29,4 +29,5 @@ data class CallNotificationData(
|
||||
val textContent: String?,
|
||||
// Expiration timestamp in millis since epoch
|
||||
val expirationTimestamp: Long,
|
||||
val audioOnly: Boolean,
|
||||
) : Parcelable
|
||||
|
||||
@@ -69,6 +69,7 @@ class RingingCallNotificationCreator(
|
||||
timestamp: Long,
|
||||
expirationTimestamp: Long,
|
||||
textContent: String?,
|
||||
audioOnly: Boolean,
|
||||
): Notification? {
|
||||
val matrixClient = matrixClientProvider.getOrRestore(sessionId).getOrNull() ?: return null
|
||||
val imageLoader = imageLoaderHolder.get(matrixClient)
|
||||
@@ -88,8 +89,7 @@ class RingingCallNotificationCreator(
|
||||
.setImportant(true)
|
||||
.build()
|
||||
|
||||
// TODO
|
||||
val answerIntent = IntentProvider.getPendingIntent(context, CallType.RoomCall(sessionId, roomId, voiceIntent = false))
|
||||
val answerIntent = IntentProvider.getPendingIntent(context, CallType.RoomCall(sessionId, roomId, voiceIntent = audioOnly))
|
||||
val notificationData = CallNotificationData(
|
||||
sessionId = sessionId,
|
||||
roomId = roomId,
|
||||
@@ -102,6 +102,7 @@ class RingingCallNotificationCreator(
|
||||
timestamp = timestamp,
|
||||
textContent = textContent,
|
||||
expirationTimestamp = expirationTimestamp,
|
||||
audioOnly = audioOnly,
|
||||
)
|
||||
|
||||
val declineIntent = PendingIntentCompat.getBroadcast(
|
||||
@@ -128,7 +129,11 @@ class RingingCallNotificationCreator(
|
||||
.setSmallIcon(CommonDrawables.ic_notification)
|
||||
.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||
.setCategory(NotificationCompat.CATEGORY_CALL)
|
||||
.setStyle(NotificationCompat.CallStyle.forIncomingCall(caller, declineIntent, answerIntent).setIsVideo(true))
|
||||
.setStyle(
|
||||
NotificationCompat.CallStyle
|
||||
.forIncomingCall(caller, declineIntent, answerIntent)
|
||||
.setIsVideo(!audioOnly)
|
||||
)
|
||||
.addPerson(caller)
|
||||
.setAutoCancel(true)
|
||||
.setWhen(timestamp)
|
||||
|
||||
@@ -45,8 +45,7 @@ class DeclineCallBroadcastReceiver : BroadcastReceiver() {
|
||||
callType = CallType.RoomCall(
|
||||
sessionId = notificationData.sessionId,
|
||||
roomId = notificationData.roomId,
|
||||
// TODO
|
||||
voiceIntent = false
|
||||
voiceIntent = notificationData.audioOnly
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -116,8 +116,7 @@ class IncomingCallActivity : AppCompatActivity() {
|
||||
CallType.RoomCall(
|
||||
notificationData.sessionId,
|
||||
notificationData.roomId,
|
||||
// TODO
|
||||
voiceIntent = false
|
||||
voiceIntent = notificationData.audioOnly
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
@@ -45,10 +46,6 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
/**
|
||||
@@ -103,7 +100,7 @@ internal fun IncomingCallScreen(
|
||||
ActionButton(
|
||||
size = 64.dp,
|
||||
onClick = { onAnswer(notificationData) },
|
||||
icon = CompoundIcons.VoiceCallSolid(),
|
||||
icon = if (notificationData.audioOnly) CompoundIcons.VoiceCallSolid() else CompoundIcons.VideoCallSolid(),
|
||||
title = stringResource(CommonStrings.action_accept),
|
||||
backgroundColor = ElementTheme.colors.iconSuccessPrimary,
|
||||
borderColor = ElementTheme.colors.borderSuccessSubtle
|
||||
@@ -163,21 +160,11 @@ private fun ActionButton(
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun IncomingCallScreenPreview() = ElementPreview {
|
||||
internal fun IncomingCallScreenPreview(
|
||||
@PreviewParameter(IncomingCallScreenProvider::class) state: CallNotificationData,
|
||||
) = ElementPreview {
|
||||
IncomingCallScreen(
|
||||
notificationData = CallNotificationData(
|
||||
sessionId = SessionId("@alice:matrix.org"),
|
||||
roomId = RoomId("!1234:matrix.org"),
|
||||
eventId = EventId("\$asdadadsad:matrix.org"),
|
||||
senderId = UserId("@bob:matrix.org"),
|
||||
roomName = "A room",
|
||||
senderName = "Bob",
|
||||
avatarUrl = null,
|
||||
notificationChannelId = "incoming_call",
|
||||
timestamp = 0L,
|
||||
textContent = null,
|
||||
expirationTimestamp = 1000L,
|
||||
),
|
||||
notificationData = state,
|
||||
onAnswer = {},
|
||||
onCancel = {},
|
||||
)
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.features.call.impl.ui
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.features.call.impl.notifications.CallNotificationData
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
|
||||
open class IncomingCallScreenProvider : PreviewParameterProvider<CallNotificationData> {
|
||||
override val values: Sequence<CallNotificationData>
|
||||
get() = sequenceOf(
|
||||
aIncomingCallScreenState(
|
||||
audioOnly = false
|
||||
),
|
||||
aIncomingCallScreenState(
|
||||
audioOnly = true
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun aIncomingCallScreenState(
|
||||
audioOnly: Boolean
|
||||
): CallNotificationData {
|
||||
return CallNotificationData(
|
||||
sessionId = SessionId("@alice:matrix.org"),
|
||||
roomId = RoomId("!1234:matrix.org"),
|
||||
eventId = EventId("\$asdadadsad:matrix.org"),
|
||||
senderId = UserId("@bob:matrix.org"),
|
||||
roomName = "A room",
|
||||
senderName = "Bob",
|
||||
avatarUrl = null,
|
||||
notificationChannelId = "incoming_call",
|
||||
timestamp = 0L,
|
||||
textContent = null,
|
||||
expirationTimestamp = 1000L,
|
||||
audioOnly = audioOnly
|
||||
)
|
||||
}
|
||||
@@ -147,7 +147,7 @@ class DefaultActiveCallManager(
|
||||
sessionId = notificationData.sessionId,
|
||||
roomId = notificationData.roomId,
|
||||
// TODO
|
||||
voiceIntent = false,
|
||||
voiceIntent = notificationData.audioOnly,
|
||||
),
|
||||
callState = CallState.Ringing(notificationData),
|
||||
)
|
||||
@@ -275,6 +275,7 @@ class DefaultActiveCallManager(
|
||||
timestamp = notificationData.timestamp,
|
||||
textContent = notificationData.textContent,
|
||||
expirationTimestamp = notificationData.expirationTimestamp,
|
||||
audioOnly = notificationData.audioOnly,
|
||||
) ?: return
|
||||
runCatchingExceptions {
|
||||
notificationManagerCompat.notify(
|
||||
|
||||
Reference in New Issue
Block a user