Call: make PiP works with 2 calls

This commit is contained in:
ganfra 2021-08-18 10:52:19 +02:00
parent d3e4a3c010
commit 799cd99176
5 changed files with 100 additions and 74 deletions

View File

@ -93,7 +93,6 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
} }
private val callViewModel: VectorCallViewModel by viewModel() private val callViewModel: VectorCallViewModel by viewModel()
private lateinit var callArgs: CallArgs
@Inject lateinit var callManager: WebRtcCallManager @Inject lateinit var callManager: WebRtcCallManager
@Inject lateinit var viewModelFactory: VectorCallViewModel.Factory @Inject lateinit var viewModelFactory: VectorCallViewModel.Factory
@ -123,13 +122,6 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
window.navigationBarColor = Color.BLACK window.navigationBarColor = Color.BLACK
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (intent.hasExtra(MvRx.KEY_ARG)) {
callArgs = intent.getParcelableExtra(MvRx.KEY_ARG)!!
} else {
Timber.tag(loggerTag.value).e("missing callArgs for VectorCall Activity")
finish()
}
Timber.tag(loggerTag.value).v("EXTRA_MODE is ${intent.getStringExtra(EXTRA_MODE)}") Timber.tag(loggerTag.value).v("EXTRA_MODE is ${intent.getStringExtra(EXTRA_MODE)}")
if (intent.getStringExtra(EXTRA_MODE) == INCOMING_RINGING) { if (intent.getStringExtra(EXTRA_MODE) == INCOMING_RINGING) {
turnScreenOnAndKeyguardOff() turnScreenOnAndKeyguardOff()
@ -152,17 +144,28 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
} }
.disposeOnDestroy() .disposeOnDestroy()
if (callArgs.isVideoCall) { callViewModel.selectSubscribe(this, VectorCallViewState::callId, VectorCallViewState::isVideoCall) { _, isVideoCall ->
if (checkPermissions(PERMISSIONS_FOR_VIDEO_IP_CALL, this, permissionCameraLauncher, R.string.permissions_rationale_msg_camera_and_audio)) { if (isVideoCall) {
start() if (checkPermissions(PERMISSIONS_FOR_VIDEO_IP_CALL, this, permissionCameraLauncher, R.string.permissions_rationale_msg_camera_and_audio)) {
} setupRenderersIfNeeded()
} else { }
if (checkPermissions(PERMISSIONS_FOR_AUDIO_IP_CALL, this, permissionCameraLauncher, R.string.permissions_rationale_msg_record_audio)) { } else {
start() if (checkPermissions(PERMISSIONS_FOR_AUDIO_IP_CALL, this, permissionCameraLauncher, R.string.permissions_rationale_msg_record_audio)) {
setupRenderersIfNeeded()
}
} }
} }
} }
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
intent?.takeIf { it.hasExtra(MvRx.KEY_ARG) }
?.let { intent.getParcelableExtra<CallArgs>(MvRx.KEY_ARG) }
?.let {
callViewModel.handle(VectorCallViewActions.SwitchCall(it))
}
}
override fun getMenuRes() = R.menu.vector_call override fun getMenuRes() = R.menu.vector_call
override fun onUserLeaveHint() { override fun onUserLeaveHint() {
@ -211,13 +214,19 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
} }
override fun onDestroy() { override fun onDestroy() {
callManager.getCallById(callArgs.callId)?.detachRenderers(listOf(views.pipRenderer, views.fullscreenRenderer)) detachRenderersIfNeeded()
turnScreenOffAndKeyguardOn()
super.onDestroy()
}
private fun detachRenderersIfNeeded() {
val callId = withState(callViewModel) { it.callId }
callManager.getCallById(callId)?.detachRenderers(listOf(views.pipRenderer, views.fullscreenRenderer))
if (surfaceRenderersAreInitialized) { if (surfaceRenderersAreInitialized) {
views.pipRenderer.release() views.pipRenderer.release()
views.fullscreenRenderer.release() views.fullscreenRenderer.release()
surfaceRenderersAreInitialized = false
} }
turnScreenOffAndKeyguardOn()
super.onDestroy()
} }
private fun renderState(state: VectorCallViewState) { private fun renderState(state: VectorCallViewState) {
@ -245,21 +254,21 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
is CallState.Idle, is CallState.Idle,
is CallState.CreateOffer, is CallState.CreateOffer,
is CallState.LocalRinging, is CallState.LocalRinging,
is CallState.Dialing -> { is CallState.Dialing -> {
views.fullscreenRenderer.isVisible = false views.fullscreenRenderer.isVisible = false
views.pipRendererWrapper.isVisible = false views.pipRendererWrapper.isVisible = false
views.callInfoGroup.isVisible = true views.callInfoGroup.isVisible = true
views.callToolbar.setSubtitle(R.string.call_ringing) views.callToolbar.setSubtitle(R.string.call_ringing)
configureCallInfo(state) configureCallInfo(state)
} }
is CallState.Answering -> { is CallState.Answering -> {
views.fullscreenRenderer.isVisible = false views.fullscreenRenderer.isVisible = false
views.pipRendererWrapper.isVisible = false views.pipRendererWrapper.isVisible = false
views.callInfoGroup.isVisible = true views.callInfoGroup.isVisible = true
views.callToolbar.setSubtitle(R.string.call_connecting) views.callToolbar.setSubtitle(R.string.call_connecting)
configureCallInfo(state) configureCallInfo(state)
} }
is CallState.Connected -> { is CallState.Connected -> {
views.callToolbar.subtitle = state.formattedDuration views.callToolbar.subtitle = state.formattedDuration
if (callState.iceConnectionState == MxPeerConnectionState.CONNECTED) { if (callState.iceConnectionState == MxPeerConnectionState.CONNECTED) {
if (state.isLocalOnHold || state.isRemoteOnHold) { if (state.isLocalOnHold || state.isRemoteOnHold) {
@ -291,7 +300,7 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
configureCallInfo(state) configureCallInfo(state)
} else { } else {
configureCallInfo(state) configureCallInfo(state)
if (callArgs.isVideoCall) { if (state.isVideoCall) {
views.fullscreenRenderer.isVisible = true views.fullscreenRenderer.isVisible = true
views.pipRendererWrapper.isVisible = true views.pipRendererWrapper.isVisible = true
views.callInfoGroup.isVisible = false views.callInfoGroup.isVisible = false
@ -311,10 +320,10 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
views.callToolbar.setSubtitle(R.string.call_connecting) views.callToolbar.setSubtitle(R.string.call_connecting)
} }
} }
is CallState.Ended -> { is CallState.Ended -> {
finish() finish()
} }
null -> { null -> {
} }
} }
} }
@ -331,12 +340,12 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
is CallState.CreateOffer, is CallState.CreateOffer,
is CallState.LocalRinging, is CallState.LocalRinging,
is CallState.Dialing, is CallState.Dialing,
is CallState.Answering -> { is CallState.Answering -> {
views.fullscreenRenderer.isVisible = false views.fullscreenRenderer.isVisible = false
views.callInfoGroup.isVisible = false views.callInfoGroup.isVisible = false
// showLoading() // showLoading()
} }
is CallState.Connected -> { is CallState.Connected -> {
if (callState.iceConnectionState == MxPeerConnectionState.CONNECTED) { if (callState.iceConnectionState == MxPeerConnectionState.CONNECTED) {
if (state.isLocalOnHold || state.isRemoteOnHold) { if (state.isLocalOnHold || state.isRemoteOnHold) {
views.smallIsHeldIcon.isVisible = true views.smallIsHeldIcon.isVisible = true
@ -403,10 +412,13 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
views.otherKnownCallLayout.setOnClickListener { views.otherKnownCallLayout.setOnClickListener {
withState(callViewModel) { withState(callViewModel) {
val otherCall = callManager.getCallById(it.otherKnownCallInfo?.callId ?: "") ?: return@withState val otherCall = callManager.getCallById(it.otherKnownCallInfo?.callId ?: "") ?: return@withState
startActivity(newIntent(this, otherCall, null)) val callArgs = CallArgs(otherCall.nativeRoomId, otherCall.callId, otherCall.mxCall.opponentUserId, !otherCall.mxCall.isOutgoing, otherCall.mxCall.isVideoCall)
finish() callViewModel.handle(VectorCallViewActions.SwitchCall(callArgs))
} }
} }
views.pipRendererWrapper.setOnClickListener {
callViewModel.handle(VectorCallViewActions.ToggleCamera)
}
pipDraggrableView = views.pipRendererWrapper.setupDraggable() pipDraggrableView = views.pipRendererWrapper.setupDraggable()
.setStickyMode(DraggableView.Mode.STICKY_XY) .setStickyMode(DraggableView.Mode.STICKY_XY)
.build() .build()
@ -418,14 +430,15 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
private val permissionCameraLauncher = registerForPermissionsResult { allGranted, _ -> private val permissionCameraLauncher = registerForPermissionsResult { allGranted, _ ->
if (allGranted) { if (allGranted) {
start() setupRenderersIfNeeded()
} else { } else {
// TODO display something // TODO display something
finish() finish()
} }
} }
private fun start() { private fun setupRenderersIfNeeded() {
detachRenderersIfNeeded()
rootEglBase = EglUtils.rootEglBase ?: return Unit.also { rootEglBase = EglUtils.rootEglBase ?: return Unit.also {
Timber.tag(loggerTag.value).v("rootEglBase is null") Timber.tag(loggerTag.value).v("rootEglBase is null")
finish() finish()
@ -443,11 +456,10 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
views.fullscreenRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL) views.fullscreenRenderer.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL)
views.fullscreenRenderer.setEnableHardwareScaler(true /* enabled */) views.fullscreenRenderer.setEnableHardwareScaler(true /* enabled */)
callManager.getCallById(callArgs.callId)?.attachViewRenderers(views.pipRenderer, views.fullscreenRenderer, val callId = withState(callViewModel) { it.callId }
intent.getStringExtra(EXTRA_MODE)?.takeIf { isFirstCreation() }) callManager.getCallById(callId)?.also { webRtcCall ->
webRtcCall.attachViewRenderers(views.pipRenderer, views.fullscreenRenderer, intent.getStringExtra(EXTRA_MODE))
views.pipRendererWrapper.setOnClickListener { intent.removeExtra(EXTRA_MODE)
callViewModel.handle(VectorCallViewActions.ToggleCamera)
} }
surfaceRenderersAreInitialized = true surfaceRenderersAreInitialized = true
} }
@ -467,7 +479,8 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
}.show(supportFragmentManager, FRAGMENT_DIAL_PAD_TAG) }.show(supportFragmentManager, FRAGMENT_DIAL_PAD_TAG)
} }
is VectorCallViewEvents.ShowCallTransferScreen -> { is VectorCallViewEvents.ShowCallTransferScreen -> {
navigator.openCallTransfer(this, callArgs.callId) val callId = withState(callViewModel) { it.callId }
navigator.openCallTransfer(this, callId)
} }
null -> { null -> {
} }
@ -486,39 +499,6 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
.show() .show()
} }
companion object {
private const val EXTRA_MODE = "EXTRA_MODE"
private const val FRAGMENT_DIAL_PAD_TAG = "FRAGMENT_DIAL_PAD_TAG"
const val OUTGOING_CREATED = "OUTGOING_CREATED"
const val INCOMING_RINGING = "INCOMING_RINGING"
const val INCOMING_ACCEPT = "INCOMING_ACCEPT"
fun newIntent(context: Context, call: WebRtcCall, mode: String?): Intent {
return Intent(context, VectorCallActivity::class.java).apply {
// what could be the best flags?
flags = Intent.FLAG_ACTIVITY_NEW_TASK
putExtra(MvRx.KEY_ARG, CallArgs(call.nativeRoomId, call.callId, call.mxCall.opponentUserId, !call.mxCall.isOutgoing, call.mxCall.isVideoCall))
putExtra(EXTRA_MODE, mode)
}
}
fun newIntent(context: Context,
callId: String,
signalingRoomId: String,
otherUserId: String,
isIncomingCall: Boolean,
isVideoCall: Boolean,
mode: String?): Intent {
return Intent(context, VectorCallActivity::class.java).apply {
// what could be the best flags?
flags = FLAG_ACTIVITY_CLEAR_TOP
putExtra(MvRx.KEY_ARG, CallArgs(signalingRoomId, callId, otherUserId, isIncomingCall, isVideoCall))
putExtra(EXTRA_MODE, mode)
}
}
}
override fun didTapAudioSettings() { override fun didTapAudioSettings() {
CallSoundDeviceChooserBottomSheet().show(supportFragmentManager, "SoundDeviceChooser") CallSoundDeviceChooserBottomSheet().show(supportFragmentManager, "SoundDeviceChooser")
} }
@ -544,7 +524,8 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
} }
private fun returnToChat() { private fun returnToChat() {
val args = RoomDetailArgs(callArgs.signalingRoomId) val roomId = withState(callViewModel) { it.roomId }
val args = RoomDetailArgs(roomId)
val intent = RoomDetailActivity.newIntent(this, args).apply { val intent = RoomDetailActivity.newIntent(this, args).apply {
flags = FLAG_ACTIVITY_CLEAR_TOP flags = FLAG_ACTIVITY_CLEAR_TOP
} }
@ -592,4 +573,37 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
) )
} }
} }
companion object {
private const val EXTRA_MODE = "EXTRA_MODE"
private const val FRAGMENT_DIAL_PAD_TAG = "FRAGMENT_DIAL_PAD_TAG"
const val OUTGOING_CREATED = "OUTGOING_CREATED"
const val INCOMING_RINGING = "INCOMING_RINGING"
const val INCOMING_ACCEPT = "INCOMING_ACCEPT"
fun newIntent(context: Context, call: WebRtcCall, mode: String?): Intent {
return Intent(context, VectorCallActivity::class.java).apply {
// what could be the best flags?
flags = Intent.FLAG_ACTIVITY_NEW_TASK
putExtra(MvRx.KEY_ARG, CallArgs(call.nativeRoomId, call.callId, call.mxCall.opponentUserId, !call.mxCall.isOutgoing, call.mxCall.isVideoCall))
putExtra(EXTRA_MODE, mode)
}
}
fun newIntent(context: Context,
callId: String,
signalingRoomId: String,
otherUserId: String,
isIncomingCall: Boolean,
isVideoCall: Boolean,
mode: String?): Intent {
return Intent(context, VectorCallActivity::class.java).apply {
// what could be the best flags?
flags = Intent.FLAG_ACTIVITY_NEW_TASK
putExtra(MvRx.KEY_ARG, CallArgs(signalingRoomId, callId, otherUserId, isIncomingCall, isVideoCall))
putExtra(EXTRA_MODE, mode)
}
}
}
} }

View File

@ -29,6 +29,8 @@ sealed class VectorCallViewActions : VectorViewModelAction {
data class ChangeAudioDevice(val device: CallAudioManager.Device) : VectorCallViewActions() data class ChangeAudioDevice(val device: CallAudioManager.Device) : VectorCallViewActions()
object OpenDialPad: VectorCallViewActions() object OpenDialPad: VectorCallViewActions()
data class SendDtmfDigit(val digit: String) : VectorCallViewActions() data class SendDtmfDigit(val digit: String) : VectorCallViewActions()
data class SwitchCall(val callArgs: CallArgs) : VectorCallViewActions()
object SwitchSoundDevice : VectorCallViewActions() object SwitchSoundDevice : VectorCallViewActions()
object HeadSetButtonPressed : VectorCallViewActions() object HeadSetButtonPressed : VectorCallViewActions()
object ToggleCamera : VectorCallViewActions() object ToggleCamera : VectorCallViewActions()

View File

@ -174,7 +174,12 @@ class VectorCallViewModel @AssistedInject constructor(
} }
init { init {
val webRtcCall = callManager.getCallById(initialState.callId) setupCallWithCurrentState()
}
private fun setupCallWithCurrentState() = withState { state ->
call?.removeListener(callListener)
val webRtcCall = callManager.getCallById(state.callId)
if (webRtcCall == null) { if (webRtcCall == null) {
setState { setState {
copy(callState = Fail(IllegalArgumentException("No call"))) copy(callState = Fail(IllegalArgumentException("No call")))
@ -229,6 +234,7 @@ class VectorCallViewModel @AssistedInject constructor(
override fun onCleared() { override fun onCleared() {
callManager.removeCurrentCallListener(currentCallListener) callManager.removeCurrentCallListener(currentCallListener)
call?.removeListener(callListener) call?.removeListener(callListener)
call = null
proximityManager.stop() proximityManager.stop()
super.onCleared() super.onCleared()
} }
@ -306,9 +312,13 @@ class VectorCallViewModel @AssistedInject constructor(
VectorCallViewEvents.ShowCallTransferScreen VectorCallViewEvents.ShowCallTransferScreen
) )
} }
VectorCallViewActions.TransferCall -> { VectorCallViewActions.TransferCall -> {
handleCallTransfer() handleCallTransfer()
} }
is VectorCallViewActions.SwitchCall -> {
setState { VectorCallViewState(action.callArgs) }
setupCallWithCurrentState()
}
}.exhaustive }.exhaustive
} }

View File

@ -348,7 +348,7 @@ class WebRtcCall(
fun attachViewRenderers(localViewRenderer: SurfaceViewRenderer?, remoteViewRenderer: SurfaceViewRenderer, mode: String?) { fun attachViewRenderers(localViewRenderer: SurfaceViewRenderer?, remoteViewRenderer: SurfaceViewRenderer, mode: String?) {
sessionScope?.launch(dispatcher) { sessionScope?.launch(dispatcher) {
Timber.tag(loggerTag.value).v("attachViewRenderers localRendeder $localViewRenderer / $remoteViewRenderer") Timber.tag(loggerTag.value).v("attachViewRenderers localRenderer $localViewRenderer / $remoteViewRenderer")
localSurfaceRenderers.addIfNeeded(localViewRenderer) localSurfaceRenderers.addIfNeeded(localViewRenderer)
remoteSurfaceRenderers.addIfNeeded(remoteViewRenderer) remoteSurfaceRenderers.addIfNeeded(remoteViewRenderer)
when (mode) { when (mode) {

View File

@ -358,7 +358,7 @@ class NoticeEventFormatter @Inject constructor(
} }
EventType.CALL_REJECT -> EventType.CALL_REJECT ->
if (event.isSentByCurrentUser()) { if (event.isSentByCurrentUser()) {
sp.getString(R.string.call_tile_you_declined) sp.getString(R.string.call_tile_you_declined,"")
} else { } else {
sp.getString(R.string.call_tile_other_declined, senderName) sp.getString(R.string.call_tile_other_declined, senderName)
} }