Show the foreground service for incoming and outgoing calls.

This commit is contained in:
onurays 2020-05-25 11:27:46 +03:00 committed by Valere
parent fb6bcc8470
commit 5d476e7259
11 changed files with 69 additions and 68 deletions

View file

@ -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)

View file

@ -144,7 +144,7 @@ internal class DefaultCallService @Inject constructor(
}
EventType.CALL_INVITE -> {
event.getClearContent().toModel<CallInviteContent>()?.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)
}
}
}

View file

@ -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"))
}
}

View file

@ -18,7 +18,8 @@
intent action. -->
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- Adding CAMERA permission prevents Chromebooks to see the application on the PlayStore -->
<!-- Tell that the Camera is not mandatory to install the application -->

View file

@ -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) {

View file

@ -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<SurfaceViewRenderer>? = null
var remoteSurfaceRenderer: WeakReference<SurfaceViewRenderer>? = 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) {

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -2,6 +2,13 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<item
android:id="@+id/video_call"
android:icon="@drawable/ic_videocam"
android:title="@string/action_video_call"
android:visible="false"
app:showAsAction="always"
tools:visible="true" />
<item
android:id="@+id/open_matrix_apps"

View file

@ -190,5 +190,14 @@
<color name="riotx_keys_backup_banner_accent_color_light">#FFF8E3</color>
<color name="riotx_keys_backup_banner_accent_color_dark">#22262E</color>
<attr name="riotx_call_actions_bg_gradient_start" format="color" />
<color name="riotx_call_actions_bg_gradient_start_light">#000000</color>
<color name="riotx_call_actions_bg_gradient_start_dark">#000000</color>
<color name="riotx_call_actions_bg_gradient_start_black">#000000</color>
<attr name="riotx_call_actions_bg_gradient_end" format="color" />
<color name="riotx_call_actions_bg_gradient_end_light">@android:color/transparent</color>
<color name="riotx_call_actions_bg_gradient_end_dark">@android:color/transparent</color>
<color name="riotx_call_actions_bg_gradient_end_black">@android:color/transparent</color>
</resources>