diff --git a/CHANGELOG.md b/CHANGELOG.md index 71ecc21dc..09583c921 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/app/src/main/java/org/linphone/notifications/NotificationsManager.kt b/app/src/main/java/org/linphone/notifications/NotificationsManager.kt index c8e8fba9f..6d9ae1ae9 100644 --- a/app/src/main/java/org/linphone/notifications/NotificationsManager.kt +++ b/app/src/main/java/org/linphone/notifications/NotificationsManager.kt @@ -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 = HashMap() private val chatNotificationsMap: HashMap = HashMap() private val previousChatNotifications: ArrayList = arrayListOf() + private val accountsErrorNotificationsMap: HashMap = HashMap() private val notificationsMap = HashMap() @@ -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() diff --git a/app/src/main/java/org/linphone/ui/main/MainActivity.kt b/app/src/main/java/org/linphone/ui/main/MainActivity.kt index 618499bdf..55eac0aa6 100644 --- a/app/src/main/java/org/linphone/ui/main/MainActivity.kt +++ b/app/src/main/java/org/linphone/ui/main/MainActivity.kt @@ -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) { diff --git a/app/src/main/java/org/linphone/ui/main/viewmodel/MainViewModel.kt b/app/src/main/java/org/linphone/ui/main/viewmodel/MainViewModel.kt index e55e056a9..547ff0ef4 100644 --- a/app/src/main/java/org/linphone/ui/main/viewmodel/MainViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/viewmodel/MainViewModel.kt @@ -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() + } + } } } diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index e447a5a49..9846e9996 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -44,12 +44,13 @@ J\'ai compris - &appName; notifications d\'appels en cours - &appName; notifications d\'appels entrants - &appName; notifications d\'appels manqués - &appName; notification de service + Notifications d\'appels en cours + Notifications d\'appels entrants + Notifications d\'appels manqués + Notification de service 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. - &appName; notifications des conversations + Notifications des conversations + Notifications d\'erreurs liées aux comptes A réagi par %1$s à : %2$s Marquer comme lu Répondre @@ -72,6 +73,8 @@ Cliquez pour ouvrir Activer haut-parleur Désactiver haut-parleur + Compte %s en erreur ! + Ouvrez &appName; pour rafraîchir la connexion Bienvenue diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6522050c4..584c6a32a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,6 +19,7 @@ linphone_6.0_notification_service_id linphone_6.0_notification_chat_id linphone_6.0.1_notification_incoming_call_id + linphone_6.1_account_error_id ❤️ 👍 @@ -84,12 +85,13 @@ Understood - &appName; active calls notifications - &appName; incoming calls notifications - &appName; missed calls notifications - &appName; service notification + Active calls notifications + Incoming calls notifications + Missed calls notifications + Service notification This service will run all the time to keep app alive and allow you to receive calls and messages without push notifications. - &appName; instant messages notifications + Instant messages notifications + Account error notifications Reacted by %1$s to: %2$s Mark as read Reply @@ -113,6 +115,8 @@ Click to open Turn on speaker Turn off speaker + Account %s registration failed! + Open &appName; to refresh the registration Welcome