android: fix call sound when the app in the background (#3660)

* android: fix call sound when the app in the background

* using previous notification channel

* Revert "using previous notification channel"

This reverts commit 19da9a9ce193c39b353f478e884a97bbbf002e77.

* prevent playing sound on call twice
This commit is contained in:
Stanislav Dmitrenko 2024-01-10 02:45:46 +07:00 committed by GitHub
parent 6067ac3c93
commit c7cf206585
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 23 additions and 14 deletions

View File

@ -164,7 +164,7 @@ class SimplexApp: Application(), LifecycleEventObserver {
androidAppContext = this androidAppContext = this
APPLICATION_ID = BuildConfig.APPLICATION_ID APPLICATION_ID = BuildConfig.APPLICATION_ID
ntfManager = object : chat.simplex.common.platform.NtfManager() { ntfManager = object : chat.simplex.common.platform.NtfManager() {
override fun notifyCallInvitation(invitation: RcvCallInvitation) = NtfManager.notifyCallInvitation(invitation) override fun notifyCallInvitation(invitation: RcvCallInvitation): Boolean = NtfManager.notifyCallInvitation(invitation)
override fun hasNotificationsForChat(chatId: String): Boolean = NtfManager.hasNotificationsForChat(chatId) override fun hasNotificationsForChat(chatId: String): Boolean = NtfManager.hasNotificationsForChat(chatId)
override fun cancelNotificationsForChat(chatId: String) = NtfManager.cancelNotificationsForChat(chatId) override fun cancelNotificationsForChat(chatId: String) = NtfManager.cancelNotificationsForChat(chatId)
override fun displayNotification(user: UserLike, chatId: String, displayName: String, msgText: String, image: String?, actions: List<Pair<NotificationAction, () -> Unit>>) = NtfManager.displayNotification(user, chatId, displayName, msgText, image, actions.map { it.first }) override fun displayNotification(user: UserLike, chatId: String, displayName: String, msgText: String, image: String?, actions: List<Pair<NotificationAction, () -> Unit>>) = NtfManager.displayNotification(user, chatId, displayName, msgText, image, actions.map { it.first })

View File

@ -30,7 +30,7 @@ object NtfManager {
const val ShowChatsAction: String = "chat.simplex.app.SHOW_CHATS" const val ShowChatsAction: String = "chat.simplex.app.SHOW_CHATS"
// DO NOT change notification channel settings / names // DO NOT change notification channel settings / names
const val CallChannel: String = "chat.simplex.app.CALL_NOTIFICATION_1" const val CallChannel: String = "chat.simplex.app.CALL_NOTIFICATION_2"
const val AcceptCallAction: String = "chat.simplex.app.ACCEPT_CALL" const val AcceptCallAction: String = "chat.simplex.app.ACCEPT_CALL"
const val RejectCallAction: String = "chat.simplex.app.REJECT_CALL" const val RejectCallAction: String = "chat.simplex.app.REJECT_CALL"
const val CallNotificationId: Int = -1 const val CallNotificationId: Int = -1
@ -59,7 +59,7 @@ object NtfManager {
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.build() .build()
val soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.packageName + "/" + R.raw.ring_once) val soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.packageName + "/raw/ring_once")
Log.d(TAG, "callNotificationChannel sound: $soundUri") Log.d(TAG, "callNotificationChannel sound: $soundUri")
callChannel.setSound(soundUri, attrs) callChannel.setSound(soundUri, attrs)
callChannel.enableVibration(true) callChannel.enableVibration(true)
@ -140,7 +140,7 @@ object NtfManager {
} }
} }
fun notifyCallInvitation(invitation: RcvCallInvitation) { fun notifyCallInvitation(invitation: RcvCallInvitation): Boolean {
val keyguardManager = getKeyguardManager(context) val keyguardManager = getKeyguardManager(context)
Log.d( Log.d(
TAG, TAG,
@ -149,7 +149,7 @@ object NtfManager {
"callOnLockScreen ${appPreferences.callOnLockScreen.get()}, " + "callOnLockScreen ${appPreferences.callOnLockScreen.get()}, " +
"onForeground ${isAppOnForeground}" "onForeground ${isAppOnForeground}"
) )
if (isAppOnForeground) return if (isAppOnForeground) return false
val contactId = invitation.contact.id val contactId = invitation.contact.id
Log.d(TAG, "notifyCallInvitation $contactId") Log.d(TAG, "notifyCallInvitation $contactId")
val image = invitation.contact.image val image = invitation.contact.image
@ -163,7 +163,7 @@ object NtfManager {
.setFullScreenIntent(fullScreenPendingIntent, true) .setFullScreenIntent(fullScreenPendingIntent, true)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
} else { } else {
val soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.packageName + "/" + R.raw.ring_once) val soundUri = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + context.packageName + "/raw/ring_once")
val fullScreenPendingIntent = PendingIntent.getActivity(context, 0, Intent(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) val fullScreenPendingIntent = PendingIntent.getActivity(context, 0, Intent(), PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
NotificationCompat.Builder(context, CallChannel) NotificationCompat.Builder(context, CallChannel)
.setContentIntent(chatPendingIntent(OpenChatAction, invitation.user.userId, invitation.contact.id)) .setContentIntent(chatPendingIntent(OpenChatAction, invitation.user.userId, invitation.contact.id))
@ -206,6 +206,7 @@ object NtfManager {
notify(CallNotificationId, notification) notify(CallNotificationId, notification)
} }
} }
return true
} }
fun showMessage(title: String, text: String) { fun showMessage(title: String, text: String) {
@ -280,6 +281,7 @@ object NtfManager {
manager.createNotificationChannel(callNotificationChannel(CallChannel, generalGetString(MR.strings.ntf_channel_calls))) manager.createNotificationChannel(callNotificationChannel(CallChannel, generalGetString(MR.strings.ntf_channel_calls)))
// Remove old channels since they can't be edited // Remove old channels since they can't be edited
manager.deleteNotificationChannel("chat.simplex.app.CALL_NOTIFICATION") manager.deleteNotificationChannel("chat.simplex.app.CALL_NOTIFICATION")
manager.deleteNotificationChannel("chat.simplex.app.CALL_NOTIFICATION_1")
manager.deleteNotificationChannel("chat.simplex.app.LOCK_SCREEN_CALL_NOTIFICATION") manager.deleteNotificationChannel("chat.simplex.app.LOCK_SCREEN_CALL_NOTIFICATION")
} }

View File

@ -93,7 +93,7 @@ abstract class NtfManager {
} }
} }
abstract fun notifyCallInvitation(invitation: RcvCallInvitation) abstract fun notifyCallInvitation(invitation: RcvCallInvitation): Boolean
abstract fun hasNotificationsForChat(chatId: String): Boolean abstract fun hasNotificationsForChat(chatId: String): Boolean
abstract fun cancelNotificationsForChat(chatId: String) abstract fun cancelNotificationsForChat(chatId: String)
abstract fun displayNotification(user: UserLike, chatId: String, displayName: String, msgText: String, image: String? = null, actions: List<Pair<NotificationAction, () -> Unit>> = emptyList()) abstract fun displayNotification(user: UserLike, chatId: String, displayName: String, msgText: String, image: String? = null, actions: List<Pair<NotificationAction, () -> Unit>> = emptyList())

View File

@ -13,8 +13,8 @@ class CallManager(val chatModel: ChatModel) {
callInvitations[invitation.contact.id] = invitation callInvitations[invitation.contact.id] = invitation
if (invitation.user.showNotifications) { if (invitation.user.showNotifications) {
if (Clock.System.now() - invitation.callTs <= 3.minutes) { if (Clock.System.now() - invitation.callTs <= 3.minutes) {
invitation.sentNotification = ntfManager.notifyCallInvitation(invitation)
activeCallInvitation.value = invitation activeCallInvitation.value = invitation
ntfManager.notifyCallInvitation(invitation)
} else { } else {
val contact = invitation.contact val contact = invitation.contact
ntfManager.displayNotification(user = invitation.user, chatId = contact.id, displayName = contact.displayName, msgText = invitation.callTypeText) ntfManager.displayNotification(user = invitation.user, chatId = contact.id, displayName = contact.displayName, msgText = invitation.callTypeText)

View File

@ -15,11 +15,10 @@ import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import chat.simplex.common.model.* import chat.simplex.common.model.*
import chat.simplex.common.platform.*
import chat.simplex.common.ui.theme.* import chat.simplex.common.ui.theme.*
import chat.simplex.common.views.helpers.ProfileImage import chat.simplex.common.views.helpers.ProfileImage
import chat.simplex.common.views.usersettings.ProfilePreview import chat.simplex.common.views.usersettings.ProfilePreview
import chat.simplex.common.platform.ntfManager
import chat.simplex.common.platform.SoundPlayer
import chat.simplex.res.MR import chat.simplex.res.MR
import kotlinx.datetime.Clock import kotlinx.datetime.Clock
@ -27,7 +26,11 @@ import kotlinx.datetime.Clock
fun IncomingCallAlertView(invitation: RcvCallInvitation, chatModel: ChatModel) { fun IncomingCallAlertView(invitation: RcvCallInvitation, chatModel: ChatModel) {
val cm = chatModel.callManager val cm = chatModel.callManager
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
LaunchedEffect(true) { SoundPlayer.start(scope, sound = !chatModel.showCallView.value) } LaunchedEffect(Unit) {
if (chatModel.activeCallInvitation.value?.sentNotification == false || appPlatform.isDesktop) {
SoundPlayer.start(scope, sound = !chatModel.showCallView.value)
}
}
DisposableEffect(true) { onDispose { SoundPlayer.stop() } } DisposableEffect(true) { onDispose { SoundPlayer.stop() } }
IncomingCallAlertLayout( IncomingCallAlertLayout(
invitation, invitation,

View File

@ -112,6 +112,9 @@ sealed class WCallResponse {
CallMediaType.Video -> MR.strings.incoming_video_call CallMediaType.Video -> MR.strings.incoming_video_call
CallMediaType.Audio -> MR.strings.incoming_audio_call CallMediaType.Audio -> MR.strings.incoming_audio_call
}) })
// Shows whether notification was shown or not to prevent playing sound twice in both notification and in-app
var sentNotification: Boolean = false
} }
@Serializable data class CallCapabilities(val encryption: Boolean) @Serializable data class CallCapabilities(val encryption: Boolean)
@Serializable data class ConnectionInfo(private val localCandidate: RTCIceCandidate?, private val remoteCandidate: RTCIceCandidate?) { @Serializable data class ConnectionInfo(private val localCandidate: RTCIceCandidate?, private val remoteCandidate: RTCIceCandidate?) {

View File

@ -16,8 +16,8 @@ import javax.imageio.ImageIO
object NtfManager { object NtfManager {
private val prevNtfs = arrayListOf<Pair<ChatId, Slice>>() private val prevNtfs = arrayListOf<Pair<ChatId, Slice>>()
fun notifyCallInvitation(invitation: RcvCallInvitation) { fun notifyCallInvitation(invitation: RcvCallInvitation): Boolean {
if (simplexWindowState.windowFocused.value) return if (simplexWindowState.windowFocused.value) return false
val contactId = invitation.contact.id val contactId = invitation.contact.id
Log.d(TAG, "notifyCallInvitation $contactId") Log.d(TAG, "notifyCallInvitation $contactId")
val image = invitation.contact.image val image = invitation.contact.image
@ -45,6 +45,7 @@ object NtfManager {
displayNotificationViaLib(contactId, title, text, prepareIconPath(largeIcon), actions) { displayNotificationViaLib(contactId, title, text, prepareIconPath(largeIcon), actions) {
ntfManager.openChatAction(invitation.user.userId, contactId) ntfManager.openChatAction(invitation.user.userId, contactId)
} }
return true
} }
fun showMessage(title: String, text: String) { fun showMessage(title: String, text: String) {

View File

@ -16,7 +16,7 @@ val defaultLocale: Locale = Locale.getDefault()
fun initApp() { fun initApp() {
ntfManager = object : NtfManager() { ntfManager = object : NtfManager() {
override fun notifyCallInvitation(invitation: RcvCallInvitation) = chat.simplex.common.model.NtfManager.notifyCallInvitation(invitation) override fun notifyCallInvitation(invitation: RcvCallInvitation): Boolean = chat.simplex.common.model.NtfManager.notifyCallInvitation(invitation)
override fun hasNotificationsForChat(chatId: String): Boolean = chat.simplex.common.model.NtfManager.hasNotificationsForChat(chatId) override fun hasNotificationsForChat(chatId: String): Boolean = chat.simplex.common.model.NtfManager.hasNotificationsForChat(chatId)
override fun cancelNotificationsForChat(chatId: String) = chat.simplex.common.model.NtfManager.cancelNotificationsForChat(chatId) override fun cancelNotificationsForChat(chatId: String) = chat.simplex.common.model.NtfManager.cancelNotificationsForChat(chatId)
override fun displayNotification(user: UserLike, chatId: String, displayName: String, msgText: String, image: String?, actions: List<Pair<NotificationAction, () -> Unit>>) = chat.simplex.common.model.NtfManager.displayNotification(user, chatId, displayName, msgText, image, actions) override fun displayNotification(user: UserLike, chatId: String, displayName: String, msgText: String, image: String?, actions: List<Pair<NotificationAction, () -> Unit>>) = chat.simplex.common.model.NtfManager.displayNotification(user, chatId, displayName, msgText, image, actions)