Implemented a microphone access service to handle background microphone usage in calls.
Signed-off-by: AmitShilo <alssamit@gmail.com>
This commit is contained in:
parent
04a49e9195
commit
53387e6617
|
@ -652,6 +652,8 @@
|
||||||
|
|
||||||
<string name="call_remove_jitsi_widget_progress">Ending call…</string>
|
<string name="call_remove_jitsi_widget_progress">Ending call…</string>
|
||||||
|
|
||||||
|
<string name="microphone_in_use_title">Microphone in use</string>
|
||||||
|
|
||||||
<!-- permissions Android M -->
|
<!-- permissions Android M -->
|
||||||
<string name="permissions_rationale_popup_title">Information</string>
|
<string name="permissions_rationale_popup_title">Information</string>
|
||||||
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->
|
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->
|
||||||
|
|
|
@ -395,6 +395,13 @@
|
||||||
android:foregroundServiceType="mediaProjection"
|
android:foregroundServiceType="mediaProjection"
|
||||||
tools:targetApi="Q" />
|
tools:targetApi="Q" />
|
||||||
|
|
||||||
|
<service
|
||||||
|
android:name=".features.call.audio.MicrophoneAccessService"
|
||||||
|
android:exported="false"
|
||||||
|
android:foregroundServiceType="microphone"
|
||||||
|
android:permission="android.permission.FOREGROUND_SERVICE_MICROPHONE">
|
||||||
|
</service>
|
||||||
|
|
||||||
<!-- Receivers -->
|
<!-- Receivers -->
|
||||||
|
|
||||||
<receiver
|
<receiver
|
||||||
|
|
|
@ -31,6 +31,7 @@ import im.vector.app.core.extensions.singletonEntryPoint
|
||||||
import im.vector.app.core.extensions.startForegroundCompat
|
import im.vector.app.core.extensions.startForegroundCompat
|
||||||
import im.vector.app.features.call.CallArgs
|
import im.vector.app.features.call.CallArgs
|
||||||
import im.vector.app.features.call.VectorCallActivity
|
import im.vector.app.features.call.VectorCallActivity
|
||||||
|
import im.vector.app.features.call.audio.MicrophoneAccessService
|
||||||
import im.vector.app.features.call.telecom.CallConnection
|
import im.vector.app.features.call.telecom.CallConnection
|
||||||
import im.vector.app.features.call.webrtc.WebRtcCall
|
import im.vector.app.features.call.webrtc.WebRtcCall
|
||||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||||
|
@ -208,6 +209,9 @@ class CallAndroidService : VectorAndroidService() {
|
||||||
stopForegroundCompat()
|
stopForegroundCompat()
|
||||||
mediaSession?.isActive = false
|
mediaSession?.isActive = false
|
||||||
myStopSelf()
|
myStopSelf()
|
||||||
|
|
||||||
|
// Also stop the microphone service if it is running
|
||||||
|
stopService(Intent(this, MicrophoneAccessService::class.java))
|
||||||
}
|
}
|
||||||
val wasConnected = connectedCallIds.remove(callId)
|
val wasConnected = connectedCallIds.remove(callId)
|
||||||
if (!wasConnected && !terminatedCall.isOutgoing && !rejected && endCallReason != EndCallReason.ANSWERED_ELSEWHERE) {
|
if (!wasConnected && !terminatedCall.isOutgoing && !rejected && endCallReason != EndCallReason.ANSWERED_ELSEWHERE) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import android.app.PictureInPictureParams
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
|
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.media.projection.MediaProjection
|
import android.media.projection.MediaProjection
|
||||||
import android.media.projection.MediaProjectionManager
|
import android.media.projection.MediaProjectionManager
|
||||||
|
@ -57,6 +58,7 @@ import im.vector.app.core.utils.PERMISSIONS_FOR_VIDEO_IP_CALL
|
||||||
import im.vector.app.core.utils.checkPermissions
|
import im.vector.app.core.utils.checkPermissions
|
||||||
import im.vector.app.core.utils.registerForPermissionsResult
|
import im.vector.app.core.utils.registerForPermissionsResult
|
||||||
import im.vector.app.databinding.ActivityCallBinding
|
import im.vector.app.databinding.ActivityCallBinding
|
||||||
|
import im.vector.app.features.call.audio.MicrophoneAccessService
|
||||||
import im.vector.app.features.call.dialpad.CallDialPadBottomSheet
|
import im.vector.app.features.call.dialpad.CallDialPadBottomSheet
|
||||||
import im.vector.app.features.call.dialpad.DialPadFragment
|
import im.vector.app.features.call.dialpad.DialPadFragment
|
||||||
import im.vector.app.features.call.transfer.CallTransferActivity
|
import im.vector.app.features.call.transfer.CallTransferActivity
|
||||||
|
@ -245,6 +247,33 @@ class VectorCallActivity :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun startMicrophoneService() {
|
||||||
|
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED &&
|
||||||
|
ContextCompat.checkSelfPermission(this, android.Manifest.permission.FOREGROUND_SERVICE_MICROPHONE) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
Timber.tag(loggerTag.value).d("Starting MicrophoneAccessService.")
|
||||||
|
val intent = Intent(this, MicrophoneAccessService::class.java)
|
||||||
|
ContextCompat.startForegroundService(this, intent)
|
||||||
|
} else {
|
||||||
|
Timber.tag(loggerTag.value).w("Permissions not granted. Cannot start MicrophoneAccessService.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopMicrophoneService() {
|
||||||
|
Timber.tag(loggerTag.value).d("Stopping MicrophoneAccessService (if needed).")
|
||||||
|
val intent = Intent(this, MicrophoneAccessService::class.java)
|
||||||
|
stopService(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
startMicrophoneService()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
stopMicrophoneService()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
detachRenderersIfNeeded()
|
detachRenderersIfNeeded()
|
||||||
turnScreenOffAndKeyguardOn()
|
turnScreenOffAndKeyguardOn()
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.features.call.audio
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Binder
|
||||||
|
import android.os.IBinder
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import im.vector.app.core.extensions.startForegroundCompat
|
||||||
|
import im.vector.app.core.services.VectorAndroidService
|
||||||
|
import im.vector.app.features.notifications.NotificationUtils
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class MicrophoneAccessService : VectorAndroidService() {
|
||||||
|
|
||||||
|
@Inject lateinit var notificationUtils: NotificationUtils
|
||||||
|
private val binder = LocalBinder()
|
||||||
|
|
||||||
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
|
showMicrophoneAccessNotification()
|
||||||
|
|
||||||
|
return START_STICKY
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showMicrophoneAccessNotification() {
|
||||||
|
val notificationId = System.currentTimeMillis().toInt()
|
||||||
|
val notification = notificationUtils.buildMicrophoneAccessNotification()
|
||||||
|
startForegroundCompat(notificationId, notification)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBind(intent: Intent?): IBinder {
|
||||||
|
return binder
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class LocalBinder : Binder() {
|
||||||
|
fun getService(): MicrophoneAccessService = this@MicrophoneAccessService
|
||||||
|
}
|
||||||
|
}
|
|
@ -538,6 +538,19 @@ class NotificationUtils @Inject constructor(
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a notification indicating that the microphone is currently being accessed by the application.
|
||||||
|
*/
|
||||||
|
fun buildMicrophoneAccessNotification(): Notification {
|
||||||
|
return NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID)
|
||||||
|
.setContentTitle(stringProvider.getString(CommonStrings.microphone_in_use_title))
|
||||||
|
.setSmallIcon(R.drawable.ic_call_answer)
|
||||||
|
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||||
|
.setColor(ThemeUtils.getColor(context, android.R.attr.colorPrimary))
|
||||||
|
.setCategory(NotificationCompat.CATEGORY_CALL)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a notification that indicates the application is initializing.
|
* Creates a notification that indicates the application is initializing.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue