Skip to content

Commit 53387e6

Browse files
AmitShiloamitshilo11
authored andcommitted
Implemented a microphone access service to handle background microphone usage in calls.
Signed-off-by: AmitShilo <[email protected]>
1 parent 04a49e9 commit 53387e6

File tree

6 files changed

+108
-0
lines changed

6 files changed

+108
-0
lines changed

library/ui-strings/src/main/res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,8 @@
652652

653653
<string name="call_remove_jitsi_widget_progress">Ending call…</string>
654654

655+
<string name="microphone_in_use_title">Microphone in use</string>
656+
655657
<!-- permissions Android M -->
656658
<string name="permissions_rationale_popup_title">Information</string>
657659
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->

vector/src/main/AndroidManifest.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,13 @@
395395
android:foregroundServiceType="mediaProjection"
396396
tools:targetApi="Q" />
397397

398+
<service
399+
android:name=".features.call.audio.MicrophoneAccessService"
400+
android:exported="false"
401+
android:foregroundServiceType="microphone"
402+
android:permission="android.permission.FOREGROUND_SERVICE_MICROPHONE">
403+
</service>
404+
398405
<!-- Receivers -->
399406

400407
<receiver

vector/src/main/java/im/vector/app/core/services/CallAndroidService.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import im.vector.app.core.extensions.singletonEntryPoint
3131
import im.vector.app.core.extensions.startForegroundCompat
3232
import im.vector.app.features.call.CallArgs
3333
import im.vector.app.features.call.VectorCallActivity
34+
import im.vector.app.features.call.audio.MicrophoneAccessService
3435
import im.vector.app.features.call.telecom.CallConnection
3536
import im.vector.app.features.call.webrtc.WebRtcCall
3637
import im.vector.app.features.call.webrtc.WebRtcCallManager
@@ -208,6 +209,9 @@ class CallAndroidService : VectorAndroidService() {
208209
stopForegroundCompat()
209210
mediaSession?.isActive = false
210211
myStopSelf()
212+
213+
// Also stop the microphone service if it is running
214+
stopService(Intent(this, MicrophoneAccessService::class.java))
211215
}
212216
val wasConnected = connectedCallIds.remove(callId)
213217
if (!wasConnected && !terminatedCall.isOutgoing && !rejected && endCallReason != EndCallReason.ANSWERED_ELSEWHERE) {

vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import android.app.PictureInPictureParams
2222
import android.content.Context
2323
import android.content.Intent
2424
import android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP
25+
import android.content.pm.PackageManager
2526
import android.graphics.Color
2627
import android.media.projection.MediaProjection
2728
import android.media.projection.MediaProjectionManager
@@ -57,6 +58,7 @@ import im.vector.app.core.utils.PERMISSIONS_FOR_VIDEO_IP_CALL
5758
import im.vector.app.core.utils.checkPermissions
5859
import im.vector.app.core.utils.registerForPermissionsResult
5960
import im.vector.app.databinding.ActivityCallBinding
61+
import im.vector.app.features.call.audio.MicrophoneAccessService
6062
import im.vector.app.features.call.dialpad.CallDialPadBottomSheet
6163
import im.vector.app.features.call.dialpad.DialPadFragment
6264
import im.vector.app.features.call.transfer.CallTransferActivity
@@ -245,6 +247,33 @@ class VectorCallActivity :
245247
}
246248
}
247249

250+
private fun startMicrophoneService() {
251+
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED &&
252+
ContextCompat.checkSelfPermission(this, android.Manifest.permission.FOREGROUND_SERVICE_MICROPHONE) == PackageManager.PERMISSION_GRANTED) {
253+
Timber.tag(loggerTag.value).d("Starting MicrophoneAccessService.")
254+
val intent = Intent(this, MicrophoneAccessService::class.java)
255+
ContextCompat.startForegroundService(this, intent)
256+
} else {
257+
Timber.tag(loggerTag.value).w("Permissions not granted. Cannot start MicrophoneAccessService.")
258+
}
259+
}
260+
261+
private fun stopMicrophoneService() {
262+
Timber.tag(loggerTag.value).d("Stopping MicrophoneAccessService (if needed).")
263+
val intent = Intent(this, MicrophoneAccessService::class.java)
264+
stopService(intent)
265+
}
266+
267+
override fun onPause() {
268+
super.onPause()
269+
startMicrophoneService()
270+
}
271+
272+
override fun onResume() {
273+
super.onResume()
274+
stopMicrophoneService()
275+
}
276+
248277
override fun onDestroy() {
249278
detachRenderersIfNeeded()
250279
turnScreenOffAndKeyguardOn()
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) 2024 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package im.vector.app.features.call.audio
18+
19+
import android.content.Intent
20+
import android.os.Binder
21+
import android.os.IBinder
22+
import dagger.hilt.android.AndroidEntryPoint
23+
import im.vector.app.core.extensions.startForegroundCompat
24+
import im.vector.app.core.services.VectorAndroidService
25+
import im.vector.app.features.notifications.NotificationUtils
26+
import javax.inject.Inject
27+
28+
@AndroidEntryPoint
29+
class MicrophoneAccessService : VectorAndroidService() {
30+
31+
@Inject lateinit var notificationUtils: NotificationUtils
32+
private val binder = LocalBinder()
33+
34+
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
35+
showMicrophoneAccessNotification()
36+
37+
return START_STICKY
38+
}
39+
40+
private fun showMicrophoneAccessNotification() {
41+
val notificationId = System.currentTimeMillis().toInt()
42+
val notification = notificationUtils.buildMicrophoneAccessNotification()
43+
startForegroundCompat(notificationId, notification)
44+
}
45+
46+
override fun onBind(intent: Intent?): IBinder {
47+
return binder
48+
}
49+
50+
inner class LocalBinder : Binder() {
51+
fun getService(): MicrophoneAccessService = this@MicrophoneAccessService
52+
}
53+
}

vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,19 @@ class NotificationUtils @Inject constructor(
538538
.build()
539539
}
540540

541+
/**
542+
* Creates a notification indicating that the microphone is currently being accessed by the application.
543+
*/
544+
fun buildMicrophoneAccessNotification(): Notification {
545+
return NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID)
546+
.setContentTitle(stringProvider.getString(CommonStrings.microphone_in_use_title))
547+
.setSmallIcon(R.drawable.ic_call_answer)
548+
.setPriority(NotificationCompat.PRIORITY_LOW)
549+
.setColor(ThemeUtils.getColor(context, android.R.attr.colorPrimary))
550+
.setCategory(NotificationCompat.CATEGORY_CALL)
551+
.build()
552+
}
553+
541554
/**
542555
* Creates a notification that indicates the application is initializing.
543556
*/

0 commit comments

Comments
 (0)