diff --git a/features/call/api/src/main/kotlin/io/element/android/features/call/api/CallType.kt b/features/call/api/src/main/kotlin/io/element/android/features/call/api/CallData.kt
similarity index 50%
rename from features/call/api/src/main/kotlin/io/element/android/features/call/api/CallType.kt
rename to features/call/api/src/main/kotlin/io/element/android/features/call/api/CallData.kt
index 4b09813418..c1dcf573c6 100644
--- a/features/call/api/src/main/kotlin/io/element/android/features/call/api/CallType.kt
+++ b/features/call/api/src/main/kotlin/io/element/android/features/call/api/CallData.kt
@@ -14,22 +14,9 @@ import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.core.SessionId
import kotlinx.parcelize.Parcelize
-sealed interface CallType : NodeInputs, Parcelable {
- @Parcelize
- data class ExternalUrl(val url: String) : CallType {
- override fun toString(): String {
- return "ExternalUrl"
- }
- }
-
- @Parcelize
- data class RoomCall(
- val sessionId: SessionId,
- val roomId: RoomId,
- val isAudioCall: Boolean
- ) : CallType {
- override fun toString(): String {
- return "RoomCall(sessionId=$sessionId, roomId=$roomId, isAudioCall=$isAudioCall)"
- }
- }
-}
+@Parcelize
+data class CallData(
+ val sessionId: SessionId,
+ val roomId: RoomId,
+ val isAudioCall: Boolean
+) : NodeInputs, Parcelable
diff --git a/features/call/api/src/main/kotlin/io/element/android/features/call/api/ElementCallEntryPoint.kt b/features/call/api/src/main/kotlin/io/element/android/features/call/api/ElementCallEntryPoint.kt
index caa557f4de..2976635ee2 100644
--- a/features/call/api/src/main/kotlin/io/element/android/features/call/api/ElementCallEntryPoint.kt
+++ b/features/call/api/src/main/kotlin/io/element/android/features/call/api/ElementCallEntryPoint.kt
@@ -17,13 +17,13 @@ import io.element.android.libraries.matrix.api.core.UserId
interface ElementCallEntryPoint {
/**
* Start a call of the given type.
- * @param callType The type of call to start.
+ * @param callData The data of call to start.
*/
- fun startCall(callType: CallType)
+ fun startCall(callData: CallData)
/**
* Handle an incoming call.
- * @param callType The type of call.
+ * @param callData The data of call.
* @param eventId The event id of the event that started the call.
* @param senderId The user id of the sender of the event that started the call.
* @param roomName The name of the room the call is in.
@@ -35,7 +35,7 @@ interface ElementCallEntryPoint {
* @param textContent The text content of the notification. If null the default content from the system will be used.
*/
suspend fun handleIncomingCall(
- callType: CallType.RoomCall,
+ callData: CallData,
eventId: EventId,
senderId: UserId,
roomName: String?,
diff --git a/features/call/impl/src/main/AndroidManifest.xml b/features/call/impl/src/main/AndroidManifest.xml
index daf1a910c9..c35c6843ff 100644
--- a/features/call/impl/src/main/AndroidManifest.xml
+++ b/features/call/impl/src/main/AndroidManifest.xml
@@ -30,44 +30,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:taskAffinity="io.element.android.features.call" />
().inject(this)
appCoroutineScope.launch {
activeCallManager.hangUpCall(
- callType = CallType.RoomCall(
+ callData = CallData(
sessionId = notificationData.sessionId,
roomId = notificationData.roomId,
isAudioCall = notificationData.audioOnly
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt
index da2c57c0ac..b9bd6640b4 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenPresenter.kt
@@ -23,7 +23,7 @@ import dev.zacsweers.metro.AssistedFactory
import dev.zacsweers.metro.AssistedInject
import im.vector.app.features.analytics.plan.MobileScreen
import io.element.android.compound.theme.ElementTheme
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.impl.data.WidgetMessage
import io.element.android.features.call.impl.utils.ActiveCallManager
import io.element.android.features.call.impl.utils.CallWidgetProvider
@@ -52,7 +52,7 @@ import kotlin.time.Duration.Companion.seconds
@AssistedInject
class CallScreenPresenter(
- @Assisted private val callType: CallType,
+ @Assisted private val callData: CallData,
@Assisted private val navigator: CallScreenNavigator,
private val callWidgetProvider: CallWidgetProvider,
userAgentProvider: UserAgentProvider,
@@ -69,10 +69,9 @@ class CallScreenPresenter(
) : Presenter {
@AssistedFactory
interface Factory {
- fun create(callType: CallType, navigator: CallScreenNavigator): CallScreenPresenter
+ fun create(callData: CallData, navigator: CallScreenNavigator): CallScreenPresenter
}
- private val isInWidgetMode = callType is CallType.RoomCall
private val userAgent = userAgentProvider.provide()
@Composable
@@ -90,9 +89,9 @@ class CallScreenPresenter(
DisposableEffect(Unit) {
coroutineScope.launch {
// Sets the call as joined
- activeCallManager.joinedCall(callType)
+ activeCallManager.joinedCall(callData)
fetchRoomCallUrl(
- inputs = callType,
+ callData = callData,
urlState = urlState,
callWidgetDriver = callWidgetDriver,
languageTag = languageTag,
@@ -100,19 +99,10 @@ class CallScreenPresenter(
)
}
onDispose {
- appCoroutineScope.launch { activeCallManager.hangUpCall(callType) }
+ appCoroutineScope.launch { activeCallManager.hangUpCall(callData) }
}
}
-
- when (callType) {
- is CallType.ExternalUrl -> {
- // No analytics yet for external calls
- }
- is CallType.RoomCall -> {
- screenTracker.TrackScreen(screen = MobileScreen.ScreenName.RoomCall)
- }
- }
-
+ screenTracker.TrackScreen(screen = MobileScreen.ScreenName.RoomCall)
HandleMatrixClientSyncState()
callWidgetDriver.value?.let { driver ->
@@ -149,18 +139,15 @@ class CallScreenPresenter(
.launchIn(this)
}
- if (callType is CallType.RoomCall) {
- // Note: For external calls isWidgetLoaded will always be false
- LaunchedEffect(Unit) {
- // Wait for the call to be joined, if it takes too long, we display an error
- delay(10.seconds)
+ LaunchedEffect(Unit) {
+ // Wait for the call to be joined, if it takes too long, we display an error
+ delay(10.seconds)
- if (!isWidgetLoaded) {
- Timber.w("The call took too long to load. Displaying an error before exiting.")
+ if (!isWidgetLoaded) {
+ Timber.w("The call took too long to load. Displaying an error before exiting.")
- // This will display a simple 'Sorry, an error occurred' dialog and force the user to exit the call
- webViewError = ""
- }
+ // This will display a simple 'Sorry, an error occurred' dialog and force the user to exit the call
+ webViewError = ""
}
}
}
@@ -204,37 +191,29 @@ class CallScreenPresenter(
webViewError = webViewError,
userAgent = userAgent,
isCallActive = isWidgetLoaded,
- isInWidgetMode = isInWidgetMode,
eventSink = ::handleEvent,
)
}
private suspend fun fetchRoomCallUrl(
- inputs: CallType,
+ callData: CallData,
urlState: MutableState>,
callWidgetDriver: MutableState,
languageTag: String?,
theme: String?,
) {
urlState.runCatchingUpdatingState {
- when (inputs) {
- is CallType.ExternalUrl -> {
- inputs.url
- }
- is CallType.RoomCall -> {
- val result = callWidgetProvider.getWidget(
- sessionId = inputs.sessionId,
- roomId = inputs.roomId,
- clientId = UUID.randomUUID().toString(),
- isAudioCall = inputs.isAudioCall,
- languageTag = languageTag,
- theme = theme,
- ).getOrThrow()
- callWidgetDriver.value = result.driver
- Timber.d("Call widget driver initialized for sessionId: ${inputs.sessionId}, roomId: ${inputs.roomId}")
- result.url
- }
- }
+ val result = callWidgetProvider.getWidget(
+ sessionId = callData.sessionId,
+ roomId = callData.roomId,
+ clientId = UUID.randomUUID().toString(),
+ isAudioCall = callData.isAudioCall,
+ languageTag = languageTag,
+ theme = theme,
+ ).getOrThrow()
+ callWidgetDriver.value = result.driver
+ Timber.d("Call widget driver initialized for sessionId: ${callData.sessionId}, roomId: ${callData.roomId}")
+ result.url
}
}
@@ -242,12 +221,11 @@ class CallScreenPresenter(
private fun HandleMatrixClientSyncState() {
val coroutineScope = rememberCoroutineScope()
DisposableEffect(Unit) {
- val roomCallType = callType as? CallType.RoomCall ?: return@DisposableEffect onDispose {}
- val client = matrixClientsProvider.getOrNull(roomCallType.sessionId) ?: return@DisposableEffect onDispose {
- Timber.w("No MatrixClient found for sessionId, can't send call notification: ${roomCallType.sessionId}")
+ val client = matrixClientsProvider.getOrNull(callData.sessionId) ?: return@DisposableEffect onDispose {
+ Timber.w("No MatrixClient found for sessionId, can't send call notification: ${callData.sessionId}")
}
coroutineScope.launch {
- Timber.d("Observing sync state in-call for sessionId: ${roomCallType.sessionId}")
+ Timber.d("Observing sync state in-call for sessionId: ${callData.sessionId}")
client.syncService.syncState
.collect { state ->
if (state != SyncState.Running) {
@@ -256,7 +234,7 @@ class CallScreenPresenter(
}
}
onDispose {
- Timber.d("Stopped observing sync state in-call for sessionId: ${roomCallType.sessionId}")
+ Timber.d("Stopped observing sync state in-call for sessionId: ${callData.sessionId}")
// Make sure we mark the call as ended in the app state
appForegroundStateService.updateIsInCallState(false)
}
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenState.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenState.kt
index c07594aebb..3608a2b620 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenState.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenState.kt
@@ -15,6 +15,5 @@ data class CallScreenState(
val webViewError: String?,
val userAgent: String,
val isCallActive: Boolean,
- val isInWidgetMode: Boolean,
val eventSink: (CallScreenEvents) -> Unit,
)
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenStateProvider.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenStateProvider.kt
index 3e72f96f87..036bb6103a 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenStateProvider.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallScreenStateProvider.kt
@@ -26,7 +26,6 @@ internal fun aCallScreenState(
webViewError: String? = null,
userAgent: String = "",
isCallActive: Boolean = true,
- isInWidgetMode: Boolean = false,
eventSink: (CallScreenEvents) -> Unit = {},
): CallScreenState {
return CallScreenState(
@@ -34,7 +33,6 @@ internal fun aCallScreenState(
webViewError = webViewError,
userAgent = userAgent,
isCallActive = isCallActive,
- isInWidgetMode = isInWidgetMode,
eventSink = eventSink,
)
}
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallTypeExtension.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallTypeExtension.kt
deleted file mode 100644
index 0c18c3e1a4..0000000000
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/CallTypeExtension.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2025 Element Creations Ltd.
- * Copyright 2025 New Vector 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 io.element.android.features.call.api.CallType
-import io.element.android.libraries.matrix.api.core.SessionId
-
-fun CallType.getSessionId(): SessionId? {
- return when (this) {
- is CallType.ExternalUrl -> null
- is CallType.RoomCall -> sessionId
- }
-}
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt
index 5fa3beb36a..dddcfceb50 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/ElementCallActivity.kt
@@ -35,8 +35,7 @@ import androidx.core.util.Consumer
import androidx.lifecycle.Lifecycle
import dev.zacsweers.metro.Inject
import io.element.android.compound.colors.SemanticColorsLightDark
-import io.element.android.features.call.api.CallType
-import io.element.android.features.call.api.CallType.ExternalUrl
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.impl.DefaultElementCallEntryPoint
import io.element.android.features.call.impl.di.CallBindings
import io.element.android.features.call.impl.pip.PictureInPictureEvents
@@ -44,7 +43,6 @@ import io.element.android.features.call.impl.pip.PictureInPicturePresenter
import io.element.android.features.call.impl.pip.PictureInPictureState
import io.element.android.features.call.impl.pip.PipView
import io.element.android.features.call.impl.services.CallForegroundService
-import io.element.android.features.call.impl.utils.CallIntentDataParser
import io.element.android.features.enterprise.api.EnterpriseService
import io.element.android.libraries.androidutils.browser.ConsoleMessageLogger
import io.element.android.libraries.architecture.Presenter
@@ -64,7 +62,6 @@ class ElementCallActivity :
AppCompatActivity(),
CallScreenNavigator,
PipView {
- @Inject lateinit var callIntentDataParser: CallIntentDataParser
@Inject lateinit var presenterFactory: CallScreenPresenter.Factory
@Inject lateinit var appPreferencesStore: AppPreferencesStore
@Inject lateinit var featureFlagService: FeatureFlagService
@@ -80,7 +77,7 @@ class ElementCallActivity :
private val requestPermissionsLauncher = registerPermissionResultLauncher()
- private val webViewTarget = mutableStateOf(null)
+ private val webViewTarget = mutableStateOf(null)
private var eventSink: ((CallScreenEvents) -> Unit)? = null
@@ -98,7 +95,7 @@ class ElementCallActivity :
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
}
- setCallType(intent)
+ setCallData(intent)
// If presenter is not created at this point, it means we have no call to display, the Activity is finishing, so return early
if (!::presenter.isInitialized) {
return
@@ -111,8 +108,8 @@ class ElementCallActivity :
setContent {
val pipState = pictureInPicturePresenter.present()
ListenToAndroidEvents(pipState)
- val colors by remember(webViewTarget.value?.getSessionId()) {
- enterpriseService.semanticColorsFlow(sessionId = webViewTarget.value?.getSessionId())
+ val colors by remember(webViewTarget.value?.sessionId) {
+ enterpriseService.semanticColorsFlow(sessionId = webViewTarget.value?.sessionId)
}.collectAsState(SemanticColorsLightDark.default)
ElementThemeApp(
appPreferencesStore = appPreferencesStore,
@@ -123,9 +120,8 @@ class ElementCallActivity :
) {
val state = presenter.present()
eventSink = state.eventSink
- LaunchedEffect(state.isCallActive, state.isInWidgetMode) {
- // Note when not in WidgetMode, isCallActive will never be true, so consider the call is active
- if (state.isCallActive || !state.isInWidgetMode) {
+ LaunchedEffect(state.isCallActive) {
+ if (state.isCallActive) {
setCallIsActive()
}
}
@@ -188,7 +184,7 @@ class ElementCallActivity :
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
- setCallType(intent)
+ setCallData(intent)
}
override fun onDestroy() {
@@ -207,25 +203,24 @@ class ElementCallActivity :
finish()
}
- private fun setCallType(intent: Intent?) {
- val callType = intent?.let {
- IntentCompat.getParcelableExtra(intent, DefaultElementCallEntryPoint.EXTRA_CALL_TYPE, CallType::class.java)
- ?: intent.dataString?.let(::parseUrl)?.let(::ExternalUrl)
+ private fun setCallData(intent: Intent?) {
+ val callData = intent?.let {
+ IntentCompat.getParcelableExtra(intent, DefaultElementCallEntryPoint.EXTRA_CALL_TYPE, CallData::class.java)
}
- val currentCallType = webViewTarget.value
- if (currentCallType == null) {
- if (callType == null) {
+ val currentCallData = webViewTarget.value
+ if (currentCallData == null) {
+ if (callData == null) {
Timber.tag(loggerTag.value).d("Re-opened the activity but we have no url to load or a cached one, finish the activity")
finish()
} else {
Timber.tag(loggerTag.value).d("Set the call type and create the presenter")
- webViewTarget.value = callType
- presenter = presenterFactory.create(callType, this)
+ webViewTarget.value = callData
+ presenter = presenterFactory.create(callData, this)
}
} else {
- if (callType == null) {
+ if (callData == null) {
Timber.tag(loggerTag.value).d("Coming back from notification, do nothing")
- } else if (callType != currentCallType) {
+ } else if (callData != currentCallData) {
Timber.tag(loggerTag.value).d("User starts another call, restart the Activity")
setIntent(intent)
recreate()
@@ -236,8 +231,6 @@ class ElementCallActivity :
}
}
- private fun parseUrl(url: String?): String? = callIntentDataParser.parse(url)
-
private fun registerPermissionResultLauncher(): ActivityResultLauncher> {
return registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt
index 2c4deab65e..1d6989fb3c 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/ui/IncomingCallActivity.kt
@@ -19,7 +19,7 @@ import androidx.core.content.IntentCompat
import androidx.lifecycle.lifecycleScope
import dev.zacsweers.metro.Inject
import io.element.android.compound.colors.SemanticColorsLightDark
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.api.ElementCallEntryPoint
import io.element.android.features.call.impl.di.CallBindings
import io.element.android.features.call.impl.notifications.CallNotificationData
@@ -118,10 +118,10 @@ class IncomingCallActivity : AppCompatActivity() {
private fun onAnswer(notificationData: CallNotificationData) {
elementCallEntryPoint.startCall(
- CallType.RoomCall(
- notificationData.sessionId,
- notificationData.roomId,
- isAudioCall = notificationData.audioOnly
+ CallData(
+ sessionId = notificationData.sessionId,
+ roomId = notificationData.roomId,
+ isAudioCall = notificationData.audioOnly,
)
)
}
@@ -129,7 +129,7 @@ class IncomingCallActivity : AppCompatActivity() {
private fun onCancel() {
val activeCall = activeCallManager.activeCall.value ?: return
appCoroutineScope.launch {
- activeCallManager.hangUpCall(callType = activeCall.callType)
+ activeCallManager.hangUpCall(callData = activeCall.callData)
}
}
}
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt
index 99679a8afb..685fc932fe 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/ActiveCallManager.kt
@@ -20,7 +20,7 @@ import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.SingleIn
import io.element.android.appconfig.ElementCallConfig
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.api.CurrentCall
import io.element.android.features.call.impl.notifications.CallNotificationData
import io.element.android.features.call.impl.notifications.RingingCallNotificationCreator
@@ -73,20 +73,20 @@ interface ActiveCallManager {
/**
* Called to hang up the active call. It will hang up the call and remove any existing UI and the active call.
- * @param callType The type of call that the user hangs up, either an external url one or a room one.
+ * @param callData The data about the call.
* @param notificationData The data for the incoming call notification.
*/
suspend fun hangUpCall(
- callType: CallType,
+ callData: CallData,
notificationData: CallNotificationData? = null,
)
/**
* Called after the user joined a call. It will remove any existing UI and set the call state as [CallState.InCall].
*
- * @param callType The type of call that the user joined, either an external url one or a room one.
+ * @param callData The data about the call.
*/
- suspend fun joinedCall(callType: CallType)
+ suspend fun joinedCall(callData: CallData)
}
@SingleIn(AppScope::class)
@@ -143,7 +143,7 @@ class DefaultActiveCallManager(
return
}
activeCall.value = ActiveCall(
- callType = CallType.RoomCall(
+ callData = CallData(
sessionId = notificationData.sessionId,
roomId = notificationData.roomId,
isAudioCall = notificationData.audioOnly,
@@ -198,17 +198,17 @@ class DefaultActiveCallManager(
}
override suspend fun hangUpCall(
- callType: CallType,
+ callData: CallData,
notificationData: CallNotificationData?,
) = mutex.withLock {
- Timber.tag(tag).d("Hang up call: $callType")
+ Timber.tag(tag).d("Hang up call: $callData")
cancelIncomingCallNotification()
val currentActiveCall = activeCall.value ?: run {
// activeCall.value can be null if the application has been killed while the call was ringing
// Build a currentActiveCall with the provided parameters.
notificationData?.let {
ActiveCall(
- callType = callType,
+ callData = callData,
callState = CallState.Ringing(
notificationData = notificationData,
)
@@ -219,8 +219,8 @@ class DefaultActiveCallManager(
return@withLock
}
- if (currentActiveCall.callType != callType) {
- Timber.tag(tag).w("Call type $callType does not match the active call type, ignoring")
+ if (currentActiveCall.callData != callData) {
+ Timber.tag(tag).w("Call type $callData does not match the active call type, ignoring")
return@withLock
}
if (currentActiveCall.callState is CallState.Ringing) {
@@ -244,8 +244,8 @@ class DefaultActiveCallManager(
activeCall.value = null
}
- override suspend fun joinedCall(callType: CallType) = mutex.withLock {
- Timber.tag(tag).d("Joined call: $callType")
+ override suspend fun joinedCall(callData: CallData) = mutex.withLock {
+ Timber.tag(tag).d("Joined call: $callData")
cancelIncomingCallNotification()
if (activeWakeLock?.isHeld == true) {
Timber.tag(tag).d("Releasing partial wakelock after joining call")
@@ -254,7 +254,7 @@ class DefaultActiveCallManager(
timedOutCallJob?.cancel()
activeCall.value = ActiveCall(
- callType = callType,
+ callData = callData,
callState = CallState.InCall,
)
}
@@ -307,15 +307,15 @@ class DefaultActiveCallManager(
private fun observeRingingCall() {
activeCall
.filterNotNull()
- .filter { it.callState is CallState.Ringing && it.callType is CallType.RoomCall }
+ .filter { it.callState is CallState.Ringing }
.flatMapLatest { activeCall ->
- val callType = activeCall.callType as CallType.RoomCall
+ val callData = activeCall.callData
val ringingInfo = activeCall.callState as CallState.Ringing
- val client = matrixClientProvider.getOrRestore(callType.sessionId).getOrNull() ?: run {
+ val client = matrixClientProvider.getOrRestore(callData.sessionId).getOrNull() ?: run {
Timber.tag(tag).d("Couldn't find session for incoming call: $activeCall")
return@flatMapLatest flowOf()
}
- val room = client.getRoom(callType.roomId) ?: run {
+ val room = client.getRoom(callData.roomId) ?: run {
Timber.tag(tag).d("Couldn't find room for incoming call: $activeCall")
return@flatMapLatest flowOf()
}
@@ -346,17 +346,17 @@ class DefaultActiveCallManager(
// has joined the call from another session.
activeCall
.filterNotNull()
- .filter { it.callState is CallState.Ringing && it.callType is CallType.RoomCall }
+ .filter { it.callState is CallState.Ringing }
.flatMapLatest { activeCall ->
- val callType = activeCall.callType as CallType.RoomCall
+ val callData = activeCall.callData
// Get a flow of updated `hasRoomCall` and `activeRoomCallParticipants` values for the room
- val room = matrixClientProvider.getOrRestore(callType.sessionId).getOrNull()?.getRoom(callType.roomId) ?: run {
+ val room = matrixClientProvider.getOrRestore(callData.sessionId).getOrNull()?.getRoom(callData.roomId) ?: run {
Timber.tag(tag).d("Couldn't find room for incoming call: $activeCall")
return@flatMapLatest flowOf()
}
room.roomInfoFlow.map {
Timber.tag(tag).d("Has room call status changed for ringing call: ${it.hasRoomCall}")
- it.hasRoomCall to (callType.sessionId in it.activeRoomCallParticipants)
+ it.hasRoomCall to (callData.sessionId in it.activeRoomCallParticipants)
}
}
// We only want to check if the room active call status changes
@@ -388,10 +388,7 @@ class DefaultActiveCallManager(
// Nothing to do
}
is CallState.InCall -> {
- when (val callType = value.callType) {
- is CallType.ExternalUrl -> defaultCurrentCallService.onCallStarted(CurrentCall.ExternalUrl(callType.url))
- is CallType.RoomCall -> defaultCurrentCallService.onCallStarted(CurrentCall.RoomCall(callType.roomId))
- }
+ defaultCurrentCallService.onCallStarted(CurrentCall.RoomCall(value.callData.roomId))
}
}
}
@@ -404,7 +401,7 @@ class DefaultActiveCallManager(
* Represents an active call.
*/
data class ActiveCall(
- val callType: CallType,
+ val callData: CallData,
val callState: CallState,
)
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/CallIntentDataParser.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/CallIntentDataParser.kt
deleted file mode 100644
index f5433c15a0..0000000000
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/CallIntentDataParser.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2025 Element Creations Ltd.
- * Copyright 2023-2025 New Vector 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.utils
-
-import android.net.Uri
-import androidx.core.net.toUri
-import dev.zacsweers.metro.Inject
-
-@Inject
-class CallIntentDataParser {
- private val validHttpSchemes = sequenceOf("https")
- private val knownHosts = sequenceOf(
- "call.element.io",
- )
-
- fun parse(data: String?): String? {
- val parsedUrl = data?.toUri() ?: return null
- val scheme = parsedUrl.scheme
- return when {
- scheme in validHttpSchemes -> parsedUrl
- scheme == "element" && parsedUrl.host == "call" -> {
- parsedUrl.getUrlParameter()
- }
- scheme == "io.element.call" && parsedUrl.host == null -> {
- parsedUrl.getUrlParameter()
- }
- // This should never be possible, but we still need to take into account the possibility
- else -> null
- }
- ?.takeIf { it.host in knownHosts }
- ?.withCustomParameters()
- }
-
- private fun Uri.getUrlParameter(): Uri? {
- return getQueryParameter("url")
- ?.let { urlParameter ->
- urlParameter.toUri().takeIf { uri ->
- uri.scheme in validHttpSchemes && !uri.host.isNullOrBlank()
- }
- }
- }
-}
-
-/**
- * Ensure the uri has the following parameters and value in the fragment:
- * - appPrompt=false
- * - confineToRoom=true
- * to ensure that the rendering will bo correct on the embedded Webview.
- */
-private fun Uri.withCustomParameters(): String {
- val builder = buildUpon()
- // Remove the existing query parameters
- builder.clearQuery()
- queryParameterNames.forEach {
- if (it == APP_PROMPT_PARAMETER || it == CONFINE_TO_ROOM_PARAMETER) return@forEach
- builder.appendQueryParameter(it, getQueryParameter(it))
- }
- // Remove the existing fragment parameters, and build the new fragment
- val currentFragment = fragment ?: ""
- // Reset the current fragment
- builder.fragment("")
- val queryFragmentPosition = currentFragment.lastIndexOf("?")
- val newFragment = if (queryFragmentPosition == -1) {
- // No existing query, build it.
- "$currentFragment?$APP_PROMPT_PARAMETER=false&$CONFINE_TO_ROOM_PARAMETER=true"
- } else {
- buildString {
- append(currentFragment.substring(0, queryFragmentPosition + 1))
- val queryFragment = currentFragment.substring(queryFragmentPosition + 1)
- // Replace the existing parameters
- val newQueryFragment = queryFragment
- .replace("$APP_PROMPT_PARAMETER=true", "$APP_PROMPT_PARAMETER=false")
- .replace("$CONFINE_TO_ROOM_PARAMETER=false", "$CONFINE_TO_ROOM_PARAMETER=true")
- append(newQueryFragment)
- // Ensure the parameters are there
- if (!newQueryFragment.contains("$APP_PROMPT_PARAMETER=false")) {
- if (newQueryFragment.isNotEmpty()) {
- append("&")
- }
- append("$APP_PROMPT_PARAMETER=false")
- }
- if (!newQueryFragment.contains("$CONFINE_TO_ROOM_PARAMETER=true")) {
- append("&$CONFINE_TO_ROOM_PARAMETER=true")
- }
- }
- }
- // We do not want to encode the Fragment part, so append it manually
- return builder.build().toString() + "#" + newFragment
-}
-
-private const val APP_PROMPT_PARAMETER = "appPrompt"
-private const val CONFINE_TO_ROOM_PARAMETER = "confineToRoom"
diff --git a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/IntentProvider.kt b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/IntentProvider.kt
index 0f74ba86d4..c6c607cbbc 100644
--- a/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/IntentProvider.kt
+++ b/features/call/impl/src/main/kotlin/io/element/android/features/call/impl/utils/IntentProvider.kt
@@ -12,21 +12,21 @@ import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import androidx.core.app.PendingIntentCompat
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.impl.DefaultElementCallEntryPoint
import io.element.android.features.call.impl.ui.ElementCallActivity
internal object IntentProvider {
- fun createIntent(context: Context, callType: CallType): Intent = Intent(context, ElementCallActivity::class.java).apply {
- putExtra(DefaultElementCallEntryPoint.EXTRA_CALL_TYPE, callType)
+ fun createIntent(context: Context, callData: CallData): Intent = Intent(context, ElementCallActivity::class.java).apply {
+ putExtra(DefaultElementCallEntryPoint.EXTRA_CALL_TYPE, callData)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_NO_USER_ACTION)
}
- fun getPendingIntent(context: Context, callType: CallType): PendingIntent {
+ fun getPendingIntent(context: Context, callData: CallData): PendingIntent {
return PendingIntentCompat.getActivity(
context,
DefaultElementCallEntryPoint.REQUEST_CODE,
- createIntent(context, callType),
+ createIntent(context, callData),
PendingIntent.FLAG_CANCEL_CURRENT,
false
)!!
diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/DefaultElementCallEntryPointTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/DefaultElementCallEntryPointTest.kt
index 85cec8c586..f21447cc85 100644
--- a/features/call/impl/src/test/kotlin/io/element/android/features/call/DefaultElementCallEntryPointTest.kt
+++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/DefaultElementCallEntryPointTest.kt
@@ -11,7 +11,7 @@ package io.element.android.features.call
import android.content.Intent
import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth.assertThat
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.impl.DefaultElementCallEntryPoint
import io.element.android.features.call.impl.notifications.CallNotificationData
import io.element.android.features.call.impl.ui.ElementCallActivity
@@ -37,7 +37,7 @@ class DefaultElementCallEntryPointTest {
@Test
fun `startCall - starts ElementCallActivity setup with the needed extras`() = runTest {
val entryPoint = createEntryPoint()
- entryPoint.startCall(CallType.RoomCall(A_SESSION_ID, A_ROOM_ID, isAudioCall = false))
+ entryPoint.startCall(CallData(A_SESSION_ID, A_ROOM_ID, isAudioCall = false))
val expectedIntent = Intent(InstrumentationRegistry.getInstrumentation().targetContext, ElementCallActivity::class.java)
val intent = shadowOf(RuntimeEnvironment.getApplication()).nextStartedActivity
@@ -53,7 +53,7 @@ class DefaultElementCallEntryPointTest {
val entryPoint = createEntryPoint(activeCallManager = activeCallManager)
entryPoint.handleIncomingCall(
- callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID, isAudioCall = false),
+ callData = CallData(A_SESSION_ID, A_ROOM_ID, isAudioCall = false),
eventId = AN_EVENT_ID,
senderId = A_USER_ID_2,
roomName = "roomName",
diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallDataTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallDataTest.kt
new file mode 100644
index 0000000000..f0cdd44082
--- /dev/null
+++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallDataTest.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2025 Element Creations Ltd.
+ * Copyright 2025 New Vector 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.ui
+
+import com.google.common.truth.Truth.assertThat
+import io.element.android.features.call.api.CallData
+import io.element.android.libraries.matrix.test.A_ROOM_ID
+import io.element.android.libraries.matrix.test.A_SESSION_ID
+import org.junit.Test
+
+class CallDataTest {
+ @Test
+ fun `RoomCall stringification does not contain the URL`() {
+ assertThat(CallData(A_SESSION_ID, A_ROOM_ID, false).toString())
+ .isEqualTo("CallData(sessionId=$A_SESSION_ID, roomId=$A_ROOM_ID, isAudioCall=false)")
+ }
+}
diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt
index b6b0120451..c2c576999c 100644
--- a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt
+++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallScreenPresenterTest.kt
@@ -13,7 +13,7 @@ import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import im.vector.app.features.analytics.plan.MobileScreen
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.impl.ui.CallScreenEvents
import io.element.android.features.call.impl.ui.CallScreenNavigator
import io.element.android.features.call.impl.ui.CallScreenPresenter
@@ -59,38 +59,13 @@ class CallScreenPresenterTest {
val warmUpRule = WarmUpRule()
@Test
- fun `present - with CallType ExternalUrl just loads the URL and sets the call as active`() = runTest {
- val analyticsLambda = lambdaRecorder {}
- val joinedCallLambda = lambdaRecorder {}
- val presenter = createCallScreenPresenter(
- callType = CallType.ExternalUrl("https://call.element.io"),
- screenTracker = FakeScreenTracker(analyticsLambda),
- activeCallManager = FakeActiveCallManager(joinedCallResult = joinedCallLambda),
- )
- moleculeFlow(RecompositionMode.Immediate) {
- presenter.present()
- }.test {
- // Wait until the URL is loaded
- advanceTimeBy(1.seconds)
- skipItems(2)
- val initialState = awaitItem()
- assertThat(initialState.urlState).isEqualTo(AsyncData.Success("https://call.element.io"))
- assertThat(initialState.webViewError).isNull()
- assertThat(initialState.isInWidgetMode).isFalse()
- assertThat(initialState.isCallActive).isFalse()
- analyticsLambda.assertions().isNeverCalled()
- joinedCallLambda.assertions().isCalledOnce()
- }
- }
-
- @Test
- fun `present - with CallType RoomCall sets call as active, loads URL and runs WidgetDriver`() = runTest {
+ fun `present - with CallData sets call as active, loads URL and runs WidgetDriver`() = runTest {
val widgetDriver = FakeMatrixWidgetDriver()
val widgetProvider = FakeCallWidgetProvider(widgetDriver)
val analyticsLambda = lambdaRecorder {}
- val joinedCallLambda = lambdaRecorder {}
+ val joinedCallLambda = lambdaRecorder {}
val presenter = createCallScreenPresenter(
- callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID, false),
+ callData = CallData(A_SESSION_ID, A_ROOM_ID, false),
widgetDriver = widgetDriver,
widgetProvider = widgetProvider,
screenTracker = FakeScreenTracker(analyticsLambda),
@@ -107,7 +82,6 @@ class CallScreenPresenterTest {
val initialState = awaitItem()
assertThat(initialState.urlState).isInstanceOf(AsyncData.Loading::class.java)
assertThat(initialState.isCallActive).isFalse()
- assertThat(initialState.isInWidgetMode).isTrue()
assertThat(widgetProvider.getWidgetCalled).isTrue()
assertThat(widgetDriver.runCalledCount).isEqualTo(1)
analyticsLambda.assertions().isCalledOnce().with(value(MobileScreen.ScreenName.RoomCall))
@@ -123,7 +97,7 @@ class CallScreenPresenterTest {
fun `present - set message interceptor, send and receive messages`() = runTest {
val widgetDriver = FakeMatrixWidgetDriver()
val presenter = createCallScreenPresenter(
- callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID, false),
+ callData = CallData(A_SESSION_ID, A_ROOM_ID, false),
widgetDriver = widgetDriver,
screenTracker = FakeScreenTracker {},
)
@@ -154,7 +128,7 @@ class CallScreenPresenterTest {
val navigator = FakeCallScreenNavigator()
val widgetDriver = FakeMatrixWidgetDriver()
val presenter = createCallScreenPresenter(
- callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID, false),
+ callData = CallData(A_SESSION_ID, A_ROOM_ID, false),
widgetDriver = widgetDriver,
navigator = navigator,
dispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true),
@@ -188,7 +162,7 @@ class CallScreenPresenterTest {
val navigator = FakeCallScreenNavigator()
val widgetDriver = FakeMatrixWidgetDriver()
val presenter = createCallScreenPresenter(
- callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID, false),
+ callData = CallData(A_SESSION_ID, A_ROOM_ID, false),
widgetDriver = widgetDriver,
navigator = navigator,
dispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true),
@@ -223,7 +197,7 @@ class CallScreenPresenterTest {
val navigator = FakeCallScreenNavigator()
val widgetDriver = FakeMatrixWidgetDriver()
val presenter = createCallScreenPresenter(
- callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID, false),
+ callData = CallData(A_SESSION_ID, A_ROOM_ID, false),
widgetDriver = widgetDriver,
navigator = navigator,
dispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true),
@@ -260,7 +234,7 @@ class CallScreenPresenterTest {
val navigator = FakeCallScreenNavigator()
val widgetDriver = FakeMatrixWidgetDriver()
val presenter = createCallScreenPresenter(
- callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID, false),
+ callData = CallData(A_SESSION_ID, A_ROOM_ID, false),
widgetDriver = widgetDriver,
navigator = navigator,
dispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true),
@@ -300,7 +274,7 @@ class CallScreenPresenterTest {
val matrixClient = FakeMatrixClient(syncService = syncService)
val appForegroundStateService = FakeAppForegroundStateService()
val presenter = createCallScreenPresenter(
- callType = CallType.RoomCall(A_SESSION_ID, A_ROOM_ID, false),
+ callData = CallData(A_SESSION_ID, A_ROOM_ID, false),
widgetDriver = widgetDriver,
navigator = navigator,
dispatchers = testCoroutineDispatchers(useUnconfinedTestDispatcher = true),
@@ -338,53 +312,8 @@ class CallScreenPresenterTest {
}
}
- @Test
- fun `present - error from WebView are updating the state`() = runTest {
- val presenter = createCallScreenPresenter(
- callType = CallType.ExternalUrl("https://call.element.io"),
- activeCallManager = FakeActiveCallManager(),
- )
- moleculeFlow(RecompositionMode.Immediate) {
- presenter.present()
- }.test {
- // Wait until the URL is loaded
- advanceTimeBy(1.seconds)
- skipItems(2)
- val initialState = awaitItem()
- initialState.eventSink(CallScreenEvents.OnWebViewError("A Webview error"))
- val finalState = awaitItem()
- assertThat(finalState.webViewError).isEqualTo("A Webview error")
- }
- }
-
- @Test
- fun `present - error from WebView are ignored if Element Call is loaded`() = runTest {
- val presenter = createCallScreenPresenter(
- callType = CallType.ExternalUrl("https://call.element.io"),
- activeCallManager = FakeActiveCallManager(),
- )
- moleculeFlow(RecompositionMode.Immediate) {
- presenter.present()
- }.test {
- // Wait until the URL is loaded
- skipItems(1)
- val initialState = awaitItem()
-
- val messageInterceptor = FakeWidgetMessageInterceptor()
- initialState.eventSink(CallScreenEvents.SetupMessageChannels(messageInterceptor))
- // Emit a message
- messageInterceptor.givenInterceptedMessage("A message")
- // WebView emits an error, but it will be ignored
- initialState.eventSink(CallScreenEvents.OnWebViewError("A Webview error"))
- val finalState = awaitItem()
- assertThat(finalState.webViewError).isNull()
-
- cancelAndIgnoreRemainingEvents()
- }
- }
-
private fun TestScope.createCallScreenPresenter(
- callType: CallType,
+ callData: CallData,
navigator: CallScreenNavigator = FakeCallScreenNavigator(),
widgetDriver: FakeMatrixWidgetDriver = FakeMatrixWidgetDriver(),
widgetProvider: FakeCallWidgetProvider = FakeCallWidgetProvider(widgetDriver),
@@ -401,7 +330,7 @@ class CallScreenPresenterTest {
}
val clock = SystemClock { 0 }
return CallScreenPresenter(
- callType = callType,
+ callData = callData,
navigator = navigator,
callWidgetProvider = widgetProvider,
userAgentProvider = userAgentProvider,
diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallTypeTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallTypeTest.kt
deleted file mode 100644
index c83408bd3b..0000000000
--- a/features/call/impl/src/test/kotlin/io/element/android/features/call/ui/CallTypeTest.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2025 Element Creations Ltd.
- * Copyright 2025 New Vector 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.ui
-
-import com.google.common.truth.Truth.assertThat
-import io.element.android.features.call.api.CallType
-import io.element.android.features.call.impl.ui.getSessionId
-import io.element.android.libraries.matrix.test.A_ROOM_ID
-import io.element.android.libraries.matrix.test.A_SESSION_ID
-import org.junit.Test
-
-class CallTypeTest {
- @Test
- fun `getSessionId returns null for ExternalUrl`() {
- assertThat(CallType.ExternalUrl("aURL").getSessionId()).isNull()
- }
-
- @Test
- fun `getSessionId returns the sessionId for RoomCall`() {
- assertThat(
- CallType.RoomCall(
- sessionId = A_SESSION_ID,
- roomId = A_ROOM_ID,
- isAudioCall = false,
- ).getSessionId()
- ).isEqualTo(A_SESSION_ID)
- }
-
- @Test
- fun `ExternalUrl stringification does not contain the URL`() {
- assertThat(CallType.ExternalUrl("aURL").toString()).isEqualTo("ExternalUrl")
- }
-
- @Test
- fun `RoomCall stringification does not contain the URL`() {
- assertThat(CallType.RoomCall(A_SESSION_ID, A_ROOM_ID, false).toString())
- .isEqualTo("RoomCall(sessionId=$A_SESSION_ID, roomId=$A_ROOM_ID, isAudioCall=false)")
- }
-}
diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/CallIntentDataParserTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/CallIntentDataParserTest.kt
deleted file mode 100644
index 43f7f931f1..0000000000
--- a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/CallIntentDataParserTest.kt
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright (c) 2025 Element Creations Ltd.
- * Copyright 2023-2025 New Vector 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.utils
-
-import com.google.common.truth.Truth.assertThat
-import io.element.android.features.call.impl.utils.CallIntentDataParser
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.RobolectricTestRunner
-import java.net.URLEncoder
-
-@RunWith(RobolectricTestRunner::class)
-class CallIntentDataParserTest {
- private val callIntentDataParser = CallIntentDataParser()
-
- @Test
- fun `a null data returns null`() {
- val url: String? = null
- assertThat(callIntentDataParser.parse(url)).isNull()
- }
-
- @Test
- fun `empty data returns null`() {
- doTest("", null)
- }
-
- @Test
- fun `invalid data returns null`() {
- doTest("!", null)
- }
-
- @Test
- fun `data with no scheme returns null`() {
- doTest("test", null)
- }
-
- @Test
- fun `Element Call http urls returns null`() {
- doTest("http://call.element.io", null)
- doTest("http://call.element.io/some-actual-call?with=parameters", null)
- }
-
- @Test
- fun `Element Call urls with unknown host returns null`() {
- // Check valid host first, should not return null
- doTest("https://call.element.io", "https://call.element.io#?appPrompt=false&confineToRoom=true")
- // Unknown host should return null
- doTest("https://unknown.io", null)
- doTest("https://call.unknown.io", null)
- doTest("https://call.element.com", null)
- doTest("https://call.element.io.tld", null)
- }
-
- @Test
- fun `Element Call urls will be returned as is`() {
- doTest(
- url = "https://call.element.io",
- expectedResult = "https://call.element.io#?$EXTRA_PARAMS"
- )
- }
-
- @Test
- fun `Element Call url with url param gets url extracted`() {
- doTest(
- url = VALID_CALL_URL_WITH_PARAM,
- expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
- )
- }
-
- @Test
- fun `HTTP and HTTPS urls that don't come from EC return null`() {
- doTest("http://app.element.io", null)
- doTest("https://app.element.io", null)
- doTest("http://", null)
- doTest("https://", null)
- }
-
- @Test
- fun `Element Call url with no url returns null`() {
- val embeddedUrl = VALID_CALL_URL_WITH_PARAM
- val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8")
- val url = "io.element.call:/?no_url=$encodedUrl"
- assertThat(callIntentDataParser.parse(url)).isNull()
- }
-
- @Test
- fun `element scheme with no call host returns null`() {
- val embeddedUrl = VALID_CALL_URL_WITH_PARAM
- val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8")
- val url = "element://no-call?url=$encodedUrl"
- assertThat(callIntentDataParser.parse(url)).isNull()
- }
-
- @Test
- fun `element scheme with no data returns null`() {
- val url = "element://call?url="
- assertThat(callIntentDataParser.parse(url)).isNull()
- }
-
- @Test
- fun `Element Call url with no data returns null`() {
- val url = "io.element.call:/?url="
- assertThat(callIntentDataParser.parse(url)).isNull()
- }
-
- @Test
- fun `element invalid scheme returns null`() {
- val embeddedUrl = VALID_CALL_URL_WITH_PARAM
- val encodedUrl = URLEncoder.encode(embeddedUrl, "utf-8")
- val url = "bad.scheme:/?url=$encodedUrl"
- assertThat(callIntentDataParser.parse(url)).isNull()
- }
-
- @Test
- fun `Element Call url with url extra param appPrompt gets url extracted`() {
- doTest(
- url = "$VALID_CALL_URL_WITH_PARAM&appPrompt=true",
- expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
- )
- }
-
- @Test
- fun `Element Call url with url extra param in fragment appPrompt gets url extracted`() {
- doTest(
- url = "$VALID_CALL_URL_WITH_PARAM#?appPrompt=true",
- expectedResult = "$VALID_CALL_URL_WITH_PARAM#?appPrompt=false&confineToRoom=true"
- )
- }
-
- @Test
- fun `Element Call url with url extra param in fragment appPrompt and other gets url extracted`() {
- doTest(
- url = "$VALID_CALL_URL_WITH_PARAM#?appPrompt=true&otherParam=maybe",
- expectedResult = "$VALID_CALL_URL_WITH_PARAM#?appPrompt=false&otherParam=maybe&confineToRoom=true"
- )
- }
-
- @Test
- fun `Element Call url with url extra param confineToRoom gets url extracted`() {
- doTest(
- url = "$VALID_CALL_URL_WITH_PARAM&confineToRoom=false",
- expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
- )
- }
-
- @Test
- fun `Element Call url with url extra param in fragment confineToRoom gets url extracted`() {
- doTest(
- url = "$VALID_CALL_URL_WITH_PARAM#?confineToRoom=false",
- expectedResult = "$VALID_CALL_URL_WITH_PARAM#?confineToRoom=true&appPrompt=false"
- )
- }
-
- @Test
- fun `Element Call url with url extra param in fragment confineToRoom and more gets url extracted`() {
- doTest(
- url = "$VALID_CALL_URL_WITH_PARAM#?confineToRoom=false&otherParam=maybe",
- expectedResult = "$VALID_CALL_URL_WITH_PARAM#?confineToRoom=true&otherParam=maybe&appPrompt=false"
- )
- }
-
- @Test
- fun `Element Call url with url fragment gets url extracted`() {
- doTest(
- url = "$VALID_CALL_URL_WITH_PARAM#fragment",
- expectedResult = "$VALID_CALL_URL_WITH_PARAM#fragment?$EXTRA_PARAMS"
- )
- }
-
- @Test
- fun `Element Call url with url fragment with params gets url extracted`() {
- doTest(
- url = "$VALID_CALL_URL_WITH_PARAM#fragment?otherParam=maybe",
- expectedResult = "$VALID_CALL_URL_WITH_PARAM#fragment?otherParam=maybe&$EXTRA_PARAMS"
- )
- }
-
- @Test
- fun `Element Call url with url fragment with other params gets url extracted`() {
- doTest(
- url = "$VALID_CALL_URL_WITH_PARAM#?otherParam=maybe",
- expectedResult = "$VALID_CALL_URL_WITH_PARAM#?otherParam=maybe&$EXTRA_PARAMS"
- )
- }
-
- @Test
- fun `Element Call url with empty fragment`() {
- doTest(
- url = "$VALID_CALL_URL_WITH_PARAM#",
- expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
- )
- }
-
- @Test
- fun `Element Call url with empty fragment query`() {
- doTest(
- url = "$VALID_CALL_URL_WITH_PARAM#?",
- expectedResult = "$VALID_CALL_URL_WITH_PARAM#?$EXTRA_PARAMS"
- )
- }
-
- private fun doTest(url: String, expectedResult: String?) {
- // Test direct parsing
- assertThat(callIntentDataParser.parse(url)).isEqualTo(expectedResult)
-
- // Test embedded url, scheme 1
- val encodedUrl = URLEncoder.encode(url, "utf-8")
- val urlScheme1 = "element://call?url=$encodedUrl"
- assertThat(callIntentDataParser.parse(urlScheme1)).isEqualTo(expectedResult)
-
- // Test embedded url, scheme 2
- val urlScheme2 = "io.element.call:/?url=$encodedUrl"
- assertThat(callIntentDataParser.parse(urlScheme2)).isEqualTo(expectedResult)
- }
-
- companion object {
- const val VALID_CALL_URL_WITH_PARAM = "https://call.element.io/some-actual-call?with=parameters"
- const val EXTRA_PARAMS = "appPrompt=false&confineToRoom=true"
- }
-}
diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt
index f9f6206ec7..3712904b03 100644
--- a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt
+++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/DefaultActiveCallManagerTest.kt
@@ -13,7 +13,7 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.content.getSystemService
import androidx.test.platform.app.InstrumentationRegistry
import com.google.common.truth.Truth.assertThat
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.impl.notifications.RingingCallNotificationCreator
import io.element.android.features.call.impl.notifications.aCallNotificationData
import io.element.android.features.call.impl.utils.ActiveCall
@@ -77,7 +77,7 @@ class DefaultActiveCallManagerTest {
assertThat(manager.activeCall.value).isEqualTo(
ActiveCall(
- callType = CallType.RoomCall(
+ callData = CallData(
sessionId = callNotificationData.sessionId,
roomId = callNotificationData.roomId,
isAudioCall = false,
@@ -104,7 +104,7 @@ class DefaultActiveCallManagerTest {
assertThat(manager.activeCall.value).isEqualTo(
ActiveCall(
- callType = CallType.RoomCall(
+ callData = CallData(
sessionId = callNotificationData.sessionId,
roomId = callNotificationData.roomId,
isAudioCall = true,
@@ -132,7 +132,7 @@ class DefaultActiveCallManagerTest {
manager.registerIncomingCall(aCallNotificationData(roomId = A_ROOM_ID_2))
assertThat(manager.activeCall.value).isEqualTo(activeCall)
- assertThat((manager.activeCall.value?.callType as? CallType.RoomCall)?.roomId).isNotEqualTo(A_ROOM_ID_2)
+ assertThat(manager.activeCall.value?.callData?.roomId).isNotEqualTo(A_ROOM_ID_2)
advanceTimeBy(1)
@@ -178,7 +178,7 @@ class DefaultActiveCallManagerTest {
}
@Test
- fun `hangUpCall - removes existing call if the CallType matches`() = runTest {
+ fun `hangUpCall - removes existing call if the CallData matches`() = runTest {
setupShadowPowerManager()
val notificationManagerCompat = mockk(relaxed = true)
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
@@ -188,7 +188,7 @@ class DefaultActiveCallManagerTest {
assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue()
- manager.hangUpCall(CallType.RoomCall(notificationData.sessionId, notificationData.roomId, false))
+ manager.hangUpCall(CallData(notificationData.sessionId, notificationData.roomId, false))
assertThat(manager.activeCall.value).isNull()
assertThat(manager.activeWakeLock?.isHeld).isFalse()
@@ -215,7 +215,7 @@ class DefaultActiveCallManagerTest {
val notificationData = aCallNotificationData(roomId = A_ROOM_ID)
manager.registerIncomingCall(notificationData)
- manager.hangUpCall(CallType.RoomCall(notificationData.sessionId, notificationData.roomId, false))
+ manager.hangUpCall(CallData(notificationData.sessionId, notificationData.roomId, false))
coVerify {
room.declineCall(notificationEventId = notificationData.eventId)
@@ -242,7 +242,7 @@ class DefaultActiveCallManagerTest {
val notificationData = aCallNotificationData(roomId = A_ROOM_ID)
// Do not register the incoming call, so the manager doesn't know about it
manager.hangUpCall(
- callType = CallType.RoomCall(notificationData.sessionId, notificationData.roomId, false),
+ callData = CallData(notificationData.sessionId, notificationData.roomId, false),
notificationData = notificationData,
)
coVerify {
@@ -320,7 +320,7 @@ class DefaultActiveCallManagerTest {
}
@Test
- fun `hangUpCall - does nothing if the CallType doesn't match`() = runTest {
+ fun `hangUpCall - does nothing if the CallData doesn't match`() = runTest {
setupShadowPowerManager()
val notificationManagerCompat = mockk(relaxed = true)
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
@@ -329,7 +329,13 @@ class DefaultActiveCallManagerTest {
assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue()
- manager.hangUpCall(CallType.ExternalUrl("https://example.com"))
+ manager.hangUpCall(
+ CallData(
+ sessionId = A_SESSION_ID,
+ roomId = A_ROOM_ID_2,
+ isAudioCall = true,
+ )
+ )
assertThat(manager.activeCall.value).isNotNull()
assertThat(manager.activeWakeLock?.isHeld).isTrue()
@@ -344,10 +350,10 @@ class DefaultActiveCallManagerTest {
val manager = createActiveCallManager(notificationManagerCompat = notificationManagerCompat)
assertThat(manager.activeCall.value).isNull()
- manager.joinedCall(CallType.RoomCall(A_SESSION_ID, A_ROOM_ID, true))
+ manager.joinedCall(CallData(A_SESSION_ID, A_ROOM_ID, true))
assertThat(manager.activeCall.value).isEqualTo(
ActiveCall(
- callType = CallType.RoomCall(
+ callData = CallData(
sessionId = A_SESSION_ID,
roomId = A_ROOM_ID,
isAudioCall = true,
@@ -450,7 +456,7 @@ class DefaultActiveCallManagerTest {
assertThat(manager.activeCall.value).isEqualTo(
ActiveCall(
- callType = CallType.RoomCall(
+ callData = CallData(
sessionId = callNotificationData.sessionId,
roomId = callNotificationData.roomId,
isAudioCall = false,
diff --git a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/FakeActiveCallManager.kt b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/FakeActiveCallManager.kt
index 2d0e126ab5..c2c38284a9 100644
--- a/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/FakeActiveCallManager.kt
+++ b/features/call/impl/src/test/kotlin/io/element/android/features/call/utils/FakeActiveCallManager.kt
@@ -8,7 +8,7 @@
package io.element.android.features.call.utils
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.impl.notifications.CallNotificationData
import io.element.android.features.call.impl.utils.ActiveCall
import io.element.android.features.call.impl.utils.ActiveCallManager
@@ -17,8 +17,8 @@ import kotlinx.coroutines.flow.MutableStateFlow
class FakeActiveCallManager(
var registerIncomingCallResult: (CallNotificationData) -> Unit = {},
- var hangUpCallResult: (CallType, CallNotificationData?) -> Unit = { _, _ -> },
- var joinedCallResult: (CallType) -> Unit = {},
+ var hangUpCallResult: (CallData, CallNotificationData?) -> Unit = { _, _ -> },
+ var joinedCallResult: (CallData) -> Unit = {},
) : ActiveCallManager {
override val activeCall = MutableStateFlow(null)
@@ -26,12 +26,12 @@ class FakeActiveCallManager(
registerIncomingCallResult(notificationData)
}
- override suspend fun hangUpCall(callType: CallType, notificationData: CallNotificationData?) = simulateLongTask {
- hangUpCallResult(callType, notificationData)
+ override suspend fun hangUpCall(callData: CallData, notificationData: CallNotificationData?) = simulateLongTask {
+ hangUpCallResult(callData, notificationData)
}
- override suspend fun joinedCall(callType: CallType) = simulateLongTask {
- joinedCallResult(callType)
+ override suspend fun joinedCall(callData: CallData) = simulateLongTask {
+ joinedCallResult(callData)
}
fun setActiveCall(value: ActiveCall?) {
diff --git a/features/call/test/src/main/kotlin/io/element/android/features/call/test/FakeElementCallEntryPoint.kt b/features/call/test/src/main/kotlin/io/element/android/features/call/test/FakeElementCallEntryPoint.kt
index fdf3ca566b..13b61feacb 100644
--- a/features/call/test/src/main/kotlin/io/element/android/features/call/test/FakeElementCallEntryPoint.kt
+++ b/features/call/test/src/main/kotlin/io/element/android/features/call/test/FakeElementCallEntryPoint.kt
@@ -8,16 +8,16 @@
package io.element.android.features.call.test
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.api.ElementCallEntryPoint
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.tests.testutils.lambda.lambdaError
class FakeElementCallEntryPoint(
- var startCallResult: (CallType) -> Unit = { lambdaError() },
+ var startCallResult: (CallData) -> Unit = { lambdaError() },
var handleIncomingCallResult: (
- CallType.RoomCall,
+ CallData,
EventId,
UserId,
String?,
@@ -27,12 +27,12 @@ class FakeElementCallEntryPoint(
String?,
) -> Unit = { _, _, _, _, _, _, _, _ -> lambdaError() }
) : ElementCallEntryPoint {
- override fun startCall(callType: CallType) {
- startCallResult(callType)
+ override fun startCall(callData: CallData) {
+ startCallResult(callData)
}
override suspend fun handleIncomingCall(
- callType: CallType.RoomCall,
+ callData: CallData,
eventId: EventId,
senderId: UserId,
roomName: String?,
@@ -44,7 +44,7 @@ class FakeElementCallEntryPoint(
textContent: String?,
) {
handleIncomingCallResult(
- callType,
+ callData,
eventId,
senderId,
roomName,
diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt
index 36e94ec456..c7b046dc14 100644
--- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt
+++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/MessagesFlowNode.kt
@@ -24,7 +24,7 @@ import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import im.vector.app.features.analytics.plan.Interaction
import io.element.android.annotations.ContributesNode
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.api.ElementCallEntryPoint
import io.element.android.features.forward.api.ForwardEntryPoint
import io.element.android.features.knockrequests.api.list.KnockRequestsListEntryPoint
@@ -277,13 +277,13 @@ class MessagesFlowNode(
}
override fun navigateToRoomCall(roomId: RoomId, isAudioCall: Boolean) {
- val callType = CallType.RoomCall(
+ val callData = CallData(
sessionId = sessionId,
roomId = roomId,
- isAudioCall = isAudioCall
+ isAudioCall = isAudioCall,
)
analyticsService.captureInteraction(Interaction.Name.MobileRoomCallButton)
- elementCallEntryPoint.startCall(callType)
+ elementCallEntryPoint.startCall(callData)
}
override fun navigateToPinnedMessagesList() {
@@ -506,13 +506,13 @@ class MessagesFlowNode(
}
override fun navigateToRoomCall(roomId: RoomId, isAudioCall: Boolean) {
- val callType = CallType.RoomCall(
+ val callData = CallData(
sessionId = sessionId,
roomId = roomId,
isAudioCall = isAudioCall
)
analyticsService.captureInteraction(Interaction.Name.MobileRoomCallButton)
- elementCallEntryPoint.startCall(callType)
+ elementCallEntryPoint.startCall(callData)
}
override fun navigateToThread(threadRootId: ThreadId, focusedEventId: EventId?) {
diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt
index c3ae902ba9..818287ab68 100644
--- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt
+++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt
@@ -25,7 +25,7 @@ import dev.zacsweers.metro.AssistedInject
import im.vector.app.features.analytics.plan.Interaction
import io.element.android.annotations.ContributesNode
import io.element.android.appconfig.LearnMoreConfig
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.api.ElementCallEntryPoint
import io.element.android.features.knockrequests.api.list.KnockRequestsListEntryPoint
import io.element.android.features.messages.api.MessagesEntryPoint
@@ -225,13 +225,13 @@ class RoomDetailsFlowNode(
}
override fun navigateToRoomCall(callIntent: CallIntent) {
- val inputs = CallType.RoomCall(
+ val callData = CallData(
sessionId = room.sessionId,
roomId = room.roomId,
isAudioCall = callIntent == CallIntent.AUDIO
)
analyticsService.captureInteraction(Interaction.Name.MobileRoomCallButton)
- elementCallEntryPoint.startCall(inputs)
+ elementCallEntryPoint.startCall(callData)
}
override fun navigateToReportRoom() {
@@ -288,7 +288,7 @@ class RoomDetailsFlowNode(
override fun startCall(dmRoomId: RoomId, callIntent: CallIntent) {
elementCallEntryPoint.startCall(
- CallType.RoomCall(
+ CallData(
roomId = dmRoomId,
sessionId = room.sessionId,
isAudioCall = callIntent == CallIntent.AUDIO
diff --git a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/UserProfileFlowNode.kt b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/UserProfileFlowNode.kt
index aaafbe04be..aff9e3502d 100644
--- a/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/UserProfileFlowNode.kt
+++ b/features/userprofile/impl/src/main/kotlin/io/element/android/features/userprofile/impl/UserProfileFlowNode.kt
@@ -20,7 +20,7 @@ import com.bumble.appyx.navmodel.backstack.operation.push
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.api.ElementCallEntryPoint
import io.element.android.features.userprofile.api.UserProfileEntryPoint
import io.element.android.features.userprofile.impl.root.UserProfileNode
@@ -86,7 +86,7 @@ class UserProfileFlowNode(
override fun startCall(dmRoomId: RoomId, callIntent: CallIntent) {
elementCallEntryPoint.startCall(
- CallType.RoomCall(
+ CallData(
sessionId = sessionId,
roomId = dmRoomId,
isAudioCall = callIntent == CallIntent.AUDIO
diff --git a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResultProcessor.kt b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResultProcessor.kt
index 0dd2761446..a97937f5d0 100644
--- a/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResultProcessor.kt
+++ b/libraries/push/impl/src/main/kotlin/io/element/android/libraries/push/impl/notifications/NotificationResultProcessor.kt
@@ -10,7 +10,7 @@ package io.element.android.libraries.push.impl.notifications
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import dev.zacsweers.metro.SingleIn
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.api.ElementCallEntryPoint
import io.element.android.libraries.di.annotations.AppCoroutineScope
import io.element.android.libraries.matrix.api.core.EventId
@@ -215,9 +215,9 @@ class DefaultNotificationResultProcessor(
private suspend fun handleRingingCallEvent(notifiableEvent: NotifiableRingingCallEvent) {
Timber.i("## handleInternal() : Incoming call.")
elementCallEntryPoint.handleIncomingCall(
- callType = CallType.RoomCall(
- notifiableEvent.sessionId,
- notifiableEvent.roomId,
+ callData = CallData(
+ sessionId = notifiableEvent.sessionId,
+ roomId = notifiableEvent.roomId,
isAudioCall = notifiableEvent.callIntent == CallIntent.AUDIO
),
eventId = notifiableEvent.eventId,
diff --git a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationResultProcessorTest.kt b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationResultProcessorTest.kt
index 6acb375bac..91f29dd28e 100644
--- a/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationResultProcessorTest.kt
+++ b/libraries/push/impl/src/test/kotlin/io/element/android/libraries/push/impl/notifications/DefaultNotificationResultProcessorTest.kt
@@ -8,7 +8,7 @@
package io.element.android.libraries.push.impl.notifications
import com.google.common.truth.Truth.assertThat
-import io.element.android.features.call.api.CallType
+import io.element.android.features.call.api.CallData
import io.element.android.features.call.test.FakeElementCallEntryPoint
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.RoomId
@@ -104,7 +104,7 @@ class DefaultNotificationResultProcessorTest {
@Test
fun `when ringing call PushData is received, the incoming call will be handled`() = runTest {
val handleIncomingCallLambda = lambdaRecorder<
- CallType.RoomCall,
+ CallData,
EventId,
UserId,
String?,
@@ -140,7 +140,7 @@ class DefaultNotificationResultProcessorTest {
fun `when notify call PushData is received, the incoming call will be treated as a normal notification`() = runTest {
val onNotifiableEventsReceived = lambdaRecorder, Unit> {}
val handleIncomingCallLambda = lambdaRecorder<
- CallType.RoomCall,
+ CallData,
EventId,
UserId,
String?,
@@ -176,7 +176,7 @@ class DefaultNotificationResultProcessorTest {
fun `when notify call PushData is received, the incoming call will be treated as a normal notification even if notification are disabled`() = runTest {
val onNotifiableEventsReceived = lambdaRecorder, Unit> {}
val handleIncomingCallLambda = lambdaRecorder<
- CallType.RoomCall,
+ CallData,
EventId,
UserId,
String?,
diff --git a/tools/adb/callLinkCustomScheme.sh b/tools/adb/callLinkCustomScheme.sh
deleted file mode 100755
index 7e6c9f02d3..0000000000
--- a/tools/adb/callLinkCustomScheme.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#! /bin/bash
-
-# Copyright (c) 2025 Element Creations Ltd.
-# Copyright 2023-2024 New Vector Ltd.
-#
-# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
-# Please see LICENSE files in the repository root for full details.
-
-# Format is:
-# element://call?url=some-encoded-url
-# For instance
-# element://call?url=https%3A%2F%2Fcall.element.io%2FTestElementCall
-
-adb shell am start -a android.intent.action.VIEW -d element://call?url=https%3A%2F%2Fcall.element.io%2FTestElementCall
diff --git a/tools/adb/callLinkCustomScheme2.sh b/tools/adb/callLinkCustomScheme2.sh
deleted file mode 100755
index 43f427f22f..0000000000
--- a/tools/adb/callLinkCustomScheme2.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#! /bin/bash
-
-# Copyright (c) 2025 Element Creations Ltd.
-# Copyright 2023-2024 New Vector Ltd.
-#
-# SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
-# Please see LICENSE files in the repository root for full details.
-
-# Format is:
-# io.element.call:/?url=some-encoded-url
-# For instance
-# io.element.call:/?url=https%3A%2F%2Fcall.element.io%2FTestElementCall
-
-adb shell am start -a android.intent.action.VIEW -d io.element.call:/?url=https%3A%2F%2Fcall.element.io%2FTestElementCall