Fix issues with stuck 'loading...' state and hangup (#1690)

* Fix issues with stuck 'loading...' state and hangu
This commit is contained in:
Jorge Martin Espinosa 2023-10-30 17:01:54 +01:00 committed by GitHub
parent d1a3a80b9b
commit 356a321788
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 34 additions and 14 deletions

View file

@ -18,6 +18,7 @@ package io.element.android.features.call.data
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
@Serializable
data class WidgetMessage(
@ -25,6 +26,7 @@ data class WidgetMessage(
@SerialName("widgetId") val widgetId: String,
@SerialName("requestId") val requestId: String,
@SerialName("action") val action: Action,
@SerialName("data") val data: JsonElement? = null,
) {
@Serializable
@ -38,6 +40,8 @@ data class WidgetMessage(
@Serializable
enum class Action {
@SerialName("im.vector.hangup")
HangUp
HangUp,
@SerialName("send_event")
SendEvent,
}
}

View file

@ -19,9 +19,12 @@ package io.element.android.features.call.ui
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
@ -41,6 +44,9 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.serialization.json.contentOrNull
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import java.util.UUID
class CallScreenPresenter @AssistedInject constructor(
@ -66,6 +72,7 @@ class CallScreenPresenter @AssistedInject constructor(
val urlState = remember { mutableStateOf<Async<String>>(Async.Uninitialized) }
val callWidgetDriver = remember { mutableStateOf<MatrixWidgetDriver?>(null) }
val messageInterceptor = remember { mutableStateOf<WidgetMessageInterceptor?>(null) }
var isJoinedCall by rememberSaveable { mutableStateOf(false) }
LaunchedEffect(Unit) {
loadUrl(callType, urlState, callWidgetDriver)
@ -92,8 +99,16 @@ class CallScreenPresenter @AssistedInject constructor(
callWidgetDriver.value?.send(it)
val parsedMessage = parseMessage(it)
if (parsedMessage?.direction == WidgetMessage.Direction.FromWidget && parsedMessage.action == WidgetMessage.Action.HangUp) {
close(callWidgetDriver.value, navigator)
if (parsedMessage?.direction == WidgetMessage.Direction.FromWidget) {
if (parsedMessage.action == WidgetMessage.Action.HangUp) {
close(callWidgetDriver.value, navigator)
} else if (parsedMessage.action == WidgetMessage.Action.SendEvent) {
// This event is received when a member joins the call, the first one will be the current one
val type = parsedMessage.data?.jsonObject?.get("type")?.jsonPrimitive?.contentOrNull
if (type == "org.matrix.msc3401.call.member") {
isJoinedCall = true
}
}
}
}
.launchIn(this)
@ -105,11 +120,13 @@ class CallScreenPresenter @AssistedInject constructor(
is CallScreeEvents.Hangup -> {
val widgetId = callWidgetDriver.value?.id
val interceptor = messageInterceptor.value
if (widgetId != null && interceptor != null) {
if (widgetId != null && interceptor != null && isJoinedCall) {
// If the call was joined, we need to hang up first. Then the UI will be dismissed automatically.
sendHangupMessage(widgetId, interceptor)
}
coroutineScope.launch {
close(callWidgetDriver.value, navigator)
} else {
coroutineScope.launch {
close(callWidgetDriver.value, navigator)
}
}
}
is CallScreeEvents.SetupMessageChannels -> {
@ -159,6 +176,7 @@ class CallScreenPresenter @AssistedInject constructor(
widgetId = widgetId,
requestId = "widgetapi-${clock.epochMillis()}",
action = WidgetMessage.Action.HangUp,
data = null,
)
messageInterceptor.sendMessage(WidgetMessageSerializer.serialize(message))
}

View file

@ -111,12 +111,8 @@ private fun CallWebView(
modifier = modifier,
factory = { context ->
WebView(context).apply {
setup(userAgent, onPermissionsRequested)
if (url is Async.Success) {
loadUrl(url.data)
}
onWebViewCreated(this)
setup(userAgent, onPermissionsRequested)
}
},
update = { webView ->

View file

@ -36,7 +36,8 @@ class WebViewWidgetMessageInterceptor(
const val LISTENER_NAME = "elementX"
}
override val interceptedMessages = MutableSharedFlow<String>(replay = 1, extraBufferCapacity = 2)
// It's important to have extra capacity here to make sure we don't drop any messages
override val interceptedMessages = MutableSharedFlow<String>(extraBufferCapacity = 10)
init {
webView.webViewClient = object : WebViewClient() {

View file

@ -36,7 +36,8 @@ class RustWidgetDriver(
private val widgetCapabilitiesProvider: WidgetCapabilitiesProvider,
): MatrixWidgetDriver {
override val incomingMessages = MutableSharedFlow<String>()
// It's important to have extra capacity here to make sure we don't drop any messages
override val incomingMessages = MutableSharedFlow<String>(extraBufferCapacity = 10)
private val driverAndHandle = makeWidgetDriver(widgetSettings.toRustWidgetSettings())
private var receiveMessageJob: Job? = null