diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 64299ff1ae..eafe99f86b 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -196,7 +196,12 @@ + android:exported="false" > + + + + + + + + + + + + () - /** - * call in progress (foreground notification) - */ -// private var mCallIdInProgress: String? = null - private lateinit var notificationUtils: NotificationUtils private lateinit var webRtcPeerConnectionManager: WebRtcPeerConnectionManager - /** - * incoming (foreground notification) - */ -// private var mIncomingCallId: String? = null - private var callRingPlayer: CallRingPlayer? = null private var wiredHeadsetStateReceiver: WiredHeadsetStateReceiver? = null + // A media button receiver receives and helps translate hardware media playback buttons, + // such as those found on wired and wireless headsets, into the appropriate callbacks in your app + private var mediaSession : MediaSessionCompat? = null + private val mediaSessionButtonCallback = object : MediaSessionCompat.Callback() { + override fun onMediaButtonEvent(mediaButtonEvent: Intent?): Boolean { + val keyEvent = mediaButtonEvent?.getParcelableExtra(Intent.EXTRA_KEY_EVENT) ?: return false + if (keyEvent.keyCode == KeyEvent.KEYCODE_HEADSETHOOK) { + webRtcPeerConnectionManager.headSetButtonTapped() + return true + } + return false + } + } + override fun onCreate() { super.onCreate() notificationUtils = vectorComponent().notificationUtils() @@ -64,22 +71,36 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe callRingPlayer?.stop() wiredHeadsetStateReceiver?.let { WiredHeadsetStateReceiver.unRegister(this, it) } wiredHeadsetStateReceiver = null + mediaSession?.release() + mediaSession = null } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Timber.v("## VOIP onStartCommand $intent") + if (mediaSession == null) { + mediaSession = MediaSessionCompat(applicationContext, CallService::class.java.name).apply { + 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) { ACTION_INCOMING_RINGING_CALL -> { + mediaSession?.isActive = true callRingPlayer?.start() displayIncomingCallNotification(intent) } ACTION_OUTGOING_RINGING_CALL -> { + mediaSession?.isActive = true callRingPlayer?.start() displayOutgoingRingingCallNotification(intent) } @@ -221,6 +242,7 @@ class CallService : VectorService(), WiredHeadsetStateReceiver.HeadsetEventListe private fun hideCallNotifications() { val notification = notificationUtils.buildCallEndedNotification() + mediaSession?.isActive = false // It's mandatory to startForeground to avoid crash startForeground(NOTIFICATION_ID, notification) diff --git a/vector/src/main/java/im/vector/riotx/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/riotx/features/call/VectorCallActivity.kt index de0d3151a9..2c1c909a97 100644 --- a/vector/src/main/java/im/vector/riotx/features/call/VectorCallActivity.kt +++ b/vector/src/main/java/im/vector/riotx/features/call/VectorCallActivity.kt @@ -326,10 +326,14 @@ class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionLis } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { - when (keyCode) { - KeyEvent.KEYCODE_HEADSETHOOK -> { - callViewModel.handle(VectorCallViewActions.HeadSetButtonPressed) - return true + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + // for newer version, it will be passed automatically to active media session + // in call service + when (keyCode) { + KeyEvent.KEYCODE_HEADSETHOOK -> { + callViewModel.handle(VectorCallViewActions.HeadSetButtonPressed) + return true + } } } return super.onKeyDown(keyCode, event) 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 8b2e1ef74c..9fbc38d816 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 @@ -184,6 +184,19 @@ class WebRtcPeerConnectionManager @Inject constructor( } } + fun headSetButtonTapped() { + Timber.v("## VOIP headSetButtonTapped") + val call = currentCall?.mxCall ?: return + if (call.state is CallState.LocalRinging) { + // accept call + acceptIncomingCall() + } + if (call.state is CallState.Connected) { + // end call? + endCall() + } + } + private fun createPeerConnectionFactory() { if (peerConnectionFactory != null) return Timber.v("## VOIP createPeerConnectionFactory")