Asserted identity: handle if needed and use the data

This commit is contained in:
ganfra 2021-06-01 18:12:10 +02:00
parent 0098d435b3
commit 0eca809b83
6 changed files with 70 additions and 14 deletions

View File

@ -144,6 +144,10 @@ android {
buildConfigField "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy", "outboundSessionKeySharingStrategy", "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy.WhenTyping" buildConfigField "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy", "outboundSessionKeySharingStrategy", "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy.WhenTyping"
// If set, MSC3086 asserted identity messages sent on VoIP calls will cause the call to appear in the room corresponding to the asserted identity.
// This *must* only be set in trusted environments.
buildConfigField "Boolean", "handleCallAssertedIdentityEvents", "false"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// Keep abiFilter for the universalApk // Keep abiFilter for the universalApk

View File

@ -221,7 +221,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
views.callStatusText.setText(R.string.call_held_by_you) views.callStatusText.setText(R.string.call_held_by_you)
} else { } else {
views.callActionText.isInvisible = true views.callActionText.isInvisible = true
state.callInfo.otherUserItem?.let { state.callInfo?.opponentUserItem?.let {
views.callStatusText.text = getString(R.string.call_held_by_user, it.getBestName()) views.callStatusText.text = getString(R.string.call_held_by_user, it.getBestName())
} }
} }
@ -255,7 +255,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
} }
private fun configureCallInfo(state: VectorCallViewState, blurAvatar: Boolean = false) { private fun configureCallInfo(state: VectorCallViewState, blurAvatar: Boolean = false) {
state.callInfo.otherUserItem?.let { state.callInfo?.opponentUserItem?.let {
val colorFilter = ContextCompat.getColor(this, R.color.bg_call_screen) val colorFilter = ContextCompat.getColor(this, R.color.bg_call_screen)
avatarRenderer.renderBlur(it, views.bgCallView, sampling = 20, rounded = false, colorFilter = colorFilter) avatarRenderer.renderBlur(it, views.bgCallView, sampling = 20, rounded = false, colorFilter = colorFilter)
if (state.transferee is VectorCallViewState.TransfereeState.NoTransferee) { if (state.transferee is VectorCallViewState.TransfereeState.NoTransferee) {
@ -269,13 +269,13 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
avatarRenderer.render(it, views.otherMemberAvatar) avatarRenderer.render(it, views.otherMemberAvatar)
} }
} }
if (state.otherKnownCallInfo?.otherUserItem == null) { if (state.otherKnownCallInfo?.opponentUserItem == null) {
views.otherKnownCallLayout.isVisible = false views.otherKnownCallLayout.isVisible = false
} else { } else {
val otherCall = callManager.getCallById(state.otherKnownCallInfo.callId) val otherCall = callManager.getCallById(state.otherKnownCallInfo.callId)
val colorFilter = ContextCompat.getColor(this, R.color.bg_call_screen) val colorFilter = ContextCompat.getColor(this, R.color.bg_call_screen)
avatarRenderer.renderBlur( avatarRenderer.renderBlur(
matrixItem = state.otherKnownCallInfo.otherUserItem, matrixItem = state.otherKnownCallInfo.opponentUserItem,
imageView = views.otherKnownCallAvatarView, imageView = views.otherKnownCallAvatarView,
sampling = 20, sampling = 20,
rounded = false, rounded = false,

View File

@ -34,11 +34,13 @@ import im.vector.app.features.call.webrtc.getOpponentAsMatrixItem
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.Session
import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.CallState
import org.matrix.android.sdk.api.session.call.MxCall import org.matrix.android.sdk.api.session.call.MxCall
import org.matrix.android.sdk.api.session.call.MxPeerConnectionState import org.matrix.android.sdk.api.session.call.MxPeerConnectionState
import org.matrix.android.sdk.api.session.room.model.call.supportCallTransfer import org.matrix.android.sdk.api.session.room.model.call.supportCallTransfer
import org.matrix.android.sdk.api.util.MatrixItem
class VectorCallViewModel @AssistedInject constructor( class VectorCallViewModel @AssistedInject constructor(
@Assisted initialState: VectorCallViewState, @Assisted initialState: VectorCallViewState,
@ -87,6 +89,12 @@ class VectorCallViewModel @AssistedInject constructor(
} }
} }
override fun assertedIdentityChanged(){
setState {
copy(callInfo = call?.extractCallInfo())
}
}
override fun onStateUpdate(call: MxCall) { override fun onStateUpdate(call: MxCall) {
val callState = call.state val callState = call.state
if (callState is CallState.Connected && callState.iceConnectionState == MxPeerConnectionState.CONNECTED) { if (callState is CallState.Connected && callState.iceConnectionState == MxPeerConnectionState.CONNECTED) {
@ -160,8 +168,7 @@ class VectorCallViewModel @AssistedInject constructor(
if (otherCall == null) { if (otherCall == null) {
copy(otherKnownCallInfo = null) copy(otherKnownCallInfo = null)
} else { } else {
val otherUserItem = otherCall.getOpponentAsMatrixItem(session) copy(otherKnownCallInfo = otherCall.extractCallInfo())
copy(otherKnownCallInfo = VectorCallViewState.CallInfo(otherCall.callId, otherUserItem))
} }
} }
} }
@ -175,7 +182,6 @@ class VectorCallViewModel @AssistedInject constructor(
} else { } else {
call = webRtcCall call = webRtcCall
callManager.addCurrentCallListener(currentCallListener) callManager.addCurrentCallListener(currentCallListener)
val item = webRtcCall.getOpponentAsMatrixItem(session)
webRtcCall.addListener(callListener) webRtcCall.addListener(callListener)
val currentSoundDevice = callManager.audioManager.selectedDevice val currentSoundDevice = callManager.audioManager.selectedDevice
if (currentSoundDevice == CallAudioManager.Device.PHONE) { if (currentSoundDevice == CallAudioManager.Device.PHONE) {
@ -185,7 +191,7 @@ class VectorCallViewModel @AssistedInject constructor(
copy( copy(
isVideoCall = webRtcCall.mxCall.isVideoCall, isVideoCall = webRtcCall.mxCall.isVideoCall,
callState = Success(webRtcCall.mxCall.state), callState = Success(webRtcCall.mxCall.state),
callInfo = VectorCallViewState.CallInfo(callId, item), callInfo = webRtcCall.extractCallInfo(),
device = currentSoundDevice ?: CallAudioManager.Device.PHONE, device = currentSoundDevice ?: CallAudioManager.Device.PHONE,
isLocalOnHold = webRtcCall.isLocalOnHold, isLocalOnHold = webRtcCall.isLocalOnHold,
isRemoteOnHold = webRtcCall.remoteOnHold, isRemoteOnHold = webRtcCall.remoteOnHold,
@ -202,6 +208,22 @@ class VectorCallViewModel @AssistedInject constructor(
} }
} }
private fun WebRtcCall.extractCallInfo(): VectorCallViewState.CallInfo{
val assertedIdentity = this.remoteAssertedIdentity
val matrixItem = if(assertedIdentity != null){
val userId = if (MatrixPatterns.isUserId(assertedIdentity.id)) {
assertedIdentity.id!!
} else {
// Need an id starting with @
"@${assertedIdentity.displayName}"
}
MatrixItem.UserItem(userId,assertedIdentity.displayName, assertedIdentity.avatarUrl)
}else {
getOpponentAsMatrixItem(session)
}
return VectorCallViewState.CallInfo(callId, matrixItem)
}
override fun onCleared() { override fun onCleared() {
callManager.removeCurrentCallListener(currentCallListener) callManager.removeCurrentCallListener(currentCallListener)
call?.removeListener(callListener) call?.removeListener(callListener)

View File

@ -20,6 +20,7 @@ import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.Uninitialized
import im.vector.app.features.call.audio.CallAudioManager import im.vector.app.features.call.audio.CallAudioManager
import org.matrix.android.sdk.api.MatrixPatterns
import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.CallState
import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
@ -39,7 +40,7 @@ data class VectorCallViewState(
val availableDevices: Set<CallAudioManager.Device> = emptySet(), val availableDevices: Set<CallAudioManager.Device> = emptySet(),
val callState: Async<CallState> = Uninitialized, val callState: Async<CallState> = Uninitialized,
val otherKnownCallInfo: CallInfo? = null, val otherKnownCallInfo: CallInfo? = null,
val callInfo: CallInfo = CallInfo(callId), val callInfo: CallInfo? = null,
val formattedDuration: String = "", val formattedDuration: String = "",
val canOpponentBeTransferred: Boolean = false, val canOpponentBeTransferred: Boolean = false,
val transferee: TransfereeState = TransfereeState.NoTransferee val transferee: TransfereeState = TransfereeState.NoTransferee
@ -53,7 +54,7 @@ data class VectorCallViewState(
data class CallInfo( data class CallInfo(
val callId: String, val callId: String,
val otherUserItem: MatrixItem? = null val opponentUserItem: MatrixItem? = null,
) )
constructor(callArgs: CallArgs) : this( constructor(callArgs: CallArgs) : this(

View File

@ -27,6 +27,7 @@ import im.vector.app.features.call.CameraProxy
import im.vector.app.features.call.CameraType import im.vector.app.features.call.CameraType
import im.vector.app.features.call.CaptureFormat import im.vector.app.features.call.CaptureFormat
import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.VectorCallActivity
import im.vector.app.features.call.lookup.sipNativeLookup
import im.vector.app.features.call.utils.asWebRTC import im.vector.app.features.call.utils.asWebRTC
import im.vector.app.features.call.utils.awaitCreateAnswer import im.vector.app.features.call.utils.awaitCreateAnswer
import im.vector.app.features.call.utils.awaitCreateOffer import im.vector.app.features.call.utils.awaitCreateOffer
@ -882,12 +883,36 @@ class WebRtcCall(
} }
fun onCallAssertedIdentityReceived(callAssertedIdentityContent: CallAssertedIdentityContent) { fun onCallAssertedIdentityReceived(callAssertedIdentityContent: CallAssertedIdentityContent) {
if (callAssertedIdentityContent.assertedIdentity == null) return sessionScope?.launch(dispatcher) {
remoteAssertedIdentity = callAssertedIdentityContent.assertedIdentity val session = sessionProvider.get() ?: return@launch
val newAssertedIdentity = callAssertedIdentityContent.assertedIdentity ?: return@launch
if (newAssertedIdentity.id == null && newAssertedIdentity.displayName == null) {
Timber.v("Asserted identity received with no relevant information, skip")
return@launch
}
remoteAssertedIdentity = newAssertedIdentity
if (newAssertedIdentity.id != null) {
val nativeUserId = session.sipNativeLookup(newAssertedIdentity.id!!).firstOrNull()?.userId
if (nativeUserId != null) {
val resolvedUser = tryOrNull {
session.resolveUser(nativeUserId)
}
if (resolvedUser != null) {
remoteAssertedIdentity = newAssertedIdentity.copy(
id = nativeUserId,
avatarUrl = resolvedUser.avatarUrl,
displayName = resolvedUser.displayName
)
} else {
remoteAssertedIdentity = newAssertedIdentity.copy(id = nativeUserId)
}
}
}
listeners.forEach { listeners.forEach {
tryOrNull { it.assertedIdentityChanged() } tryOrNull { it.assertedIdentityChanged() }
} }
} }
}
// MxCall.StateListener // MxCall.StateListener

View File

@ -21,6 +21,7 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.OnLifecycleEvent import androidx.lifecycle.OnLifecycleEvent
import im.vector.app.ActiveSessionDataSource import im.vector.app.ActiveSessionDataSource
import im.vector.app.BuildConfig
import im.vector.app.core.services.CallService import im.vector.app.core.services.CallService
import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.VectorCallActivity
import im.vector.app.features.call.audio.CallAudioManager import im.vector.app.features.call.audio.CallAudioManager
@ -423,6 +424,9 @@ class WebRtcCallManager @Inject constructor(
} }
override fun onCallAssertedIdentityReceived(callAssertedIdentityContent: CallAssertedIdentityContent) { override fun onCallAssertedIdentityReceived(callAssertedIdentityContent: CallAssertedIdentityContent) {
if(!BuildConfig.handleCallAssertedIdentityEvents){
return
}
val call = callsByCallId[callAssertedIdentityContent.callId] val call = callsByCallId[callAssertedIdentityContent.callId]
?: return Unit.also { ?: return Unit.also {
Timber.w("onCallAssertedIdentityReceived for non active call? ${callAssertedIdentityContent.callId}") Timber.w("onCallAssertedIdentityReceived for non active call? ${callAssertedIdentityContent.callId}")