From 5d476e72590392bb52c8f0edbb8851b754dbbcaf Mon Sep 17 00:00:00 2001 From: onurays Date: Mon, 25 May 2020 11:27:46 +0300 Subject: [PATCH] Show the foreground service for incoming and outgoing calls. --- .../android/api/session/call/CallsListener.kt | 2 +- .../session/call/DefaultCallService.kt | 8 +- .../riotx/features/debug/DebugMenuActivity.kt | 4 +- vector/src/main/AndroidManifest.xml | 3 +- .../features/call/VectorCallViewModel.kt | 2 +- .../call/WebRtcPeerConnectionManager.kt | 80 +++++++------------ .../call/service/CallHeadsUpServiceArgs.kt | 3 +- .../home/room/detail/RoomDetailFragment.kt | 15 ++-- .../home/room/detail/RoomDetailViewModel.kt | 4 +- vector/src/main/res/menu/menu_timeline.xml | 7 ++ vector/src/main/res/values/colors_riotx.xml | 9 +++ 11 files changed, 69 insertions(+), 68 deletions(-) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/call/CallsListener.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/call/CallsListener.kt index ff8ddb8de9..1fc4170f5c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/call/CallsListener.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/call/CallsListener.kt @@ -41,7 +41,7 @@ interface CallsListener { // */ // fun onCallHangUp(peerSignalingClient: PeerSignalingClient) - fun onCallInviteReceived(signalingRoomId: String, callInviteContent: CallInviteContent) + fun onCallInviteReceived(signalingRoomId: String, participantUserId: String, callInviteContent: CallInviteContent) fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/call/DefaultCallService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/call/DefaultCallService.kt index 0617a657fc..fba50a0c37 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/call/DefaultCallService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/call/DefaultCallService.kt @@ -144,7 +144,7 @@ internal class DefaultCallService @Inject constructor( } EventType.CALL_INVITE -> { event.getClearContent().toModel()?.let { - onCallInvite(event.roomId ?: "", it) + onCallInvite(event.roomId ?: "", event.senderId ?: "", it) } } EventType.CALL_HANGUP -> { @@ -171,10 +171,12 @@ internal class DefaultCallService @Inject constructor( } } - private fun onCallInvite(roomId: String, answer: CallInviteContent) { + private fun onCallInvite(roomId: String, userId: String, answer: CallInviteContent) { + if (userId == this.userId) return + callListeners.forEach { tryThis { - it.onCallInviteReceived(roomId, answer) + it.onCallInviteReceived(roomId, userId, answer) } } } diff --git a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt index 8b4a777454..2a8bc22e2e 100644 --- a/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt +++ b/vector/src/debug/java/im/vector/riotx/features/debug/DebugMenuActivity.kt @@ -35,7 +35,6 @@ import im.vector.riotx.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA import im.vector.riotx.core.utils.allGranted import im.vector.riotx.core.utils.checkPermissions import im.vector.riotx.core.utils.toast -import im.vector.riotx.features.call.VectorCallActivity import im.vector.riotx.features.debug.sas.DebugSasEmojiActivity import im.vector.riotx.features.qrcode.QrCodeScannerActivity import kotlinx.android.synthetic.debug.activity_debug_menu.* @@ -185,7 +184,8 @@ class DebugMenuActivity : VectorBaseActivity() { fun scanQRCode() { if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, this, PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) { // doScanQRCode() - startActivity(VectorCallActivity.newIntent(this, "!cyIJhOLwWgmmqreHLD:matrix.org")) + // TODO. Find a better way? + //startActivity(VectorCallActivity.newIntent(this, "!cyIJhOLwWgmmqreHLD:matrix.org")) } } diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 76281afe0b..abb6c929cc 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -18,7 +18,8 @@ intent action. --> - + + diff --git a/vector/src/main/java/im/vector/riotx/features/call/VectorCallViewModel.kt b/vector/src/main/java/im/vector/riotx/features/call/VectorCallViewModel.kt index c8b8a3316c..4613c6200b 100644 --- a/vector/src/main/java/im/vector/riotx/features/call/VectorCallViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/call/VectorCallViewModel.kt @@ -69,7 +69,7 @@ class VectorCallViewModel @AssistedInject constructor( } } - override fun onCallInviteReceived(signalingRoomId: String, callInviteContent: CallInviteContent) { + override fun onCallInviteReceived(signalingRoomId: String, participantUserId: String, callInviteContent: CallInviteContent) { } override fun onCallHangupReceived(callHangupContent: CallHangupContent) { diff --git a/vector/src/main/java/im/vector/riotx/features/call/WebRtcPeerConnectionManager.kt b/vector/src/main/java/im/vector/riotx/features/call/WebRtcPeerConnectionManager.kt index 57081afbe1..3ff40afdbb 100644 --- a/vector/src/main/java/im/vector/riotx/features/call/WebRtcPeerConnectionManager.kt +++ b/vector/src/main/java/im/vector/riotx/features/call/WebRtcPeerConnectionManager.kt @@ -19,21 +19,16 @@ package im.vector.riotx.features.call import android.content.ComponentName import android.content.Context import android.content.Intent -import android.graphics.drawable.Icon -import android.os.Build -import android.telecom.PhoneAccount -import android.telecom.PhoneAccountHandle -import android.telecom.TelecomManager +import android.content.ServiceConnection +import android.os.IBinder import androidx.core.content.ContextCompat import im.vector.matrix.android.api.session.call.CallsListener import im.vector.matrix.android.api.session.call.EglUtils import im.vector.matrix.android.api.session.room.model.call.CallAnswerContent import im.vector.matrix.android.api.session.room.model.call.CallHangupContent import im.vector.matrix.android.api.session.room.model.call.CallInviteContent -import im.vector.riotx.BuildConfig -import im.vector.riotx.R +import im.vector.riotx.core.di.ActiveSessionHolder import im.vector.riotx.features.call.service.CallHeadsUpService -import im.vector.riotx.features.call.telecom.VectorConnectionService import org.webrtc.AudioSource import org.webrtc.AudioTrack import org.webrtc.DefaultVideoDecoderFactory @@ -62,8 +57,9 @@ import javax.inject.Singleton */ @Singleton class WebRtcPeerConnectionManager @Inject constructor( - private val context: Context -) : CallsListener { + private val context: Context, + private val sessionHolder: ActiveSessionHolder + ) : CallsListener { interface Listener { fun addLocalIceCandidate(candidates: IceCandidate) @@ -74,27 +70,8 @@ class WebRtcPeerConnectionManager @Inject constructor( fun sendOffer(sessionDescription: SessionDescription) } - var phoneAccountHandle: PhoneAccountHandle? = null var localMediaStream: MediaStream? = null - init { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - val componentName = ComponentName(BuildConfig.APPLICATION_ID, VectorConnectionService::class.java.name) - val appName = context.getString(R.string.app_name) - phoneAccountHandle = PhoneAccountHandle(componentName, appName) - val phoneAccount = PhoneAccount.Builder(phoneAccountHandle, BuildConfig.APPLICATION_ID) - .setIcon(Icon.createWithResource(context, R.drawable.riotx_logo)) - .setCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED) - .setCapabilities(PhoneAccount.CAPABILITY_VIDEO_CALLING) - .setCapabilities(PhoneAccount.CAPABILITY_CALL_SUBJECT) - .build() - ContextCompat.getSystemService(context, TelecomManager::class.java) - ?.registerPhoneAccount(phoneAccount) - } else { - // ignore? - } - } - var listener: Listener? = null // *Comments copied from webrtc demo app* @@ -121,6 +98,17 @@ class WebRtcPeerConnectionManager @Inject constructor( var localSurfaceRenderer: WeakReference? = null var remoteSurfaceRenderer: WeakReference? = null + var callHeadsUpService: CallHeadsUpService? = null + + private val serviceConnection = object : ServiceConnection { + override fun onServiceDisconnected(name: ComponentName?) { + } + + override fun onServiceConnected(name: ComponentName?, service: IBinder?) { + callHeadsUpService = (service as? CallHeadsUpService.CallHeadsUpServiceBinder)?.getService() + } + } + fun createPeerConnectionFactory() { executor.execute { if (peerConnectionFactory == null) { @@ -331,6 +319,7 @@ class WebRtcPeerConnectionManager @Inject constructor( peerConnectionFactory?.stopAecDump() peerConnectionFactory = null } + context.stopService(Intent(context, CallHeadsUpService::class.java)) } companion object { @@ -356,27 +345,20 @@ class WebRtcPeerConnectionManager @Inject constructor( } } - override fun onCallInviteReceived(signalingRoomId: String, callInviteContent: CallInviteContent) { - val callHeadsUpServiceIntent = Intent(context, CallHeadsUpService::class.java) + fun startOutgoingCall(context: Context, signalingRoomId: String, participantUserId: String, isVideoCall: Boolean) { + startHeadsUpService(signalingRoomId, sessionHolder.getActiveSession().myUserId, false, isVideoCall) + context.startActivity(VectorCallActivity.newIntent(context, signalingRoomId, participantUserId, false, isVideoCall)) + } + + override fun onCallInviteReceived(signalingRoomId: String, participantUserId: String, callInviteContent: CallInviteContent) { + startHeadsUpService(signalingRoomId, participantUserId, true, callInviteContent.isVideo()) + } + + private fun startHeadsUpService(roomId: String, participantUserId: String, isIncomingCall: Boolean, isVideoCall: Boolean) { + val callHeadsUpServiceIntent = CallHeadsUpService.newInstance(context, roomId, participantUserId, isIncomingCall, isVideoCall) ContextCompat.startForegroundService(context, callHeadsUpServiceIntent) - /* - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - ContextCompat.getSystemService(context, TelecomManager::class.java)?.let { telecomManager -> - phoneAccountHandle?.let { phoneAccountHandle -> - telecomManager.addNewIncomingCall( - phoneAccountHandle, - Bundle().apply { - putString("MX_CALL_ROOM_ID", signalingRoomId) - putString("MX_CALL_CALL_ID", callInviteContent.callId) - putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, phoneAccountHandle) - putInt(TelecomManager.EXTRA_INCOMING_VIDEO_STATE, VideoProfile.STATE_BIDIRECTIONAL) - putInt(TelecomManager.EXTRA_START_CALL_WITH_VIDEO_STATE, VideoProfile.STATE_BIDIRECTIONAL) - } - ) - } - } - } - */ + + context.bindService(Intent(context, CallHeadsUpService::class.java), serviceConnection, 0) } override fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) { diff --git a/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpServiceArgs.kt b/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpServiceArgs.kt index 9769724944..381975a2ee 100644 --- a/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpServiceArgs.kt +++ b/vector/src/main/java/im/vector/riotx/features/call/service/CallHeadsUpServiceArgs.kt @@ -21,7 +21,8 @@ import kotlinx.android.parcel.Parcelize @Parcelize data class CallHeadsUpServiceArgs( - val callerDisplayName: String, + val roomId: String, + val participantUserId: String, val isIncomingCall: Boolean, val isVideoCall: Boolean ) : Parcelable diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt index efa045ddd2..b31ab35085 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailFragment.kt @@ -127,7 +127,7 @@ import im.vector.riotx.features.attachments.ContactAttachment import im.vector.riotx.features.attachments.preview.AttachmentsPreviewActivity import im.vector.riotx.features.attachments.preview.AttachmentsPreviewArgs import im.vector.riotx.features.attachments.toGroupedContentAttachmentData -import im.vector.riotx.features.call.service.CallHeadsUpService +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 @@ -197,7 +197,8 @@ class RoomDetailFragment @Inject constructor( val roomDetailViewModelFactory: RoomDetailViewModel.Factory, private val eventHtmlRenderer: EventHtmlRenderer, private val vectorPreferences: VectorPreferences, - private val colorProvider: ColorProvider) : + private val colorProvider: ColorProvider, + private val webRtcPeerConnectionManager: WebRtcPeerConnectionManager) : VectorBaseFragment(), TimelineEventController.Callback, VectorInviteView.Callback, @@ -484,14 +485,10 @@ class RoomDetailFragment @Inject constructor( roomDetailViewModel.handle(RoomDetailAction.ResendAll) return true } - if (item.itemId == R.id.voip_call) { - /* - VectorCallActivity.newIntent(requireContext(), roomDetailArgs.roomId).let { - startActivity(it) + if (item.itemId == R.id.voice_call || item.itemId == R.id.video_call) { + roomDetailViewModel.getOtherUserIds()?.firstOrNull()?.let { + webRtcPeerConnectionManager.startOutgoingCall(requireContext(), roomDetailArgs.roomId, it, item.itemId == R.id.video_call) } - */ - val callHeadsUpServiceIntent = Intent(requireContext(), CallHeadsUpService::class.java) - ContextCompat.startForegroundService(requireContext(), callHeadsUpServiceIntent) return true } return super.onOptionsItemSelected(item) diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 49a469847b..7e33d69345 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -213,6 +213,8 @@ class RoomDetailViewModel @AssistedInject constructor( } } + fun getOtherUserIds() = room.roomSummary()?.otherMemberIds + override fun handle(action: RoomDetailAction) { when (action) { is RoomDetailAction.UserIsTyping -> handleUserIsTyping(action) @@ -366,7 +368,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 on production, worker cancellation is not working properly */ timeline.pendingEventCount() > 0 && vectorPreferences.developerMode() R.id.resend_all -> timeline.failedToDeliverEventCount() > 0 diff --git a/vector/src/main/res/menu/menu_timeline.xml b/vector/src/main/res/menu/menu_timeline.xml index 8e271a0285..ce20c59290 100644 --- a/vector/src/main/res/menu/menu_timeline.xml +++ b/vector/src/main/res/menu/menu_timeline.xml @@ -2,6 +2,13 @@ + #FFF8E3 #22262E + + #000000 + #000000 + #000000 + + + @android:color/transparent + @android:color/transparent + @android:color/transparent \ No newline at end of file