Ask for permission before starting call

This commit is contained in:
Valere 2020-06-18 23:37:54 +02:00
parent b27eead016
commit 25fe56116c
4 changed files with 63 additions and 17 deletions

View File

@ -567,7 +567,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
}
}
fun startOutgoingCall(context: Context, signalingRoomId: String, otherUserId: String, isVideoCall: Boolean) {
fun startOutgoingCall(signalingRoomId: String, otherUserId: String, isVideoCall: Boolean) {
executor.execute {
if (peerConnectionFactory == null) {
createPeerConnectionFactory()
@ -584,7 +584,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
val name = sessionHolder.getSafeActiveSession()?.getUser(createdCall.otherUserId)?.getBestName()
?: createdCall.otherUserId
CallService.onOutgoingCallRinging(
context = context,
context = context.applicationContext,
isVideo = createdCall.isVideoCall,
roomName = name,
roomId = createdCall.roomId,
@ -596,7 +596,7 @@ class WebRtcPeerConnectionManager @Inject constructor(
}
// start the activity now
context.startActivity(VectorCallActivity.newIntent(context, createdCall))
context.applicationContext.startActivity(VectorCallActivity.newIntent(context, createdCall))
}
override fun onCallIceCandidateReceived(mxCall: MxCall, iceCandidatesContent: CallCandidatesContent) {

View File

@ -68,7 +68,7 @@ sealed class RoomDetailAction : VectorViewModelAction {
object ClearSendQueue : RoomDetailAction()
object ResendAll : RoomDetailAction()
object StartCall : RoomDetailAction()
data class StartCall(val isVideo: Boolean) : RoomDetailAction()
data class AcceptVerificationRequest(val transactionId: String, val otherUserId: String) : RoomDetailAction()
data class DeclineVerificationRequest(val transactionId: String, val otherUserId: String) : RoomDetailAction()

View File

@ -107,6 +107,8 @@ import im.vector.riotx.core.ui.views.JumpToReadMarkerView
import im.vector.riotx.core.ui.views.NotificationAreaView
import im.vector.riotx.core.utils.Debouncer
import im.vector.riotx.core.utils.KeyboardStateUtils
import im.vector.riotx.core.utils.PERMISSIONS_FOR_AUDIO_IP_CALL
import im.vector.riotx.core.utils.PERMISSIONS_FOR_VIDEO_IP_CALL
import im.vector.riotx.core.utils.PERMISSIONS_FOR_WRITING_FILES
import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_DOWNLOAD_FILE
import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_INCOMING_URI
@ -120,6 +122,8 @@ import im.vector.riotx.core.utils.createJSonViewerStyleProvider
import im.vector.riotx.core.utils.createUIHandler
import im.vector.riotx.core.utils.getColorFromUserId
import im.vector.riotx.core.utils.isValidUrl
import im.vector.riotx.core.utils.onPermissionResultAudioIpCall
import im.vector.riotx.core.utils.onPermissionResultVideoIpCall
import im.vector.riotx.core.utils.openUrlInExternalBrowser
import im.vector.riotx.core.utils.saveMedia
import im.vector.riotx.core.utils.shareMedia
@ -132,7 +136,6 @@ import im.vector.riotx.features.attachments.preview.AttachmentsPreviewArgs
import im.vector.riotx.features.attachments.toGroupedContentAttachmentData
import im.vector.riotx.features.call.SharedActiveCallViewModel
import im.vector.riotx.features.call.VectorCallActivity
import im.vector.riotx.features.call.WebRtcPeerConnectionManager
import im.vector.riotx.features.command.Command
import im.vector.riotx.features.crypto.keysbackup.restore.KeysBackupRestoreActivity
import im.vector.riotx.features.crypto.util.toImageRes
@ -202,8 +205,7 @@ class RoomDetailFragment @Inject constructor(
val roomDetailViewModelFactory: RoomDetailViewModel.Factory,
private val eventHtmlRenderer: EventHtmlRenderer,
private val vectorPreferences: VectorPreferences,
private val colorProvider: ColorProvider,
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager) :
private val colorProvider: ColorProvider) :
VectorBaseFragment(),
TimelineEventController.Callback,
VectorInviteView.Callback,
@ -215,6 +217,9 @@ class RoomDetailFragment @Inject constructor(
companion object {
private const val AUDIO_CALL_PERMISSION_REQUEST_CODE = 1
private const val VIDEO_CALL_PERMISSION_REQUEST_CODE = 2
/**
* Sanitize the display name.
*
@ -503,22 +508,22 @@ class RoomDetailFragment @Inject constructor(
}
R.id.voice_call,
R.id.video_call -> {
roomDetailViewModel.getOtherUserIds()?.firstOrNull()?.let {
// TODO CALL We should check/ask for permission here first
val activeCall = sharedCallActionViewModel.activeCall.value
val isVideoCall = item.itemId == R.id.video_call
if (activeCall != null) {
// resume existing if same room, if not prompt to kill and then restart new call?
if (activeCall.roomId == roomDetailArgs.roomId) {
onTapToReturnToCall()
} else {
// TODO might not work well, and should prompt
webRtcPeerConnectionManager.endCall()
webRtcPeerConnectionManager.startOutgoingCall(requireContext(), roomDetailArgs.roomId, it, item.itemId == R.id.video_call)
}
// else {
// TODO might not work well, and should prompt
// webRtcPeerConnectionManager.endCall()
// safeStartCall(it, isVideoCall)
// }
} else {
webRtcPeerConnectionManager.startOutgoingCall(requireContext(), roomDetailArgs.roomId, it, item.itemId == R.id.video_call)
safeStartCall(isVideoCall)
}
}
true
}
else -> super.onOptionsItemSelected(item)
@ -536,6 +541,22 @@ class RoomDetailFragment @Inject constructor(
.show()
}
private fun safeStartCall(isVideoCall: Boolean) {
val startCallAction = RoomDetailAction.StartCall(isVideoCall)
roomDetailViewModel.pendingAction = startCallAction
if (isVideoCall) {
if (checkPermissions(PERMISSIONS_FOR_VIDEO_IP_CALL, this, VIDEO_CALL_PERMISSION_REQUEST_CODE, R.string.permissions_rationale_msg_camera_and_audio)) {
roomDetailViewModel.pendingAction = null
roomDetailViewModel.handle(startCallAction)
}
} else {
if (checkPermissions(PERMISSIONS_FOR_AUDIO_IP_CALL, this, AUDIO_CALL_PERMISSION_REQUEST_CODE, R.string.permissions_rationale_msg_record_audio)) {
roomDetailViewModel.pendingAction = null
roomDetailViewModel.handle(startCallAction)
}
}
}
private fun renderRegularMode(text: String) {
autoCompleter.exitSpecialMode()
composerLayout.collapse()
@ -1130,6 +1151,22 @@ class RoomDetailFragment @Inject constructor(
launchAttachmentProcess(pendingType)
}
}
AUDIO_CALL_PERMISSION_REQUEST_CODE -> {
if (onPermissionResultAudioIpCall(requireContext(), grantResults)) {
(roomDetailViewModel.pendingAction as? RoomDetailAction.StartCall)?.let {
roomDetailViewModel.pendingAction = null
roomDetailViewModel.handle(it)
}
}
}
VIDEO_CALL_PERMISSION_REQUEST_CODE -> {
if (onPermissionResultVideoIpCall(requireContext(), grantResults)) {
(roomDetailViewModel.pendingAction as? RoomDetailAction.StartCall)?.let {
roomDetailViewModel.pendingAction = null
roomDetailViewModel.handle(it)
}
}
}
}
} else {
// Reset all pending data

View File

@ -67,6 +67,7 @@ import im.vector.riotx.core.platform.VectorViewModel
import im.vector.riotx.core.resources.StringProvider
import im.vector.riotx.core.resources.UserPreferencesProvider
import im.vector.riotx.core.utils.subscribeLogError
import im.vector.riotx.features.call.WebRtcPeerConnectionManager
import im.vector.riotx.features.command.CommandParser
import im.vector.riotx.features.command.ParsedCommand
import im.vector.riotx.features.crypto.verification.SupportedVerificationMethodsProvider
@ -97,7 +98,8 @@ class RoomDetailViewModel @AssistedInject constructor(
private val rainbowGenerator: RainbowGenerator,
private val session: Session,
private val supportedVerificationMethodsProvider: SupportedVerificationMethodsProvider,
private val stickerPickerActionHandler: StickerPickerActionHandler
private val stickerPickerActionHandler: StickerPickerActionHandler,
private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager
) : VectorViewModel<RoomDetailViewState, RoomDetailAction, RoomDetailViewEvents>(initialState), Timeline.Listener {
private val room = session.getRoom(initialState.roomId)!!
@ -255,13 +257,20 @@ class RoomDetailViewModel @AssistedInject constructor(
is RoomDetailAction.ResumeVerification -> handleResumeRequestVerification(action)
is RoomDetailAction.ReRequestKeys -> handleReRequestKeys(action)
is RoomDetailAction.SelectStickerAttachment -> handleSelectStickerAttachment()
}
is RoomDetailAction.StartCall -> handleStartCall(action)
}.exhaustive
}
private fun handleSendSticker(action: RoomDetailAction.SendSticker) {
room.sendEvent(EventType.STICKER, action.stickerContent.toContent())
}
private fun handleStartCall(action: RoomDetailAction.StartCall) {
room.roomSummary()?.otherMemberIds?.firstOrNull()?.let {
webRtcPeerConnectionManager.startOutgoingCall(room.roomId, it, action.isVideo)
}
}
private fun handleSelectStickerAttachment() {
viewModelScope.launch {
val viewEvent = stickerPickerActionHandler.handle()
@ -369,7 +378,7 @@ class RoomDetailViewModel @AssistedInject constructor(
}
fun isMenuItemVisible(@IdRes itemId: Int) = when (itemId) {
R.id.clear_message_queue ->
R.id.clear_message_queue ->
// For now always disable when not in developer mode, worker cancellation is not working properly
timeline.pendingEventCount() > 0 && vectorPreferences.developerMode()
R.id.resend_all -> timeline.failedToDeliverEventCount() > 0