Show system notification when account registration is failed

This commit is contained in:
Sylvain Berfini 2025-07-12 16:48:42 +02:00
parent 98cc173d2e
commit 9d0f2cafc9
6 changed files with 128 additions and 22 deletions

View file

@ -17,16 +17,24 @@ Group changes to describe their impact on the project, as follows:
- Support right click on some items to open bottom sheet/menu
- Added toggle speaker action in active call notification
- Increased text size for chat messages that only contains emoji(s)
- Handle read-only CardDAV address books, disable edit/delete menus for contacts in read-only FriendList.
- Show information to user when filtering contacts doesn't show them all and user may have to refine it's search
- Show Android notification when an account goes to failed registration state (only when background mode is enabled)
- New settings:
- one for user to choose whether to sort contacts by first name or last name
- one to hide contacts that have neither a SIP address nor a phone number
- one to let app auto-answer call with video sending already enabled
- Added a vu meter for recording & playback volumes (disabled by default, must be enabled in CorePreferences)
- Added a vu meter for recording & playback volumes (must be enabled in developer settings)
- Added a way to go to Help & Troubleshooting pages from Assistant
- Added support for HDMI audio devices
### Changed
- Hide SIP address/phone number picker dialog if contact has exactly one SIP address matching both the app default domain & the currently selected account domain
- Improved UI on tablets with screen sw600dp and higher, will look more like our desktop app
- Simplified audio device name in settings
- Reworked some settings (moved calls related ones from advanced settings to advanced calls settings)
- Increased shared media preview size in chat
- Un-encrypted conversation warning will be more visible for accounts that support end-to-end encrypted conversations
## [6.0.11] - 2025-07-11

View file

@ -53,6 +53,7 @@ import org.linphone.contacts.AvatarGenerator
import org.linphone.contacts.ContactsManager.ContactsListener
import org.linphone.contacts.getAvatarBitmap
import org.linphone.contacts.getPerson
import org.linphone.core.Account
import org.linphone.core.Address
import org.linphone.core.AudioDevice
import org.linphone.core.Call
@ -69,6 +70,7 @@ import org.linphone.core.CoreListenerStub
import org.linphone.core.Factory
import org.linphone.core.Friend
import org.linphone.core.MediaDirection
import org.linphone.core.RegistrationState
import org.linphone.core.tools.Log
import org.linphone.ui.call.CallActivity
import org.linphone.ui.main.MainActivity
@ -102,12 +104,16 @@ class NotificationsManager
const val INTENT_REMOTE_SIP_URI = "REMOTE_ADDRESS"
const val CHAT_TAG = "Chat"
private const val ACCOUNT_ERROR_TAG = "Account Error"
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 DUMMY_NOTIF_ID = 3
private const val KEEP_ALIVE_FOR_THIRD_PARTY_ACCOUNTS_ID = 5
private const val ACCOUNT_REGISTRATION_ERROR_ID = 7
private const val MISSED_CALL_ID = 10
}
@ -129,6 +135,7 @@ class NotificationsManager
private val callNotificationsMap: HashMap<String, Notifiable> = HashMap()
private val chatNotificationsMap: HashMap<String, Notifiable> = HashMap()
private val previousChatNotifications: ArrayList<Int> = arrayListOf()
private val accountsErrorNotificationsMap: HashMap<String, Int> = HashMap()
private val notificationsMap = HashMap<Int, Notification>()
@ -451,6 +458,27 @@ class NotificationsManager
)
dismissChatNotification(chatRoom)
}
@WorkerThread
override fun onAccountRegistrationStateChanged(
core: Core,
account: Account,
state: RegistrationState?,
message: String
) {
if (state == RegistrationState.Failed) {
showAccountErrorNotification(account)
} else if (state == RegistrationState.Ok) {
// Check if a notification exists for that identity address and if yes, remove it
val identity = account.params.identityAddress?.asStringUriOnly().orEmpty()
val notificationId = accountsErrorNotificationsMap.getOrDefault(identity, -1)
if (notificationId != -1) {
accountsErrorNotificationsMap.remove(identity)
Log.i("$TAG Removing account registration error notification with ID [$notificationId] for [$identity]")
cancelNotification(notificationId, ACCOUNT_ERROR_TAG)
}
}
}
}
val chatMessageListener: ChatMessageListener = object : ChatMessageListenerStub() {
@ -599,6 +627,7 @@ class NotificationsManager
createMissedCallNotificationChannel()
createActiveCallNotificationChannel()
createMessageChannel()
createAccountErrorNotificationChannel()
}
@WorkerThread
@ -1124,6 +1153,49 @@ class NotificationsManager
notify(notifiable.notificationId, notification, CHAT_TAG)
}
@WorkerThread
private fun showAccountErrorNotification(account: Account) {
// Don't do it if background mode is not enabled, otherwise it will trigger every time
// the app is put in background and it's not relevant as long as push notifications work
if (!corePreferences.keepServiceAlive) return
if (Compatibility.isPostNotificationsPermissionGranted(context)) {
val pendingIntent = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(
Intent(context, MainActivity::class.java).apply {
action = Intent.ACTION_MAIN // Needed as well
}
)
getPendingIntent(
ACCOUNT_REGISTRATION_ERROR_ID,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)!!
}
val identity = account.params.identityAddress?.asStringUriOnly().orEmpty()
val notificationId = identity.hashCode()
val notification = NotificationCompat.Builder(
context,
context.getString(R.string.notification_channel_account_error_id)
)
.setContentTitle(context.getString(R.string.notification_account_registration_error_title, identity))
.setContentText(context.getString(R.string.notification_account_registration_error_message))
.setSmallIcon(R.drawable.linphone_notification)
.setAutoCancel(false)
.setOngoing(true)
.setCategory(NotificationCompat.CATEGORY_ERROR)
.setWhen(System.currentTimeMillis())
.setShowWhen(true)
.setContentIntent(pendingIntent)
.build()
accountsErrorNotificationsMap.put(identity, notificationId)
Log.i("$TAG Showing account registration error notification with ID [$notificationId] for [$identity]")
notify(notificationId, notification, ACCOUNT_ERROR_TAG)
}
}
@SuppressLint("MissingPermission")
@WorkerThread
private fun notify(id: Int, notification: Notification, tag: String? = null) {
@ -1807,6 +1879,21 @@ class NotificationsManager
notificationManager.createNotificationChannel(channel)
}
@MainThread
private fun createAccountErrorNotificationChannel() {
val id = context.getString(R.string.notification_channel_account_error_id)
val name = context.getString(R.string.notification_channel_account_error_name)
val channel = NotificationChannel(id, name, NotificationManager.IMPORTANCE_HIGH).apply {
description = name
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
enableLights(true)
enableVibration(true)
setShowBadge(true)
}
notificationManager.createNotificationChannel(channel)
}
@WorkerThread
private fun getChatRoomPendingIntent(chatRoom: ChatRoom, notificationId: Int): PendingIntent {
val args = Bundle()

View file

@ -428,9 +428,8 @@ class MainActivity : GenericActivity() {
super.onResume()
viewModel.enableAccountMonitoring(true)
viewModel.checkForNewAccount()
viewModel.updateNetworkReachability()
viewModel.updateMissingPermissionAlert()
viewModel.updateAccountsAndNetworkReachability()
}
override fun onNewIntent(intent: Intent) {

View file

@ -415,13 +415,6 @@ class MainViewModel
}
}
@UiThread
fun updateNetworkReachability() {
coreContext.postOnCoreThread {
checkNetworkReachability()
}
}
@UiThread
fun updateMissingPermissionAlert() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
@ -437,13 +430,25 @@ class MainViewModel
}
@UiThread
fun checkForNewAccount() {
fun updateAccountsAndNetworkReachability() {
coreContext.postOnCoreThread { core ->
val count = core.accountList.size
val accounts = core.accountList
val count = accounts.size
if (count > accountsFound) {
Log.i("$TAG Newly added account detected!")
showNewAccountToastEvent.postValue(Event(true))
}
accountsFound = count
checkNetworkReachability()
for (account in accounts) {
if (account.state == RegistrationState.Failed) {
val identity = account.params.identityAddress?.asStringUriOnly().orEmpty()
Log.i("$TAG Account [$identity] registration state is failed, refreshing REGISTER")
account.refreshRegister()
}
}
}
}

View file

@ -44,12 +44,13 @@
<string name="dialog_understood">J\'ai compris</string>
<!-- Related to Android notifications -->
<string name="notification_channel_call_name">&appName; notifications d\'appels en cours</string>
<string name="notification_channel_incoming_call_name">&appName; notifications d\'appels entrants</string>
<string name="notification_channel_missed_call_name">&appName; notifications d\'appels manqués</string>
<string name="notification_channel_service_name">&appName; notification de service</string>
<string name="notification_channel_call_name">Notifications d\'appels en cours</string>
<string name="notification_channel_incoming_call_name">Notifications d\'appels entrants</string>
<string name="notification_channel_missed_call_name">Notifications d\'appels manqués</string>
<string name="notification_channel_service_name">Notification de service</string>
<string name="notification_channel_service_desc">Ce service sera actif en permanence pour garder l\'app en vie et vous permettre de recevoir appels et messages sans recourir aux notifications push.</string>
<string name="notification_channel_chat_name">&appName; notifications des conversations</string>
<string name="notification_channel_chat_name">Notifications des conversations</string>
<string name="notification_channel_account_error_name">Notifications d\'erreurs liées aux comptes</string>
<string name="notification_chat_message_reaction_received">A réagi par %1$s à : %2$s</string>
<string name="notification_mark_message_as_read">Marquer comme lu</string>
<string name="notification_reply_to_message">Répondre</string>
@ -72,6 +73,8 @@
<string name="notification_keep_app_alive_message">Cliquez pour ouvrir</string>
<string name="notification_enable_speaker_for_call">Activer haut-parleur</string>
<string name="notification_disable_speaker_for_call">Désactiver haut-parleur</string>
<string name="notification_account_registration_error_title">Compte %s en erreur !</string>
<string name="notification_account_registration_error_message">Ouvrez &appName; pour rafraîchir la connexion</string>
<!-- First screens user see when app is installed and started -->
<string name="welcome_page_title">Bienvenue</string>

View file

@ -19,6 +19,7 @@
<string name="notification_channel_service_id" translatable="false">linphone_6.0_notification_service_id</string>
<string name="notification_channel_chat_id" translatable="false">linphone_6.0_notification_chat_id</string>
<string name="notification_channel_without_ringtone_incoming_call_id" translatable="false">linphone_6.0.1_notification_incoming_call_id</string>
<string name="notification_channel_account_error_id" translatable="false">linphone_6.1_account_error_id</string>
<string name="emoji_love" translatable="false">❤️</string>
<string name="emoji_thumbs_up" translatable="false">👍</string>
@ -84,12 +85,13 @@
<string name="dialog_understood">Understood</string>
<!-- Related to Android notifications -->
<string name="notification_channel_call_name">&appName; active calls notifications</string>
<string name="notification_channel_incoming_call_name">&appName; incoming calls notifications</string>
<string name="notification_channel_missed_call_name">&appName; missed calls notifications</string>
<string name="notification_channel_service_name">&appName; service notification</string>
<string name="notification_channel_call_name">Active calls notifications</string>
<string name="notification_channel_incoming_call_name">Incoming calls notifications</string>
<string name="notification_channel_missed_call_name">Missed calls notifications</string>
<string name="notification_channel_service_name">Service notification</string>
<string name="notification_channel_service_desc">This service will run all the time to keep app alive and allow you to receive calls and messages without push notifications.</string>
<string name="notification_channel_chat_name">&appName; instant messages notifications</string>
<string name="notification_channel_chat_name">Instant messages notifications</string>
<string name="notification_channel_account_error_name">Account error notifications</string>
<string name="notification_chat_message_reaction_received">Reacted by %1$s to: %2$s</string>
<string name="notification_mark_message_as_read">Mark as read</string>
<string name="notification_reply_to_message">Reply</string>
@ -113,6 +115,8 @@
<string name="notification_keep_app_alive_message">Click to open</string>
<string name="notification_enable_speaker_for_call">Turn on speaker</string>
<string name="notification_disable_speaker_for_call">Turn off speaker</string>
<string name="notification_account_registration_error_title">Account %s registration failed!</string>
<string name="notification_account_registration_error_message">Open &appName; to refresh the registration</string>
<!-- First screens user see when app is installed and started -->
<string name="welcome_page_title">Welcome</string>