Skip to content

Commit

Permalink
feat: terminate the SFT OneOnOneCall once the other person hangup the…
Browse files Browse the repository at this point in the history
… call (WPB-7153) (#2923)

* chore: resolve conflicts

* chore: unit test

* chore: resolve conflicts

* chore: unit test

* chore: unit test

* feat: terminate the SFT OneOnOneCall once the other person hangup the call

* chore: unit test

* chore: unit test

* chore: typo

---------

Co-authored-by: Mohamad Jaara <[email protected]>
  • Loading branch information
ohassine and MohamadJaara authored Aug 5, 2024
1 parent 28e19a6 commit 58b3896
Show file tree
Hide file tree
Showing 15 changed files with 595 additions and 31 deletions.
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ sqldelight = "2.0.1"
sqlcipher-android = "4.5.5"
pbandk = "0.14.2"
turbine = "1.0.0"
avs = "9.6.13"
avs = "9.6.15"
jna = "5.14.0"
core-crypto = "1.0.0-rc.56-hotfix.2"
core-crypto-multiplatform = "0.6.0-rc.3-multiplatform-pre1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,23 @@ package com.wire.kalium.logic.feature.call
import com.wire.kalium.calling.Calling
import com.wire.kalium.calling.types.Handle
import com.wire.kalium.logic.cache.SelfConversationIdProvider
import com.wire.kalium.logic.configuration.UserConfigRepository
import com.wire.kalium.logic.data.call.CallRepository
import com.wire.kalium.logic.data.call.VideoStateChecker
import com.wire.kalium.logic.data.call.mapper.CallMapperImpl
import com.wire.kalium.logic.data.conversation.ClientId
import com.wire.kalium.logic.data.conversation.ConversationRepository
import com.wire.kalium.logic.data.conversation.SubconversationRepository
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.id.CurrentClientIdProvider
import com.wire.kalium.logic.data.id.FederatedIdMapper
import com.wire.kalium.logic.data.id.QualifiedIdMapper
import com.wire.kalium.logic.data.message.Message
import com.wire.kalium.logic.data.message.MessageContent
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.data.user.UserRepository
import com.wire.kalium.logic.data.id.CurrentClientIdProvider
import com.wire.kalium.logic.feature.call.usecase.ConversationClientsInCallUpdater
import com.wire.kalium.logic.feature.call.usecase.GetCallConversationTypeProvider
import com.wire.kalium.logic.feature.message.MessageSender
import com.wire.kalium.logic.featureFlags.KaliumConfigs
import com.wire.kalium.logic.test_util.TestKaliumDispatcher
Expand All @@ -48,11 +52,6 @@ import kotlinx.coroutines.test.runTest
import kotlin.test.BeforeTest
import kotlin.test.Ignore
import kotlin.test.Test
import com.wire.kalium.logic.feature.call.usecase.ConversationClientsInCallUpdater
import com.wire.kalium.logic.feature.call.usecase.GetCallConversationTypeProvider
import com.wire.kalium.network.NetworkStateObserver
import com.wire.kalium.util.DateTimeUtil.toIsoDateTimeString
import kotlinx.datetime.Instant

class CallManagerTest {

Expand All @@ -77,6 +76,12 @@ class CallManagerTest {
@Mock
private val conversationRepository = mock(classOf<ConversationRepository>())

@Mock
private val subconversationRepository = mock(classOf<SubconversationRepository>())

@Mock
private val userConfigRepository = mock(classOf<UserConfigRepository>())

@Mock
private val federatedIdMapper = mock(classOf<FederatedIdMapper>())

Expand Down Expand Up @@ -109,6 +114,8 @@ class CallManagerTest {
currentClientIdProvider = currentClientIdProvider,
selfConversationIdProvider = selfConversationIdProvider,
conversationRepository = conversationRepository,
subconversationRepository = subconversationRepository,
userConfigRepository = userConfigRepository,
messageSender = messageSender,
kaliumDispatchers = dispatcher,
federatedIdMapper = federatedIdMapper,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@
package com.wire.kalium.logic.feature.call

import com.wire.kalium.logic.cache.SelfConversationIdProvider
import com.wire.kalium.logic.configuration.UserConfigRepository
import com.wire.kalium.logic.data.call.CallRepository
import com.wire.kalium.logic.data.call.VideoStateChecker
import com.wire.kalium.logic.data.call.mapper.CallMapper
import com.wire.kalium.logic.data.conversation.ConversationRepository
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.data.conversation.SubconversationRepository
import com.wire.kalium.logic.data.id.CurrentClientIdProvider
import com.wire.kalium.logic.data.id.FederatedIdMapper
import com.wire.kalium.logic.data.id.QualifiedID
import com.wire.kalium.logic.data.id.QualifiedIdMapper
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.data.user.UserRepository
import com.wire.kalium.logic.data.id.CurrentClientIdProvider
import com.wire.kalium.logic.feature.call.usecase.ConversationClientsInCallUpdater
import com.wire.kalium.logic.feature.call.usecase.GetCallConversationTypeProvider
import com.wire.kalium.logic.feature.message.MessageSender
Expand All @@ -43,6 +45,8 @@ actual class GlobalCallManager {
currentClientIdProvider: CurrentClientIdProvider,
selfConversationIdProvider: SelfConversationIdProvider,
conversationRepository: ConversationRepository,
subconversationRepository: SubconversationRepository,
userConfigRepository: UserConfigRepository,
messageSender: MessageSender,
callMapper: CallMapper,
federatedIdMapper: FederatedIdMapper,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,22 @@ import com.wire.kalium.calling.types.Uint32_t
import com.wire.kalium.logger.obfuscateId
import com.wire.kalium.logic.cache.SelfConversationIdProvider
import com.wire.kalium.logic.callingLogger
import com.wire.kalium.logic.configuration.UserConfigRepository
import com.wire.kalium.logic.data.call.CallClient
import com.wire.kalium.logic.data.call.CallClientList
import com.wire.kalium.logic.data.call.CallRepository
import com.wire.kalium.logic.data.call.CallStatus
import com.wire.kalium.logic.data.call.CallType
import com.wire.kalium.logic.data.call.EpochInfo
import com.wire.kalium.logic.data.call.MLSCallHelperImpl
import com.wire.kalium.logic.data.call.VideoState
import com.wire.kalium.logic.data.call.VideoStateChecker
import com.wire.kalium.logic.data.call.mapper.CallMapper
import com.wire.kalium.logic.data.call.mapper.ParticipantMapperImpl
import com.wire.kalium.logic.data.conversation.ClientId
import com.wire.kalium.logic.data.conversation.Conversation
import com.wire.kalium.logic.data.conversation.ConversationRepository
import com.wire.kalium.logic.data.conversation.SubconversationRepository
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.id.CurrentClientIdProvider
import com.wire.kalium.logic.data.id.FederatedIdMapper
Expand Down Expand Up @@ -105,6 +108,8 @@ class CallManagerImpl internal constructor(
private val videoStateChecker: VideoStateChecker,
private val conversationClientsInCallUpdater: ConversationClientsInCallUpdater,
private val getCallConversationType: GetCallConversationTypeProvider,
private val subconversationRepository: SubconversationRepository,
private val userConfigRepository: UserConfigRepository,
private val kaliumConfigs: KaliumConfigs,
private val json: Json = Json { ignoreUnknownKeys = true },
private val shouldRemoteMuteChecker: ShouldRemoteMuteChecker = ShouldRemoteMuteCheckerImpl(),
Expand Down Expand Up @@ -191,8 +196,16 @@ class CallManagerImpl internal constructor(
.keepingStrongReference(),
establishedCallHandler = OnEstablishedCall(callRepository, scope, qualifiedIdMapper)
.keepingStrongReference(),
closeCallHandler = OnCloseCall(callRepository, scope, qualifiedIdMapper)
.keepingStrongReference(),
closeCallHandler = OnCloseCall(
callRepository = callRepository,
mlsCallHelper = MLSCallHelperImpl(
callRepository = callRepository,
subconversationRepository = subconversationRepository,
userConfigRepository = userConfigRepository
),
scope = scope,
qualifiedIdMapper = qualifiedIdMapper
).keepingStrongReference(),
metricsHandler = metricsHandler,
callConfigRequestHandler = OnConfigRequest(calling, callRepository, scope)
.keepingStrongReference(),
Expand Down Expand Up @@ -464,6 +477,12 @@ class CallManagerImpl internal constructor(
qualifiedIdMapper = qualifiedIdMapper,
participantMapper = ParticipantMapperImpl(videoStateChecker, callMapper),
userRepository = userRepository,
mlsCallHelper = MLSCallHelperImpl(
callRepository = callRepository,
subconversationRepository = subconversationRepository,
userConfigRepository = userConfigRepository
),
endCall = { endCall(it) },
callingScope = scope
).keepingStrongReference()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ import com.wire.kalium.calling.ENVIRONMENT_DEFAULT
import com.wire.kalium.calling.callbacks.LogHandler
import com.wire.kalium.logic.cache.SelfConversationIdProvider
import com.wire.kalium.logic.callingLogger
import com.wire.kalium.logic.configuration.UserConfigRepository
import com.wire.kalium.logic.data.call.CallRepository
import com.wire.kalium.logic.data.call.VideoStateChecker
import com.wire.kalium.logic.data.call.mapper.CallMapper
import com.wire.kalium.logic.data.conversation.ConversationRepository
import com.wire.kalium.logic.data.conversation.SubconversationRepository
import com.wire.kalium.logic.data.id.FederatedIdMapper
import com.wire.kalium.logic.data.id.QualifiedID
import com.wire.kalium.logic.data.id.QualifiedIdMapper
Expand Down Expand Up @@ -79,6 +81,8 @@ actual class GlobalCallManager(
currentClientIdProvider: CurrentClientIdProvider,
selfConversationIdProvider: SelfConversationIdProvider,
conversationRepository: ConversationRepository,
subconversationRepository: SubconversationRepository,
userConfigRepository: UserConfigRepository,
messageSender: MessageSender,
callMapper: CallMapper,
federatedIdMapper: FederatedIdMapper,
Expand All @@ -103,6 +107,8 @@ actual class GlobalCallManager(
videoStateChecker = videoStateChecker,
conversationClientsInCallUpdater = conversationClientsInCallUpdater,
getCallConversationType = getCallConversationType,
subconversationRepository = subconversationRepository,
userConfigRepository = userConfigRepository,
kaliumConfigs = kaliumConfigs
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ import com.wire.kalium.calling.types.Uint32_t
import com.wire.kalium.logger.obfuscateId
import com.wire.kalium.logic.callingLogger
import com.wire.kalium.logic.data.call.CallRepository
import com.wire.kalium.logic.data.call.CallStatus
import com.wire.kalium.logic.data.call.MLSCallHelper
import com.wire.kalium.logic.data.conversation.Conversation
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.id.QualifiedIdMapper
import com.wire.kalium.logic.data.call.CallStatus
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

@Suppress("LongParameterList")
class OnCloseCall(
private val callRepository: CallRepository,
private val mlsCallHelper: MLSCallHelper,
private val scope: CoroutineScope,
private val qualifiedIdMapper: QualifiedIdMapper
) : CloseCallHandler {
Expand Down Expand Up @@ -67,15 +69,20 @@ class OnCloseCall(
status = callStatus
)

val conversationType =
callRepository.getCallMetadataProfile()[conversationIdWithDomain]?.conversationType

if (callRepository.getCallMetadataProfile()[conversationIdWithDomain]?.protocol is Conversation.ProtocolInfo.MLS) {
callRepository.leaveMlsConference(conversationIdWithDomain)
mlsCallHelper.handleCallTermination(conversationIdWithDomain, conversationType)
}

callingLogger.i("[OnCloseCall] -> ConversationId: ${conversationId.obfuscateId()} | callStatus: $callStatus")
}
}

private fun shouldPersistMissedCall(conversationId: ConversationId, callStatus: CallStatus): Boolean {
private fun shouldPersistMissedCall(
conversationId: ConversationId,
callStatus: CallStatus
): Boolean {
if (callStatus == CallStatus.MISSED)
return true
return callRepository.getCallMetadataProfile().data[conversationId]?.let {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,29 @@ import com.wire.kalium.logger.obfuscateId
import com.wire.kalium.logic.callingLogger
import com.wire.kalium.logic.data.call.CallParticipants
import com.wire.kalium.logic.data.call.CallRepository
import com.wire.kalium.logic.data.call.MLSCallHelper
import com.wire.kalium.logic.data.call.Participant
import com.wire.kalium.logic.data.call.mapper.ParticipantMapper
import com.wire.kalium.logic.data.id.ConversationId
import com.wire.kalium.logic.data.id.QualifiedIdMapper
import com.wire.kalium.logic.data.user.UserRepository
import com.wire.kalium.logic.functional.onFailure
import com.wire.kalium.logic.functional.onSuccess
import com.wire.kalium.logic.kaliumLogger
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json

// TODO: add tests for this class
@Suppress("LongParameterList")
class OnParticipantListChanged internal constructor(
private val callRepository: CallRepository,
private val qualifiedIdMapper: QualifiedIdMapper,
private val participantMapper: ParticipantMapper,
private val userRepository: UserRepository,
private val mlsCallHelper: MLSCallHelper,
private val endCall: suspend (conversationId: ConversationId) -> Unit,
private val callingScope: CoroutineScope
) : ParticipantChangedHandler {

Expand All @@ -65,6 +72,22 @@ class OnParticipantListChanged internal constructor(
participants.add(participant)
}
}
val callProtocol = callRepository.currentCallProtocol(conversationIdWithDomain)

val currentCall = callRepository.establishedCallsFlow().first().firstOrNull()
currentCall?.let {
val shouldEndSFTOneOnOneCall = mlsCallHelper.shouldEndSFTOneOnOneCall(
conversationId = conversationIdWithDomain,
callProtocol = callProtocol,
conversationType = it.conversationType,
newCallParticipants = participants,
previousCallParticipants = it.participants
)
if (shouldEndSFTOneOnOneCall) {
kaliumLogger.i("[onParticipantChanged] - Ending MLS call due to participant leaving")
endCall(conversationIdWithDomain)
}
}

callRepository.updateCallParticipants(
conversationId = conversationIdWithDomain,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ import com.wire.kalium.logic.data.conversation.ClientId
import com.wire.kalium.logic.data.conversation.Conversation
import com.wire.kalium.logic.data.conversation.ConversationDetails
import com.wire.kalium.logic.data.conversation.ConversationRepository
import com.wire.kalium.logic.data.conversation.EpochChangesObserver
import com.wire.kalium.logic.data.conversation.JoinSubconversationUseCase
import com.wire.kalium.logic.data.conversation.LeaveSubconversationUseCase
import com.wire.kalium.logic.data.conversation.MLSConversationRepository
import com.wire.kalium.logic.data.conversation.SubconversationRepository
import com.wire.kalium.logic.data.id.ConversationId
Expand All @@ -50,9 +53,6 @@ import com.wire.kalium.logic.data.team.TeamRepository
import com.wire.kalium.logic.data.user.UserId
import com.wire.kalium.logic.data.user.UserRepository
import com.wire.kalium.logic.di.MapperProvider
import com.wire.kalium.logic.data.conversation.JoinSubconversationUseCase
import com.wire.kalium.logic.data.conversation.LeaveSubconversationUseCase
import com.wire.kalium.logic.data.conversation.EpochChangesObserver
import com.wire.kalium.logic.functional.Either
import com.wire.kalium.logic.functional.flatMap
import com.wire.kalium.logic.functional.getOrNull
Expand Down Expand Up @@ -121,6 +121,7 @@ interface CallRepository {
fun updateParticipantsActiveSpeaker(conversationId: ConversationId, activeSpeakers: CallActiveSpeakers)
suspend fun getLastClosedCallCreatedByConversationId(conversationId: ConversationId): Flow<String?>
suspend fun updateOpenCallsToClosedStatus()
suspend fun leavePreviouslyJoinedMlsConferences()
suspend fun persistMissedCall(conversationId: ConversationId)
suspend fun joinMlsConference(
conversationId: ConversationId,
Expand All @@ -129,6 +130,7 @@ interface CallRepository {
suspend fun leaveMlsConference(conversationId: ConversationId)
suspend fun observeEpochInfo(conversationId: ConversationId): Either<CoreFailure, Flow<EpochInfo>>
suspend fun advanceEpoch(conversationId: ConversationId)
fun currentCallProtocol(conversationId: ConversationId): Conversation.ProtocolInfo?
}

@Suppress("LongParameterList", "TooManyFunctions")
Expand Down Expand Up @@ -426,7 +428,9 @@ internal class CallDataSource(
}
}

if (_callMetadataProfile.value[conversationId]?.protocol is Conversation.ProtocolInfo.MLS) {
if (_callMetadataProfile.value[conversationId]?.protocol is Conversation.ProtocolInfo.MLS &&
_callMetadataProfile.value[conversationId]?.conversationType == Conversation.Type.GROUP
) {
participants.forEach { participant ->
if (participant.hasEstablishedAudio) {
clearStaleParticipantTimeout(participant)
Expand Down Expand Up @@ -542,7 +546,7 @@ internal class CallDataSource(
}
}

private suspend fun leavePreviouslyJoinedMlsConferences() {
override suspend fun leavePreviouslyJoinedMlsConferences() {
callingLogger.i("Leaving previously joined MLS conferences")

callDAO.observeEstablishedCalls()
Expand Down Expand Up @@ -667,6 +671,9 @@ internal class CallDataSource(
} ?: callingLogger.w("[CallRepository] -> Requested new epoch but there's no conference subconversation")
}

override fun currentCallProtocol(conversationId: ConversationId): Conversation.ProtocolInfo? =
_callMetadataProfile.value.data[conversationId]?.protocol

companion object {
val STALE_PARTICIPANT_TIMEOUT = 190.toDuration(kotlin.time.DurationUnit.SECONDS)
}
Expand Down
Loading

0 comments on commit 58b3896

Please sign in to comment.