From 27d4f6057882d4ae7d55d10e9b964b7e52b35e0a Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 14 Sep 2021 18:50:51 +0200 Subject: [PATCH 1/2] Jitsi: introduces ConferenceEvent to avoid using directly Jitsi sdk from fragments/activities --- ...siBroadcastEvent.kt => ConferenceEvent.kt} | 40 +++++++++++++------ .../conference/JitsiActiveConferenceHolder.kt | 13 +++--- .../call/conference/VectorJitsiActivity.kt | 18 ++++----- .../home/room/detail/RoomDetailAction.kt | 4 +- .../home/room/detail/RoomDetailFragment.kt | 18 ++++----- .../home/room/detail/RoomDetailViewModel.kt | 10 ++--- 6 files changed, 58 insertions(+), 45 deletions(-) rename vector/src/main/java/im/vector/app/features/call/conference/{JitsiBroadcastEvent.kt => ConferenceEvent.kt} (63%) diff --git a/vector/src/main/java/im/vector/app/features/call/conference/JitsiBroadcastEvent.kt b/vector/src/main/java/im/vector/app/features/call/conference/ConferenceEvent.kt similarity index 63% rename from vector/src/main/java/im/vector/app/features/call/conference/JitsiBroadcastEvent.kt rename to vector/src/main/java/im/vector/app/features/call/conference/ConferenceEvent.kt index 00ad7c540e..cfa076f31b 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/JitsiBroadcastEvent.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/ConferenceEvent.kt @@ -28,20 +28,21 @@ import com.facebook.react.bridge.JavaOnlyMap import org.jitsi.meet.sdk.BroadcastEmitter import org.jitsi.meet.sdk.BroadcastEvent import org.jitsi.meet.sdk.JitsiMeet -import org.matrix.android.sdk.api.extensions.tryOrNull +import timber.log.Timber private const val CONFERENCE_URL_DATA_KEY = "url" -fun BroadcastEvent.extractConferenceUrl(): String? { - return when (type) { - BroadcastEvent.Type.CONFERENCE_TERMINATED, - BroadcastEvent.Type.CONFERENCE_WILL_JOIN, - BroadcastEvent.Type.CONFERENCE_JOINED -> data[CONFERENCE_URL_DATA_KEY] as? String - else -> null +sealed class ConferenceEvent(open val data: Map) { + data class Terminated(override val data: Map) : ConferenceEvent(data) + data class WillJoin(override val data: Map) : ConferenceEvent(data) + data class Joined(override val data: Map) : ConferenceEvent(data) + + fun extractConferenceUrl(): String? { + return data[CONFERENCE_URL_DATA_KEY] as? String } } -class JitsiBroadcastEmitter(private val context: Context) { +class ConferenceEventEmitter(private val context: Context) { fun emitConferenceEnded() { val broadcastEventData = JavaOnlyMap.of(CONFERENCE_URL_DATA_KEY, JitsiMeet.getCurrentConference()) @@ -49,8 +50,9 @@ class JitsiBroadcastEmitter(private val context: Context) { } } -class JitsiBroadcastEventObserver(private val context: Context, - private val onBroadcastEvent: (BroadcastEvent) -> Unit) : LifecycleObserver { +class ConferenceEventObserver(private val context: Context, + private val onBroadcastEvent: (ConferenceEvent) -> Unit) + : LifecycleObserver { // See https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-android-sdk#listening-for-broadcasted-events private val broadcastReceiver = object : BroadcastReceiver() { @@ -61,8 +63,10 @@ class JitsiBroadcastEventObserver(private val context: Context, @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) fun unregisterForBroadcastMessages() { - tryOrNull("Unable to unregister receiver") { + try { LocalBroadcastManager.getInstance(context).unregisterReceiver(broadcastReceiver) + } catch (throwable: Throwable) { + Timber.v("Unable to unregister receiver") } } @@ -72,13 +76,23 @@ class JitsiBroadcastEventObserver(private val context: Context, for (type in BroadcastEvent.Type.values()) { intentFilter.addAction(type.action) } - tryOrNull("Unable to register receiver") { + try { LocalBroadcastManager.getInstance(context).registerReceiver(broadcastReceiver, intentFilter) + } catch (throwable: Throwable) { + Timber.v("Unable to register receiver") } } private fun onBroadcastReceived(intent: Intent) { val event = BroadcastEvent(intent) - onBroadcastEvent(event) + val conferenceEvent = when (event.type) { + BroadcastEvent.Type.CONFERENCE_JOINED -> ConferenceEvent.Joined(event.data) + BroadcastEvent.Type.CONFERENCE_TERMINATED -> ConferenceEvent.Terminated(event.data) + BroadcastEvent.Type.CONFERENCE_WILL_JOIN -> ConferenceEvent.WillJoin(event.data) + else -> null + } + if (conferenceEvent != null) { + onBroadcastEvent(conferenceEvent) + } } } diff --git a/vector/src/main/java/im/vector/app/features/call/conference/JitsiActiveConferenceHolder.kt b/vector/src/main/java/im/vector/app/features/call/conference/JitsiActiveConferenceHolder.kt index 1a9fc5ea10..179956612d 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/JitsiActiveConferenceHolder.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/JitsiActiveConferenceHolder.kt @@ -18,7 +18,6 @@ package im.vector.app.features.call.conference import android.content.Context import androidx.lifecycle.ProcessLifecycleOwner -import org.jitsi.meet.sdk.BroadcastEvent import org.matrix.android.sdk.api.extensions.orFalse import javax.inject.Inject import javax.inject.Singleton @@ -29,18 +28,18 @@ class JitsiActiveConferenceHolder @Inject constructor(context: Context) { private var activeConference: String? = null init { - ProcessLifecycleOwner.get().lifecycle.addObserver(JitsiBroadcastEventObserver(context, this::onBroadcastEvent)) + ProcessLifecycleOwner.get().lifecycle.addObserver(ConferenceEventObserver(context, this::onBroadcastEvent)) } fun isJoined(confId: String?): Boolean { return confId != null && activeConference?.endsWith(confId).orFalse() } - private fun onBroadcastEvent(broadcastEvent: BroadcastEvent) { - when (broadcastEvent.type) { - BroadcastEvent.Type.CONFERENCE_JOINED -> activeConference = broadcastEvent.extractConferenceUrl() - BroadcastEvent.Type.CONFERENCE_TERMINATED -> activeConference = null - else -> Unit + private fun onBroadcastEvent(conferenceEvent: ConferenceEvent) { + when (conferenceEvent) { + is ConferenceEvent.Joined -> activeConference = conferenceEvent.extractConferenceUrl() + is ConferenceEvent.Terminated -> activeConference = null + else -> Unit } } } diff --git a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt index a7a6f99cfc..e7fd541f3d 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt @@ -39,13 +39,13 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivityJitsiBinding import kotlinx.parcelize.Parcelize -import org.jitsi.meet.sdk.BroadcastEvent import org.jitsi.meet.sdk.JitsiMeet import org.jitsi.meet.sdk.JitsiMeetActivityDelegate import org.jitsi.meet.sdk.JitsiMeetActivityInterface import org.jitsi.meet.sdk.JitsiMeetConferenceOptions import org.jitsi.meet.sdk.JitsiMeetView import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.util.JsonDict import timber.log.Timber import java.net.URL import javax.inject.Inject @@ -87,7 +87,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMee JitsiCallViewEvents.LeaveConference -> handleLeaveConference() }.exhaustive } - lifecycle.addObserver(JitsiBroadcastEventObserver(this, this::onBroadcastEvent)) + lifecycle.addObserver(ConferenceEventObserver(this, this::onBroadcastEvent)) } override fun onResume() { @@ -113,7 +113,7 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMee jitsiMeetView?.dispose() // Fake emitting CONFERENCE_TERMINATED event when currentConf is not null (probably when closing the PiP screen). if (currentConf != null) { - JitsiBroadcastEmitter(this).emitConferenceEnded() + ConferenceEventEmitter(this).emitConferenceEnded() } JitsiMeetActivityDelegate.onHostDestroy(this) super.onDestroy() @@ -223,15 +223,15 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMee JitsiMeetActivityDelegate.onRequestPermissionsResult(requestCode, permissions, grantResults) } - private fun onBroadcastEvent(event: BroadcastEvent) { - Timber.v("Broadcast received: ${event.type}") - when (event.type) { - BroadcastEvent.Type.CONFERENCE_TERMINATED -> onConferenceTerminated(event.data) - else -> Unit + private fun onBroadcastEvent(event: ConferenceEvent) { + Timber.v("Broadcast received: $event") + when (event) { + is ConferenceEvent.Terminated -> onConferenceTerminated(event.data) + else -> Unit } } - private fun onConferenceTerminated(data: Map) { + private fun onConferenceTerminated(data: JsonDict) { Timber.v("JitsiMeetViewListener.onConferenceTerminated()") // Do not finish if there is an error if (data["error"] == null) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt index 94388dcfeb..9bb82cdc27 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailAction.kt @@ -19,7 +19,7 @@ package im.vector.app.features.home.room.detail import android.net.Uri import android.view.View import im.vector.app.core.platform.VectorViewModelAction -import org.jitsi.meet.sdk.BroadcastEvent +import im.vector.app.features.call.conference.ConferenceEvent import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent @@ -97,7 +97,7 @@ sealed class RoomDetailAction : VectorViewModelAction { data class EnsureNativeWidgetAllowed(val widget: Widget, val userJustAccepted: Boolean, val grantedEvents: RoomDetailViewEvents) : RoomDetailAction() - data class UpdateJoinJitsiCallStatus(val jitsiEvent: BroadcastEvent): RoomDetailAction() + data class UpdateJoinJitsiCallStatus(val conferenceEvent: ConferenceEvent): RoomDetailAction() data class OpenOrCreateDm(val userId: String) : RoomDetailAction() data class JumpToReadReceipt(val userId: String) : RoomDetailAction() diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index d45aa69cf3..287ff70dde 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -123,8 +123,9 @@ import im.vector.app.features.attachments.preview.AttachmentsPreviewArgs import im.vector.app.features.attachments.toGroupedContentAttachmentData import im.vector.app.features.call.SharedKnownCallsViewModel import im.vector.app.features.call.VectorCallActivity -import im.vector.app.features.call.conference.JitsiBroadcastEmitter -import im.vector.app.features.call.conference.JitsiBroadcastEventObserver +import im.vector.app.features.call.conference.ConferenceEvent +import im.vector.app.features.call.conference.ConferenceEventEmitter +import im.vector.app.features.call.conference.ConferenceEventObserver import im.vector.app.features.call.conference.JitsiCallViewModel import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.command.Command @@ -184,7 +185,6 @@ import nl.dionsegijn.konfetti.models.Shape import nl.dionsegijn.konfetti.models.Size import org.billcarsonfr.jsonviewer.JSonViewerDialog import org.commonmark.parser.Parser -import org.jitsi.meet.sdk.BroadcastEvent import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.content.ContentAttachmentData @@ -324,7 +324,7 @@ class RoomDetailFragment @Inject constructor( } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - lifecycle.addObserver(JitsiBroadcastEventObserver(vectorBaseActivity, this::onBroadcastJitsiEvent)) + lifecycle.addObserver(ConferenceEventObserver(vectorBaseActivity, this::onBroadcastJitsiEvent)) super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java) knownCallsViewModel = activityViewModelProvider.get(SharedKnownCallsViewModel::class.java) @@ -366,10 +366,10 @@ class RoomDetailFragment @Inject constructor( knownCallsViewModel .liveKnownCalls - .observe(viewLifecycleOwner, { + .observe(viewLifecycleOwner) { currentCallsViewPresenter.updateCall(callManager.getCurrentCall(), it) invalidateOptionsMenu() - }) + } roomDetailViewModel.selectSubscribe(RoomDetailViewState::canShowJumpToReadMarker, RoomDetailViewState::unreadState) { _, _ -> updateJumpToReadMarkerViewVisibility() @@ -454,11 +454,11 @@ class RoomDetailFragment @Inject constructor( } private fun leaveJitsiConference() { - JitsiBroadcastEmitter(vectorBaseActivity).emitConferenceEnded() + ConferenceEventEmitter(vectorBaseActivity).emitConferenceEnded() } - private fun onBroadcastJitsiEvent(jitsiEvent: BroadcastEvent) { - roomDetailViewModel.handle(RoomDetailAction.UpdateJoinJitsiCallStatus(jitsiEvent)) + private fun onBroadcastJitsiEvent(conferenceEvent: ConferenceEvent) { + roomDetailViewModel.handle(RoomDetailAction.UpdateJoinJitsiCallStatus(conferenceEvent)) } private fun onCannotRecord() { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index 3e902dc2ef..5ea5e81240 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -40,6 +40,7 @@ import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.features.call.conference.JitsiActiveConferenceHolder import im.vector.app.features.attachments.toContentAttachmentData +import im.vector.app.features.call.conference.ConferenceEvent import im.vector.app.features.call.conference.JitsiService import im.vector.app.features.call.lookup.CallProtocolsChecker import im.vector.app.features.call.webrtc.WebRtcCallManager @@ -66,7 +67,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.commonmark.parser.Parser import org.commonmark.renderer.html.HtmlRenderer -import org.jitsi.meet.sdk.BroadcastEvent import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.extensions.tryOrNull @@ -368,12 +368,12 @@ class RoomDetailViewModel @AssistedInject constructor( } return@withState } - when (action.jitsiEvent.type) { - BroadcastEvent.Type.CONFERENCE_JOINED, - BroadcastEvent.Type.CONFERENCE_TERMINATED -> { + when (action.conferenceEvent) { + is ConferenceEvent.Joined, + is ConferenceEvent.Terminated -> { setState { copy(jitsiState = jitsiState.copy(hasJoined = activeConferenceHolder.isJoined(jitsiState.confId))) } } - else -> Unit + else -> Unit } } From 8e9cd52cf0d0a606b521c8010ea9458dcfebc299 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 16 Sep 2021 18:57:50 +0200 Subject: [PATCH 2/2] Add changelog file --- changelog.d/4014.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/4014.misc diff --git a/changelog.d/4014.misc b/changelog.d/4014.misc new file mode 100644 index 0000000000..d2c69a4ac5 --- /dev/null +++ b/changelog.d/4014.misc @@ -0,0 +1 @@ +Introduces ConferenceEvent to abstract usage of Jitsi BroadcastEvent class. \ No newline at end of file