Fixed issues with incoming call notification not being dismissed in some cases + fixed toast in case of remote provisioning issue

This commit is contained in:
Sylvain Berfini 2024-04-09 14:08:23 +02:00
parent 6e97466a86
commit 5a37f15bc7
8 changed files with 92 additions and 35 deletions

View file

@ -97,6 +97,7 @@
<data android:scheme="tel" />
<data android:scheme="sip" />
<data android:scheme="sips" />
<data android:scheme="linphone-config" />
</intent-filter>
</activity>

View file

@ -120,15 +120,15 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C
status: ConfiguringState?,
message: String?
) {
Log.i("$TAG Configuring state changed [$status]")
Log.i("$TAG Configuring state changed [$status], message is [$message]")
if (status == ConfiguringState.Successful) {
val text = context.getString(
org.linphone.R.string.assistant_qr_code_provisioning_done
org.linphone.R.string.toast_remote_provisioning_config_applied
)
greenToastToShowEvent.postValue(Event(Pair(text, org.linphone.R.drawable.smiley)))
} else if (status == ConfiguringState.Failed) {
val text = context.getString(
org.linphone.R.string.assistant_qr_code_provisioning_done
org.linphone.R.string.toast_remote_provisioning_config_failed
)
redToastToShowEvent.postValue(
Event(Pair(text, org.linphone.R.drawable.warning_circle))
@ -505,7 +505,9 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C
fun terminateCall(call: Call) {
if (call.dir == Call.Dir.Incoming && LinphoneUtils.isCallIncoming(call.state)) {
val reason = if (call.core.callsNb > 1) Reason.Busy else Reason.Declined
Log.i("$TAG Declining call [${call.remoteAddress.asStringUriOnly()}] with reason [$reason]")
Log.i(
"$TAG Declining call [${call.remoteAddress.asStringUriOnly()}] with reason [$reason]"
)
call.decline(reason)
} else {
Log.i("$TAG Terminating call [${call.remoteAddress.asStringUriOnly()}]")

View file

@ -26,7 +26,6 @@ import android.content.Context
import android.content.Intent
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.core.tools.Log
import org.linphone.utils.LinphoneUtils
class NotificationBroadcastReceiver : BroadcastReceiver() {
companion object {

View file

@ -97,6 +97,8 @@ class NotificationsManager @MainThread constructor(private val context: Context)
private var currentForegroundServiceNotificationId = -1
private var currentlyRingingCallRemoteAddress: Address? = null
private val notificationManager: NotificationManagerCompat by lazy {
NotificationManagerCompat.from(context)
}
@ -117,14 +119,32 @@ class NotificationsManager @MainThread constructor(private val context: Context)
showCallNotification(call, true)
}
Call.State.Connected -> {
if (call.dir == Call.Dir.Incoming) {
Log.i(
"$TAG Connected call was incoming (so it was answered), removing incoming call notification"
)
removeIncomingCallNotification()
}
Log.i(
"$TAG Showing connected call notification for [${call.remoteAddress.asStringUriOnly()}]"
)
showCallNotification(call, false)
}
Call.State.End, Call.State.Error -> {
val remoteSipAddress = call.remoteAddress
if (call.dir == Call.Dir.Incoming && currentlyRingingCallRemoteAddress?.weakEqual(
remoteSipAddress
) == true
) {
Log.i(
"$TAG Incoming call has been declined, cancelling incoming call notification"
)
removeIncomingCallNotification()
}
Log.i(
"$TAG Removing terminated call notification for [${call.remoteAddress.asStringUriOnly()}]"
"$TAG Removing terminated/declined call notification for [${remoteSipAddress.asStringUriOnly()}]"
)
dismissCallNotification(call)
}
@ -415,25 +435,31 @@ class NotificationsManager @MainThread constructor(private val context: Context)
core.removeListener(coreListener)
}
@WorkerThread
fun removeIncomingCallNotification() {
if (currentForegroundServiceNotificationId == INCOMING_CALL_ID) {
if (coreService != null) {
Log.i(
"$TAG Service found, stopping it as foreground before cancelling notification"
)
coreService?.stopForeground(STOP_FOREGROUND_REMOVE)
} else {
Log.w("$TAG Incoming call foreground notification Service wasn't found, weird...")
}
currentForegroundServiceNotificationId = -1
} else {
Log.i(
"$TAG Incoming call notification wasn't used to keep running Service as foreground"
)
}
cancelNotification(INCOMING_CALL_ID)
currentlyRingingCallRemoteAddress = null
}
@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)
@ -458,6 +484,7 @@ class NotificationsManager @MainThread constructor(private val context: Context)
isIncoming
)
if (isIncoming) {
currentlyRingingCallRemoteAddress = call.remoteAddress
notify(INCOMING_CALL_ID, notification)
if (currentForegroundServiceNotificationId == -1) {
startIncomingCallForeground(notification)

View file

@ -21,7 +21,6 @@ package org.linphone.telecom
import android.content.Context
import android.net.Uri
import android.telecom.DisconnectCause
import androidx.annotation.WorkerThread
import androidx.core.telecom.CallAttributesCompat
import androidx.core.telecom.CallsManager
@ -34,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.Reason
import org.linphone.core.tools.Log
import org.linphone.utils.LinphoneUtils

View file

@ -184,6 +184,22 @@ class MainActivity : GenericActivity() {
Log.e("$TAG Security exception when doing reportFullyDrawn(): $se")
}
}
coreContext.greenToastToShowEvent.observe(this) {
it.consume { pair ->
val message = pair.first
val icon = pair.second
showGreenToast(message, icon)
}
}
coreContext.redToastToShowEvent.observe(this) {
it.consume { pair ->
val message = pair.first
val icon = pair.second
showRedToast(message, icon)
}
}
}
override fun onPostCreate(savedInstanceState: Bundle?) {
@ -204,14 +220,6 @@ class MainActivity : GenericActivity() {
}
}
coreContext.greenToastToShowEvent.observe(this) {
it.consume { pair ->
val message = pair.first
val icon = pair.second
showGreenToast(message, icon)
}
}
if (intent != null) {
handleIntent(intent, false)
} else {
@ -394,7 +402,15 @@ class MainActivity : GenericActivity() {
Intent.ACTION_SEND_MULTIPLE -> {
handleSendIntent(intent, true)
}
Intent.ACTION_VIEW, Intent.ACTION_DIAL, Intent.ACTION_CALL -> {
Intent.ACTION_VIEW -> {
val uri = intent.data?.toString() ?: ""
if (uri.startsWith("linphone-config:")) {
handleConfigIntent(uri)
} else {
handleCallIntent(intent)
}
}
Intent.ACTION_DIAL, Intent.ACTION_CALL -> {
handleCallIntent(intent)
}
Intent.ACTION_VIEW_LOCUS -> {
@ -627,6 +643,18 @@ class MainActivity : GenericActivity() {
}
}
@MainThread
private fun handleConfigIntent(uri: String) {
val remoteConfigUri = uri.substring("linphone-config:".length)
coreContext.postOnCoreThread { core ->
coreContext.core.provisioningUri = remoteConfigUri
Log.w("$TAG Remote provisioning URL set to [$remoteConfigUri], restarting Core now")
coreContext.core.stop()
coreContext.core.start()
Log.i("$TAG Core restarted after remote provisioning URL was applied")
}
}
private fun loadContacts() {
coreContext.contactsManager.loadContacts(this)
}

View file

@ -102,6 +102,8 @@
<string name="toast_call_transfer_in_progress">Appel en cours de transfert</string>
<string name="toast_call_transfer_successful">L\'appel a été transferré</string>
<string name="toast_call_transfer_failed">Le transfert a échoué !</string>
<string name="toast_remote_provisioning_config_applied">Configuration appliquée avec succès</string>
<string name="toast_remote_provisioning_config_failed">Erreur durant la récupération ou l\'application de la configuration</string>
<!-- Assistant related string (account register / login / etc...) -->
<string name="assistant_dialog_general_terms_and_privacy_policy_title">Conditions de service &amp; politique de confidentialité</string>
@ -110,7 +112,6 @@
<string name="assistant_dialog_confirm_phone_number_message">Êtes-vous sûr de vouloir utiliser ce numéro de téléphone ?</string>
<string name="assistant_account_login">Connexion</string>
<string name="assistant_scan_qr_code">Scanner un QR code</string>
<string name="assistant_qr_code_provisioning_done">Configuration téléchargée avec succès</string>
<string name="assistant_login_third_party_sip_account">J\'ai un compte SIP tiers</string>
<string name="assistant_login_using_single_sign_on">Single sign on</string>
<string name="assistant_no_account_yet">Pas encore de compte ?</string>

View file

@ -137,6 +137,8 @@
<string name="toast_call_transfer_in_progress">Call is being transferred</string>
<string name="toast_call_transfer_successful">Call has been successfully transferred</string>
<string name="toast_call_transfer_failed">Call transfer failed!</string>
<string name="toast_remote_provisioning_config_applied">Configuration successfully applied</string>
<string name="toast_remote_provisioning_config_failed">Error while trying to download and apply remote configuration</string>
<!-- Assistant related string (account register / login / etc...) -->
<string name="assistant_dialog_general_terms_and_privacy_policy_title">General terms &amp; privacy policy</string>
@ -145,7 +147,6 @@
<string name="assistant_dialog_confirm_phone_number_message">Are you sure you want to use this phone number?</string>
<string name="assistant_account_login">Login</string>
<string name="assistant_scan_qr_code">Scan QR code</string>
<string name="assistant_qr_code_provisioning_done">Configuration successfully applied</string>+
<string name="assistant_login_third_party_sip_account">Use a third party SIP account</string>
<string name="assistant_login_using_single_sign_on">Single sign on</string>
<string name="assistant_no_account_yet">No account yet?</string>