diff --git a/app/src/main/assets/linphonerc_factory b/app/src/main/assets/linphonerc_factory
index 58a9c38e2..fc2954596 100644
--- a/app/src/main/assets/linphonerc_factory
+++ b/app/src/main/assets/linphonerc_factory
@@ -27,6 +27,7 @@ rls_uri=sips:rls@sip.linphone.org
[sound]
#remove this property for any application that is not Linphone public version itself
ec_calibrator_cool_tones=1
+disable_ringing=1
[audio]
android_disable_audio_focus_requests=1
diff --git a/app/src/main/java/org/linphone/core/CoreContext.kt b/app/src/main/java/org/linphone/core/CoreContext.kt
index 74be178cd..67b2827d5 100644
--- a/app/src/main/java/org/linphone/core/CoreContext.kt
+++ b/app/src/main/java/org/linphone/core/CoreContext.kt
@@ -262,6 +262,8 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C
val audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
audioManager.registerAudioDeviceCallback(audioDeviceCallback, coreThread)
+ corePreferences.linphoneConfigurationVersion = "6.0"
+
Log.i("$TAG Report Core created and started")
}
diff --git a/app/src/main/java/org/linphone/core/CorePreferences.kt b/app/src/main/java/org/linphone/core/CorePreferences.kt
index 43c6ae520..958fe90de 100644
--- a/app/src/main/java/org/linphone/core/CorePreferences.kt
+++ b/app/src/main/java/org/linphone/core/CorePreferences.kt
@@ -126,6 +126,13 @@ class CorePreferences @UiThread constructor(private val context: Context) {
config.setInt("app", "dark_mode", value)
}
+ @get:WorkerThread @set:WorkerThread
+ var linphoneConfigurationVersion: String
+ get() = config.getString("app", "linphonerc_version", "5.2")!!
+ set(value) {
+ config.setString("app", "linphonerc_version", value)
+ }
+
@get:WorkerThread
val darkModeAllowed: Boolean
get() = config.getBool("ui", "dark_mode_allowed", true)
diff --git a/app/src/main/java/org/linphone/notifications/NotificationsManager.kt b/app/src/main/java/org/linphone/notifications/NotificationsManager.kt
index 988120b86..8adb34914 100644
--- a/app/src/main/java/org/linphone/notifications/NotificationsManager.kt
+++ b/app/src/main/java/org/linphone/notifications/NotificationsManager.kt
@@ -29,6 +29,9 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
+import android.media.AudioAttributes
+import android.media.AudioManager
+import android.media.RingtoneManager
import android.net.Uri
import android.os.Bundle
import androidx.annotation.AnyThread
@@ -88,6 +91,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
private const val MISSED_CALL_TAG = "Missed call"
const val CHAT_NOTIFICATIONS_GROUP = "CHAT_NOTIF_GROUP"
+ private const val INCOMING_CALL_ID = 1
private const val MISSED_CALL_ID = 10
}
@@ -321,12 +325,6 @@ class NotificationsManager @MainThread constructor(private val context: Context)
private var currentlyDisplayedChatRoomId: String = ""
init {
- createServiceChannel()
- createIncomingCallNotificationChannel()
- createMissedCallNotificationChannel()
- createActiveCallNotificationChannel()
- createMessageChannel()
-
for (notification in notificationManager.activeNotifications) {
if (notification.tag.isNullOrEmpty()) {
Log.w(
@@ -365,8 +363,10 @@ class NotificationsManager @MainThread constructor(private val context: Context)
if (core.callsNb == 0) {
Log.w("$TAG No call anymore, stopping service")
stopCallForeground()
- } else {
- Log.i("$TAG At least a call is still running")
+ } else if (currentForegroundServiceNotificationId == -1) {
+ Log.i(
+ "$TAG At least a call is still running and no foreground service notification was found"
+ )
val call = core.currentCall ?: core.calls.first()
startCallForeground(call)
}
@@ -379,9 +379,33 @@ class NotificationsManager @MainThread constructor(private val context: Context)
coreService = null
}
+ @MainThread
+ private fun createChannels(clearPreviousChannels: Boolean) {
+ if (clearPreviousChannels) {
+ Log.w("$TAG We were asked to remove all existing notification channels")
+ for (channel in notificationManager.notificationChannels) {
+ Log.i("$TAG Deleting notification channel ID [${channel.id}]")
+ notificationManager.deleteNotificationChannel(channel.id)
+ }
+ }
+
+ createServiceChannel()
+ createIncomingCallNotificationChannel()
+ createMissedCallNotificationChannel()
+ createActiveCallNotificationChannel()
+ createMessageChannel()
+ }
+
@WorkerThread
fun onCoreStarted(core: Core) {
Log.i("$TAG Core has been started")
+
+ val rcVersion = corePreferences.linphoneConfigurationVersion
+ val clearPreviousChannels = rcVersion == "5.2"
+ coreContext.postOnMainThread {
+ createChannels(clearPreviousChannels)
+ }
+
core.addListener(coreListener)
}
@@ -394,6 +418,22 @@ class NotificationsManager @MainThread constructor(private val context: Context)
@WorkerThread
private fun showCallNotification(call: Call, isIncoming: Boolean) {
val notifiable = getNotifiableForCall(call)
+ if (!isIncoming && call.dir == Call.Dir.Incoming) {
+ if (currentForegroundServiceNotificationId == INCOMING_CALL_ID) {
+ // This is an accepted incoming call, remove notification before adding it again to change channel
+ Log.i(
+ "$TAG Incoming call with notification ID [${notifiable.notificationId}] was accepted, cancelling notification before adding it again to the right channel"
+ )
+ if (coreService != null) {
+ Log.i(
+ "$TAG Service found, stopping it as foreground before cancelling notification"
+ )
+ coreService?.stopForeground(STOP_FOREGROUND_REMOVE)
+ }
+ cancelNotification(INCOMING_CALL_ID)
+ currentForegroundServiceNotificationId = -1
+ }
+ }
val callNotificationIntent = Intent(context, CallActivity::class.java)
callNotificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
@@ -417,10 +457,16 @@ class NotificationsManager @MainThread constructor(private val context: Context)
pendingIntent,
isIncoming
)
- notify(notifiable.notificationId, notification)
-
- if (notifiable.notificationId == currentForegroundServiceNotificationId) {
- startCallForeground(call)
+ if (isIncoming) {
+ notify(INCOMING_CALL_ID, notification)
+ if (currentForegroundServiceNotificationId == -1) {
+ startIncomingCallForeground(notification)
+ }
+ } else {
+ notify(notifiable.notificationId, notification)
+ if (currentForegroundServiceNotificationId == -1) {
+ startCallForeground(call)
+ }
}
}
@@ -465,6 +511,26 @@ class NotificationsManager @MainThread constructor(private val context: Context)
notify(MISSED_CALL_ID, notification, MISSED_CALL_TAG)
}
+ @WorkerThread
+ private fun startIncomingCallForeground(notification: Notification) {
+ Log.i("$TAG Trying to start foreground Service using incoming call notification")
+ val service = coreService
+ if (service != null) {
+ Log.i(
+ "$TAG Service found, starting it as foreground using notification ID [$INCOMING_CALL_ID] with type PHONE_CALL"
+ )
+ Compatibility.startServiceForeground(
+ service,
+ INCOMING_CALL_ID,
+ notification,
+ Compatibility.FOREGROUND_SERVICE_TYPE_PHONE_CALL
+ )
+ currentForegroundServiceNotificationId = INCOMING_CALL_ID
+ } else {
+ Log.w("$TAG Core Foreground Service hasn't started yet...")
+ }
+ }
+
@WorkerThread
private fun startCallForeground(call: Call) {
Log.i("$TAG Trying to start/update foreground Service using call notification")
@@ -863,19 +929,15 @@ class NotificationsManager @MainThread constructor(private val context: Context)
channel
).apply {
try {
- style.setIsVideo(isVideo)
- style.setAnswerButtonColorHint(
- context.getColor(R.color.success_500)
- )
- style.setDeclineButtonColorHint(
- context.getColor(R.color.danger_500)
- )
+ style.setIsVideo(false)
setStyle(style)
} catch (iae: IllegalArgumentException) {
Log.e(
"$TAG Can't use notification call style: $iae"
)
}
+ setColorized(true)
+ setOnlyAlertOnce(true)
setSmallIcon(smallIcon)
setCategory(NotificationCompat.CATEGORY_CALL)
setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
@@ -1017,7 +1079,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
return PendingIntent.getBroadcast(
context,
- notifiable.notificationId,
+ 3,
hangupIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
@@ -1032,7 +1094,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
return PendingIntent.getBroadcast(
context,
- notifiable.notificationId,
+ 2,
answerIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
@@ -1146,13 +1208,16 @@ class NotificationsManager @MainThread constructor(private val context: Context)
val id = context.getString(R.string.notification_channel_incoming_call_id)
val name = context.getString(R.string.notification_channel_incoming_call_name)
+ val ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE)
+ val audioAttributes = AudioAttributes.Builder()
+ .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+ .setLegacyStreamType(AudioManager.STREAM_RING)
+ .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build()
+
val channel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_HIGH).apply {
description = name
- lightColor = context.getColor(R.color.main1_500)
- lockscreenVisibility = Notification.VISIBILITY_PUBLIC
enableVibration(true)
- enableLights(true)
- setShowBadge(false)
+ setSound(ringtone, audioAttributes)
}
notificationManager.createNotificationChannel(channel)
}
@@ -1164,11 +1229,8 @@ class NotificationsManager @MainThread constructor(private val context: Context)
val channel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_HIGH).apply {
description = name
- lightColor = context.getColor(R.color.main1_500)
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
enableVibration(true)
- enableLights(true)
- setShowBadge(false)
}
notificationManager.createNotificationChannel(channel)
}
@@ -1181,9 +1243,6 @@ class NotificationsManager @MainThread constructor(private val context: Context)
val channel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_DEFAULT).apply {
description = name
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
- enableVibration(false)
- enableLights(false)
- setShowBadge(false)
}
notificationManager.createNotificationChannel(channel)
}
@@ -1195,11 +1254,8 @@ class NotificationsManager @MainThread constructor(private val context: Context)
val channel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_HIGH).apply {
description = name
- lightColor = context.getColor(R.color.main1_500)
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
- enableLights(true)
enableVibration(true)
- setShowBadge(true)
}
notificationManager.createNotificationChannel(channel)
}
@@ -1211,9 +1267,6 @@ class NotificationsManager @MainThread constructor(private val context: Context)
val channel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_LOW).apply {
description = name
- enableVibration(false)
- enableLights(false)
- setShowBadge(false)
}
notificationManager.createNotificationChannel(channel)
}
diff --git a/app/src/main/java/org/linphone/telecom/TelecomCallControlCallback.kt b/app/src/main/java/org/linphone/telecom/TelecomCallControlCallback.kt
index f209c11de..1f1539793 100644
--- a/app/src/main/java/org/linphone/telecom/TelecomCallControlCallback.kt
+++ b/app/src/main/java/org/linphone/telecom/TelecomCallControlCallback.kt
@@ -34,7 +34,6 @@ import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.core.AudioDevice
import org.linphone.core.Call
import org.linphone.core.CallListenerStub
-import org.linphone.core.MediaDirection
import org.linphone.core.tools.Log
import org.linphone.utils.AudioUtils
@@ -55,15 +54,9 @@ class TelecomCallControlCallback(
Log.i("$TAG Call [${call.remoteAddress.asStringUriOnly()}] state changed [$state]")
if (state == Call.State.Connected) {
if (call.dir == Call.Dir.Incoming) {
- val videoEnabled = call.currentParams.isVideoEnabled && call.currentParams.videoDirection != MediaDirection.Inactive
scope.launch {
- val type = if (videoEnabled) {
- CallAttributesCompat.CALL_TYPE_VIDEO_CALL
- } else {
- CallAttributesCompat.CALL_TYPE_AUDIO_CALL
- }
- Log.i("$TAG Answering call with type [$type]")
- callControl.answer(type)
+ Log.i("$TAG Answering call")
+ callControl.answer(CallAttributesCompat.CALL_TYPE_AUDIO_CALL)
}
} else {
scope.launch {
@@ -74,7 +67,7 @@ class TelecomCallControlCallback(
} else if (state == Call.State.End) {
scope.launch {
Log.i("$TAG Disconnecting call")
- callControl.disconnect(DisconnectCause(DisconnectCause.REMOTE))
+ callControl.disconnect(DisconnectCause(DisconnectCause.LOCAL))
}
} else if (state == Call.State.Pausing) {
scope.launch {
diff --git a/app/src/main/java/org/linphone/telecom/TelecomManager.kt b/app/src/main/java/org/linphone/telecom/TelecomManager.kt
index 2f790afd0..554d1377e 100644
--- a/app/src/main/java/org/linphone/telecom/TelecomManager.kt
+++ b/app/src/main/java/org/linphone/telecom/TelecomManager.kt
@@ -33,7 +33,6 @@ import org.linphone.core.AudioDevice
import org.linphone.core.Call
import org.linphone.core.Core
import org.linphone.core.CoreListenerStub
-import org.linphone.core.MediaDirection
import org.linphone.core.tools.Log
import org.linphone.utils.LinphoneUtils
@@ -51,98 +50,7 @@ class TelecomManager @WorkerThread constructor(context: Context) {
private val coreListener = object : CoreListenerStub() {
@WorkerThread
override fun onCallCreated(core: Core, call: Call) {
- Log.i("$TAG Call created: $call")
-
- val address = call.remoteAddress
- val friend = coreContext.contactsManager.findContactByAddress(address)
- val displayName = friend?.name ?: LinphoneUtils.getDisplayName(address)
-
- val uri = Uri.parse(address.asStringUriOnly())
-
- val direction = if (call.dir == Call.Dir.Outgoing) {
- CallAttributesCompat.DIRECTION_OUTGOING
- } else {
- CallAttributesCompat.DIRECTION_INCOMING
- }
-
- val params = if (call.dir == Call.Dir.Outgoing) {
- call.params
- } else {
- call.remoteParams
- }
- val type = if (params?.isVideoEnabled == true && params.videoDirection != MediaDirection.Inactive) {
- CallAttributesCompat.CALL_TYPE_VIDEO_CALL
- } else {
- CallAttributesCompat.CALL_TYPE_AUDIO_CALL
- }
-
- val capabilities = CallAttributesCompat.SUPPORTS_SET_INACTIVE or CallAttributesCompat.SUPPORTS_TRANSFER
-
- val callAttributes = CallAttributesCompat(
- displayName,
- uri,
- direction,
- type,
- capabilities
- )
- Log.i("$TAG Adding call to Telecom's CallsManager with attributes [$callAttributes]")
-
- scope.launch {
- try {
- callsManager.addCall(
- callAttributes,
- { callType -> // onAnswer
- Log.i("$TAG We're asked to answer the call with type [$callType]")
- coreContext.postOnCoreThread {
- if (LinphoneUtils.isCallIncoming(call.state)) {
- Log.i("$TAG Answering call")
- coreContext.answerCall(call) // TODO FIXME: use call type
- }
- }
- },
- { disconnectCause -> // onDisconnect
- Log.i(
- "$TAG We're asked to terminate the call with reason [$disconnectCause]"
- )
- coreContext.postOnCoreThread {
- Log.i(
- "$TAG Terminating call [${call.remoteAddress.asStringUriOnly()}]"
- )
- call.terminate() // TODO FIXME: use cause
- }
- },
- { // onSetActive
- Log.i("$TAG We're asked to resume the call")
- coreContext.postOnCoreThread {
- Log.i("$TAG Resuming call")
- call.resume()
- }
- },
- { // onSetInactive
- Log.i("$TAG We're asked to pause the call")
- coreContext.postOnCoreThread {
- Log.i("$TAG Pausing call")
- call.pause()
- }
- }
- ) {
- val callbacks = TelecomCallControlCallback(call, this, scope)
-
- coreContext.postOnCoreThread {
- val callId = call.callLog.callId.orEmpty()
- if (callId.isNotEmpty()) {
- Log.i("$TAG Storing our callbacks for call ID [$callId]")
- map[callId] = callbacks
- }
- }
-
- // We must first call setCallback on callControlScope before using it
- callbacks.onCallControlCallbackSet()
- }
- } catch (e: Exception) {
- Log.e("$TAG Failed to add call to Telecom's CallsManager!")
- }
- }
+ onCallCreated(call)
}
}
@@ -157,6 +65,91 @@ class TelecomManager @WorkerThread constructor(context: Context) {
)
}
+ @WorkerThread
+ fun onCallCreated(call: Call) {
+ Log.i("$TAG Call created: $call")
+
+ val address = call.remoteAddress
+ val friend = coreContext.contactsManager.findContactByAddress(address)
+ val displayName = friend?.name ?: LinphoneUtils.getDisplayName(address)
+
+ val uri = Uri.parse(address.asStringUriOnly())
+
+ val direction = if (call.dir == Call.Dir.Outgoing) {
+ CallAttributesCompat.DIRECTION_OUTGOING
+ } else {
+ CallAttributesCompat.DIRECTION_INCOMING
+ }
+
+ val capabilities = CallAttributesCompat.SUPPORTS_SET_INACTIVE or CallAttributesCompat.SUPPORTS_TRANSFER
+
+ val callAttributes = CallAttributesCompat(
+ displayName,
+ uri,
+ direction,
+ CallAttributesCompat.CALL_TYPE_AUDIO_CALL,
+ capabilities
+ )
+ Log.i("$TAG Adding call to Telecom's CallsManager with attributes [$callAttributes]")
+
+ scope.launch {
+ try {
+ callsManager.addCall(
+ callAttributes,
+ { callType -> // onAnswer
+ Log.i("$TAG We're asked to answer the call with type [$callType]")
+ coreContext.postOnCoreThread {
+ if (LinphoneUtils.isCallIncoming(call.state)) {
+ Log.i("$TAG Answering call")
+ coreContext.answerCall(call)
+ }
+ }
+ },
+ { disconnectCause -> // onDisconnect
+ Log.i(
+ "$TAG We're asked to terminate the call with reason [$disconnectCause]"
+ )
+ coreContext.postOnCoreThread {
+ Log.i(
+ "$TAG Terminating call [${call.remoteAddress.asStringUriOnly()}]"
+ )
+ call.terminate() // TODO FIXME: use cause
+ }
+ },
+ { // onSetActive
+ Log.i("$TAG We're asked to resume the call")
+ coreContext.postOnCoreThread {
+ Log.i("$TAG Resuming call")
+ call.resume()
+ }
+ },
+ { // onSetInactive
+ Log.i("$TAG We're asked to pause the call")
+ coreContext.postOnCoreThread {
+ Log.i("$TAG Pausing call")
+ call.pause()
+ }
+ }
+ ) {
+ val callbacks = TelecomCallControlCallback(call, this, scope)
+
+ coreContext.postOnCoreThread {
+ val callId = call.callLog.callId.orEmpty()
+ if (callId.isNotEmpty()) {
+ Log.i("$TAG Storing our callbacks for call ID [$callId]")
+ map[callId] = callbacks
+ }
+ }
+
+ // We must first call setCallback on callControlScope before using it
+ callbacks.onCallControlCallbackSet()
+ }
+ } catch (e: Exception) {
+ Log.e("$TAG Failed to add call to Telecom's CallsManager!")
+ }
+ }
+ }
+
@WorkerThread
fun onCoreStarted(core: Core) {
Log.i("$TAG Core has been started")
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 19f2a18df..d96a62b76 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -13,11 +13,11 @@
subscribe.linphone.org
linphone.org/contact
- linphone_notification_call_id
- linphone_notification_incoming_call_id
- linphone_notification_missed_call_id
- linphone_notification_service_id
- linphone_notification_chat_id
+ linphone_6.0_notification_call_id
+ linphone_6.0_notification_incoming_call_id
+ linphone_6.0_notification_missed_call_id
+ linphone_6.0_notification_service_id
+ linphone_6.0_notification_chat_id
❤️
👍