diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt index 4576675d4a..229c20f95d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt @@ -126,7 +126,16 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa private fun handleCallRejectEvent(event: Event) { val content = event.getClearContent().toModel() ?: return val call = content.getCall() ?: return + if (call.ourPartyId == content.partyId) { + // Ignore remote echo + return + } activeCallHandler.removeCall(content.callId) + if (event.senderId == userId) { + // discard current call, it's rejected by another of my session + callListenersDispatcher.onCallManagedByOtherSession(content.callId) + return + } // No need to check party_id for reject because if we'd received either // an answer or reject, we wouldn't be in state InviteSent if (call.state != CallState.Dialing) { @@ -177,6 +186,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa } if (event.senderId == userId) { // discard current call, it's answered by another of my session + activeCallHandler.removeCall(call.callId) callListenersDispatcher.onCallManagedByOtherSession(content.callId) } else { if (call.opponentPartyId != null) { diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index 420f57c57a..e9b29d99ba 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -161,7 +161,7 @@ Formatter\.formatShortFileSize===1 # android\.text\.TextUtils ### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt -enum class===87 +enum class===88 ### Do not import temporary legacy classes import org.matrix.android.sdk.internal.legacy.riot===3 diff --git a/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt b/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt index d5d8bb14dd..f725742711 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallRingPlayer.kt @@ -16,33 +16,76 @@ package im.vector.app.core.services +import android.app.NotificationChannel import android.content.Context -import android.media.Ringtone -import android.media.RingtoneManager import android.media.AudioAttributes import android.media.AudioManager import android.media.MediaPlayer +import android.media.Ringtone +import android.media.RingtoneManager import android.os.Build +import android.os.VibrationEffect +import android.os.Vibrator import androidx.core.content.getSystemService import im.vector.app.R +import im.vector.app.features.notifications.NotificationUtils +import org.matrix.android.sdk.api.extensions.orFalse import timber.log.Timber class CallRingPlayerIncoming( - context: Context + context: Context, + private val notificationUtils: NotificationUtils ) { private val applicationContext = context.applicationContext - private var r: Ringtone? = null + private var ringtone: Ringtone? = null + private var vibrator: Vibrator? = null - fun start() { - val notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE) - r = RingtoneManager.getRingtone(applicationContext, notification) - Timber.v("## VOIP Starting ringing incomming") - r?.play() + private val VIBRATE_PATTERN = longArrayOf(0, 400, 600) + + fun start(fromBg: Boolean) { + val audioManager = applicationContext.getSystemService() + val incomingCallChannel = notificationUtils.getChannelForIncomingCall(fromBg) + val ringerMode = audioManager?.ringerMode + if (ringerMode == AudioManager.RINGER_MODE_NORMAL) { + playRingtoneIfNeeded(incomingCallChannel) + } else if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { + vibrateIfNeeded(incomingCallChannel) + } + } + + private fun playRingtoneIfNeeded(incomingCallChannel: NotificationChannel?) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && incomingCallChannel?.sound != null) { + Timber.v("Ringtone already configured by notification channel") + return + } + val ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE) + ringtone = RingtoneManager.getRingtone(applicationContext, ringtoneUri) + Timber.v("Play ringtone for incoming call") + ringtone?.play() + } + + private fun vibrateIfNeeded(incomingCallChannel: NotificationChannel?) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && incomingCallChannel?.shouldVibrate().orFalse()) { + Timber.v("## Vibration already configured by notification channel") + return + } + vibrator = applicationContext.getSystemService() + Timber.v("Vibrate for incoming call") + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val vibrationEffect = VibrationEffect.createWaveform(VIBRATE_PATTERN, 0) + vibrator?.vibrate(vibrationEffect) + } else { + @Suppress("DEPRECATION") + vibrator?.vibrate(VIBRATE_PATTERN, 0) + } } fun stop() { - r?.stop() + ringtone?.stop() + ringtone = null + vibrator?.cancel() + vibrator = null } } @@ -55,12 +98,12 @@ class CallRingPlayerOutgoing( private var player: MediaPlayer? = null fun start() { - val audioManager = applicationContext.getSystemService()!! + val audioManager: AudioManager? = applicationContext.getSystemService() player?.release() player = createPlayer() // Check if sound is enabled - val ringerMode = audioManager.ringerMode + val ringerMode = audioManager?.ringerMode if (player != null && ringerMode == AudioManager.RINGER_MODE_NORMAL) { try { if (player?.isPlaying == false) { @@ -89,14 +132,14 @@ class CallRingPlayerOutgoing( mediaPlayer.setOnErrorListener(MediaPlayerErrorListener()) mediaPlayer.isLooping = true - if (Build.VERSION.SDK_INT <= 21) { - @Suppress("DEPRECATION") - mediaPlayer.setAudioStreamType(AudioManager.STREAM_RING) - } else { + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { mediaPlayer.setAudioAttributes(AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) .setUsage(AudioAttributes.USAGE_VOICE_COMMUNICATION) .build()) + } else { + @Suppress("DEPRECATION") + mediaPlayer.setAudioStreamType(AudioManager.STREAM_RING) } return mediaPlayer } catch (failure: Throwable) { diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt index af1bd734c1..2b7d878d49 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt @@ -79,7 +79,7 @@ class CallService : VectorService() { callManager = vectorComponent().webRtcCallManager() avatarRenderer = vectorComponent().avatarRenderer() alertManager = vectorComponent().alertManager() - callRingPlayerIncoming = CallRingPlayerIncoming(applicationContext) + callRingPlayerIncoming = CallRingPlayerIncoming(applicationContext, notificationUtils) callRingPlayerOutgoing = CallRingPlayerOutgoing(applicationContext) } @@ -98,21 +98,17 @@ class CallService : VectorService() { setCallback(mediaSessionButtonCallback) } } - if (intent == null) { - // Service started again by the system. - // TODO What do we do here? - return START_STICKY - } mediaSession?.let { // This ensures that the correct callbacks to MediaSessionCompat.Callback // will be triggered based on the incoming KeyEvent. MediaButtonReceiver.handleIntent(it, intent) } - when (intent.action) { + when (intent?.action) { ACTION_INCOMING_RINGING_CALL -> { mediaSession?.isActive = true - callRingPlayerIncoming?.start() + val fromBg = intent.getBooleanExtra(EXTRA_IS_IN_BG, false) + callRingPlayerIncoming?.start(fromBg) displayIncomingCallNotification(intent) } ACTION_OUTGOING_RINGING_CALL -> { @@ -136,15 +132,12 @@ class CallService : VectorService() { handleCallTerminated(intent) } else -> { - // Should not happen - callRingPlayerIncoming?.stop() - callRingPlayerOutgoing?.stop() - myStopSelf() + handleUnexpectedState(null) } } // We want the system to restore the service if killed - return START_STICKY + return START_REDELIVER_INTENT } // ================================================================================ @@ -158,10 +151,8 @@ class CallService : VectorService() { private fun displayIncomingCallNotification(intent: Intent) { Timber.v("## VOIP displayIncomingCallNotification $intent") val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" - val call = callManager.getCallById(callId) ?: return - if (knownCalls.contains(callId)) { - Timber.v("Call already notified $callId$") - return + val call = callManager.getCallById(callId) ?: return Unit.also { + handleUnexpectedState(callId) } val isVideoCall = call.mxCall.isVideoCall val fromBg = intent.getBooleanExtra(EXTRA_IS_IN_BG, false) @@ -202,13 +193,14 @@ class CallService : VectorService() { private fun handleCallTerminated(intent: Intent) { val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" + alertManager.cancelAlert(callId) if (!knownCalls.remove(callId)) { Timber.v("Call terminated for unknown call $callId$") + handleUnexpectedState(callId) return } val notification = notificationUtils.buildCallEndedNotification() notificationManager.notify(callId.hashCode(), notification) - alertManager.cancelAlert(callId) if (knownCalls.isEmpty()) { mediaSession?.isActive = false myStopSelf() @@ -225,11 +217,9 @@ class CallService : VectorService() { } private fun displayOutgoingRingingCallNotification(intent: Intent) { - val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: return - val call = callManager.getCallById(callId) ?: return - if (knownCalls.contains(callId)) { - Timber.v("Call already notified $callId$") - return + val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" + val call = callManager.getCallById(callId) ?: return Unit.also { + handleUnexpectedState(callId) } val opponentMatrixItem = getOpponentMatrixItem(call) Timber.v("displayOutgoingCallNotification : display the dedicated notification") @@ -251,10 +241,8 @@ class CallService : VectorService() { private fun displayCallInProgressNotification(intent: Intent) { Timber.v("## VOIP displayCallInProgressNotification") val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" - val call = callManager.getCallById(callId) ?: return - if (!knownCalls.contains(callId)) { - Timber.v("Call in progress for unknown call $callId$") - return + val call = callManager.getCallById(callId) ?: return Unit.also { + handleUnexpectedState(callId) } val opponentMatrixItem = getOpponentMatrixItem(call) alertManager.cancelAlert(callId) @@ -262,7 +250,27 @@ class CallService : VectorService() { mxCall = call.mxCall, title = opponentMatrixItem?.getBestName() ?: call.mxCall.opponentUserId ) - notificationManager.notify(callId.hashCode(), notification) + if (knownCalls.isEmpty()) { + startForeground(callId.hashCode(), notification) + } else { + notificationManager.notify(callId.hashCode(), notification) + } + knownCalls.add(callId) + } + + private fun handleUnexpectedState(callId: String?) { + Timber.v("Fallback to clear everything") + callRingPlayerIncoming?.stop() + callRingPlayerOutgoing?.stop() + if (callId != null) { + notificationManager.cancel(callId.hashCode()) + } + val notification = notificationUtils.buildCallEndedNotification() + startForeground(DEFAULT_NOTIFICATION_ID, notification) + if (knownCalls.isEmpty()) { + mediaSession?.isActive = false + myStopSelf() + } } fun addConnection(callConnection: CallConnection) { @@ -274,7 +282,7 @@ class CallService : VectorService() { } companion object { - private const val NOTIFICATION_ID = 6480 + private const val DEFAULT_NOTIFICATION_ID = 6480 private const val ACTION_INCOMING_RINGING_CALL = "im.vector.app.core.services.CallService.ACTION_INCOMING_RINGING_CALL" private const val ACTION_OUTGOING_RINGING_CALL = "im.vector.app.core.services.CallService.ACTION_OUTGOING_RINGING_CALL" diff --git a/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt b/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt index ef6f3e431a..59418147d7 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/BottomSheetActionButton.kt @@ -20,7 +20,6 @@ import android.content.Context import android.content.res.ColorStateList import android.graphics.drawable.Drawable import android.util.AttributeSet -import android.view.LayoutInflater import android.widget.FrameLayout import androidx.core.content.ContextCompat import androidx.core.content.withStyledAttributes diff --git a/vector/src/main/java/im/vector/app/features/call/audio/API21AudioDeviceDetector.kt b/vector/src/main/java/im/vector/app/features/call/audio/API21AudioDeviceDetector.kt index 8ca6b2bb16..32b243aa2b 100644 --- a/vector/src/main/java/im/vector/app/features/call/audio/API21AudioDeviceDetector.kt +++ b/vector/src/main/java/im/vector/app/features/call/audio/API21AudioDeviceDetector.kt @@ -21,11 +21,7 @@ import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothManager import android.bluetooth.BluetoothProfile import android.content.Context -import android.media.AudioDeviceCallback -import android.media.AudioDeviceInfo import android.media.AudioManager -import android.os.Build -import androidx.annotation.RequiresApi import androidx.core.content.getSystemService import im.vector.app.core.services.BluetoothHeadsetReceiver import im.vector.app.core.services.WiredHeadsetStateReceiver @@ -52,16 +48,15 @@ internal class API21AudioDeviceDetector(private val context: Context, private fun getAvailableSoundDevices(): Set { return HashSet().apply { if (isBluetoothHeadsetOn()) add(CallAudioManager.Device.WIRELESS_HEADSET) - if(isWiredHeadsetOn()){ + if (isWiredHeadsetOn()) { add(CallAudioManager.Device.HEADSET) - }else { + } else { add(CallAudioManager.Device.PHONE) } add(CallAudioManager.Device.SPEAKER) } } - private fun isWiredHeadsetOn(): Boolean { return audioManager.isWiredHeadsetOn } @@ -82,7 +77,6 @@ internal class API21AudioDeviceDetector(private val context: Context, } } - /** * Helper method to trigger an audio route update when devices change. It * makes sure the operation is performed on the audio thread. @@ -119,7 +113,6 @@ internal class API21AudioDeviceDetector(private val context: Context, onAudioDeviceChange() } - override fun stop() { Timber.i("Stop using $this as the audio device handler") wiredHeadsetStateReceiver?.let { WiredHeadsetStateReceiver.unRegister(context, it) } diff --git a/vector/src/main/java/im/vector/app/features/call/audio/API23AudioDeviceDetector.kt b/vector/src/main/java/im/vector/app/features/call/audio/API23AudioDeviceDetector.kt index 2305ca7ed5..7174554d5f 100644 --- a/vector/src/main/java/im/vector/app/features/call/audio/API23AudioDeviceDetector.kt +++ b/vector/src/main/java/im/vector/app/features/call/audio/API23AudioDeviceDetector.kt @@ -30,7 +30,7 @@ internal class API23AudioDeviceDetector(private val audioManager: AudioManager, private val onAudioDeviceChangeRunner = Runnable { val devices: MutableSet = HashSet() - val deviceInfos = audioManager.getDevices(AudioManager.GET_DEVICES_ALL) + val deviceInfos = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS) for (info in deviceInfos) { when (info.type) { AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> devices.add(CallAudioManager.Device.WIRELESS_HEADSET) diff --git a/vector/src/main/java/im/vector/app/features/call/audio/CallAudioManager.kt b/vector/src/main/java/im/vector/app/features/call/audio/CallAudioManager.kt index 92b0018b57..66370763e1 100644 --- a/vector/src/main/java/im/vector/app/features/call/audio/CallAudioManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/audio/CallAudioManager.kt @@ -18,6 +18,8 @@ package im.vector.app.features.call.audio import android.content.Context import android.media.AudioManager +import android.os.Build +import androidx.core.content.getSystemService import org.matrix.android.sdk.api.extensions.orFalse import timber.log.Timber import java.util.HashSet @@ -25,7 +27,7 @@ import java.util.concurrent.Executors class CallAudioManager(private val context: Context, val configChange: (() -> Unit)?) { - private val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager + private val audioManager: AudioManager? = context.getSystemService() private var audioDeviceDetector: AudioDeviceDetector? = null private var audioDeviceRouter: AudioDeviceRouter? = null @@ -56,8 +58,11 @@ class CallAudioManager(private val context: Context, val configChange: (() -> Un } private fun setup() { + if (audioManager == null) { + return + } audioDeviceDetector?.stop() - audioDeviceDetector = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { + audioDeviceDetector = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { API23AudioDeviceDetector(audioManager, this) } else { API21AudioDeviceDetector(context, audioManager, this) diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/PeerConnectionObserver.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/PeerConnectionObserver.kt index b476d7dbe6..9b4adcf955 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/PeerConnectionObserver.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/PeerConnectionObserver.kt @@ -16,7 +16,6 @@ package im.vector.app.features.call.webrtc -import im.vector.app.features.call.audio.CallAudioManager import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.MxPeerConnectionState import org.webrtc.DataChannel diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt index 95e7e92646..bc55c3e924 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt @@ -21,7 +21,6 @@ import android.hardware.camera2.CameraManager import androidx.core.content.getSystemService import im.vector.app.core.services.CallService import im.vector.app.core.utils.CountUpTimer -import im.vector.app.features.call.audio.CallAudioManager import im.vector.app.features.call.CameraEventsHandlerAdapter import im.vector.app.features.call.CameraProxy import im.vector.app.features.call.CameraType @@ -92,7 +91,7 @@ class WebRtcCall(val mxCall: MxCall, private val sessionProvider: Provider, private val peerConnectionFactoryProvider: Provider, private val onCallBecomeActive: (WebRtcCall) -> Unit, - private val onCallEnded: (WebRtcCall) -> Unit) : MxCall.StateListener { + private val onCallEnded: (String) -> Unit) : MxCall.StateListener { interface Listener : MxCall.StateListener { fun onCaptureStateChanged() {} @@ -725,7 +724,7 @@ class WebRtcCall(val mxCall: MxCall, GlobalScope.launch(dispatcher) { release() } - onCallEnded(this) + onCallEnded(callId) if (originatedByMe) { if (wasRinging) { mxCall.reject() diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt index f7f50b4681..86cf3972c9 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt @@ -21,9 +21,7 @@ import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent import im.vector.app.ActiveSessionDataSource -import im.vector.app.core.services.BluetoothHeadsetReceiver import im.vector.app.core.services.CallService -import im.vector.app.core.services.WiredHeadsetStateReceiver import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.audio.CallAudioManager import im.vector.app.features.call.utils.EglUtils @@ -186,22 +184,34 @@ class WebRtcCallManager @Inject constructor( this.currentCall.setAndNotify(call) } - private fun onCallEnded(call: WebRtcCall) { - Timber.v("## VOIP WebRtcPeerConnectionManager onCall ended: ${call.mxCall.callId}") - CallService.onCallTerminated(context, call.callId) - callsByCallId.remove(call.mxCall.callId) - callsByRoomId[call.mxCall.roomId]?.remove(call) - if (getCurrentCall() == call) { + private fun onCallEnded(callId: String) { + Timber.v("## VOIP WebRtcPeerConnectionManager onCall ended: $callId") + val webRtcCall = callsByCallId.remove(callId) ?: return Unit.also { + Timber.v("On call ended for unknown call $callId") + } + CallService.onCallTerminated(context, callId) + callsByRoomId[webRtcCall.roomId]?.remove(webRtcCall) + if (getCurrentCall()?.callId == callId) { val otherCall = getCalls().lastOrNull() currentCall.setAndNotify(otherCall) } // This must be done in this thread executor.execute { + // There is no active calls if (getCurrentCall() == null) { Timber.v("## VOIP Dispose peerConnectionFactory as there is no need to keep one") peerConnectionFactory?.dispose() peerConnectionFactory = null audioManager.setMode(CallAudioManager.Mode.DEFAULT) + // did we start background sync? so we should stop it + if (isInBackground) { + if (FcmHelper.isPushSupported()) { + currentSession?.stopAnyBackgroundSync() + } else { + // for fdroid we should not stop, it should continue syncing + // maybe we should restore default timeout/delay though? + } + } } Timber.v("## VOIP WebRtcPeerConnectionManager close() executor done") } @@ -225,7 +235,6 @@ class WebRtcCallManager @Inject constructor( val mxCall = currentSession?.callSignalingService()?.createOutgoingCall(signalingRoomId, otherUserId, isVideoCall) ?: return val webRtcCall = createWebRtcCall(mxCall) currentCall.setAndNotify(webRtcCall) - //callAudioManager.startForCall(mxCall) CallService.onOutgoingCallRinging( context = context.applicationContext, @@ -261,6 +270,9 @@ class WebRtcCallManager @Inject constructor( callsByCallId[mxCall.callId] = webRtcCall callsByRoomId.getOrPut(mxCall.roomId) { ArrayList(1) } .add(webRtcCall) + if (getCurrentCall() == null) { + currentCall.setAndNotify(webRtcCall) + } return webRtcCall } @@ -268,18 +280,6 @@ class WebRtcCallManager @Inject constructor( callsByRoomId[roomId]?.forEach { it.endCall(originatedByMe) } } - fun onWiredDeviceEvent(event: WiredHeadsetStateReceiver.HeadsetPlugEvent) { - Timber.v("## VOIP onWiredDeviceEvent $event") - getCurrentCall() ?: return - // sometimes we received un-wanted unplugged... - //callAudioManager.wiredStateChange(event) - } - - fun onWirelessDeviceEvent(event: BluetoothHeadsetReceiver.BTHeadsetPlugEvent) { - Timber.v("## VOIP onWirelessDeviceEvent $event") - //callAudioManager.bluetoothStateChange(event.plugged) - } - override fun onCallInviteReceived(mxCall: MxCall, callInviteContent: CallInviteContent) { Timber.v("## VOIP onCallInviteReceived callId ${mxCall.callId}") if (getCallsByRoomId(mxCall.roomId).isNotEmpty()) { @@ -294,7 +294,6 @@ class WebRtcCallManager @Inject constructor( createWebRtcCall(mxCall).apply { offerSdp = callInviteContent.offer } - //callAudioManager.startForCall(mxCall) // Start background service with notification CallService.onIncomingCallRinging( context = context, @@ -367,21 +366,6 @@ class WebRtcCallManager @Inject constructor( override fun onCallManagedByOtherSession(callId: String) { Timber.v("## VOIP onCallManagedByOtherSession: $callId") - val webRtcCall = callsByCallId.remove(callId) - if (webRtcCall != null) { - callsByRoomId[webRtcCall.mxCall.roomId]?.remove(webRtcCall) - } - // TODO: handle this properly - CallService.onCallTerminated(context, callId) - - // did we start background sync? so we should stop it - if (isInBackground) { - if (FcmHelper.isPushSupported()) { - currentSession?.stopAnyBackgroundSync() - } else { - // for fdroid we should not stop, it should continue syncing - // maybe we should restore default timeout/delay though? - } - } + onCallEnded(callId) } } diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index d1e52b2a78..e7cafc6a9b 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -208,6 +208,10 @@ class NotificationUtils @Inject constructor(private val context: Context, }) } + fun getChannel(channelId: String): NotificationChannel? { + return notificationManager.getNotificationChannel(channelId) + } + /** * Build a polling thread listener notification * @@ -266,6 +270,11 @@ class NotificationUtils @Inject constructor(private val context: Context, return notification } + fun getChannelForIncomingCall(fromBg: Boolean): NotificationChannel? { + val notificationChannel = if (fromBg) CALL_NOTIFICATION_CHANNEL_ID else SILENT_NOTIFICATION_CHANNEL_ID + return getChannel(notificationChannel) + } + /** * Build an incoming call notification. * This notification starts the VectorHomeActivity which is in charge of centralizing the incoming call flow. diff --git a/vector/src/main/res/layout/view_bottom_sheet_action_button.xml b/vector/src/main/res/layout/view_bottom_sheet_action_button.xml index c0e0ba7bcb..ec2e7d2bfe 100644 --- a/vector/src/main/res/layout/view_bottom_sheet_action_button.xml +++ b/vector/src/main/res/layout/view_bottom_sheet_action_button.xml @@ -44,7 +44,7 @@ android:textSize="16sp" app:layout_constrainedWidth="true" app:layout_constraintBottom_toTopOf="@+id/bottomSheetActionSubTitle" - app:layout_constraintEnd_toStartOf="@+id/itemVerificationActionIcon" + app:layout_constraintEnd_toStartOf="@+id/bottomSheetActionIcon" app:layout_constraintStart_toEndOf="@+id/bottomSheetActionLeftIcon" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed"