Hide presence SIP addresses from contact details & editor views

This commit is contained in:
Sylvain Berfini 2026-01-05 11:11:26 +01:00
parent 6f09853424
commit 24d808b1a7
4 changed files with 34 additions and 18 deletions

View file

@ -37,6 +37,7 @@ Group changes to describe their impact on the project, as follows:
- No longer follow TelecomManager audio endpoint during calls, using our own routing policy
- Removing an account will also remove all related data in the local database (auth info, call logs, conversations, meetings, etc...)
- 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
- Hide SIP address associated to phone number through presence mecanism in contact details & editor views.
- Improved UI on tablets with screen sw600dp and higher, will look more like our desktop app
- Improved navigation within app when using a keyboard
- Now loading media/documents contents in conversation by chunks (instead of all of them at once)

View file

@ -817,6 +817,10 @@ fun Friend.getListOfSipAddressesAndPhoneNumbers(listener: ContactNumberOrAddress
// Will return an empty list if corePreferences.hideSipAddresses == true
for (address in getListOfSipAddresses()) {
if (LinphoneUtils.isSipAddressLinkedToPhoneNumberByPresence(this, address.asStringUriOnly())) {
continue
}
val data = ContactNumberOrAddressModel(
this,
address,
@ -832,7 +836,6 @@ fun Friend.getListOfSipAddressesAndPhoneNumbers(listener: ContactNumberOrAddress
return addressesAndNumbers
}
val indexOfLastSipAddress = addressesAndNumbers.count()
for (number in phoneNumbersWithLabel) {
val phoneNumber = number.phoneNumber
val presenceModel = getPresenceModelForUriOrTel(phoneNumber)
@ -840,25 +843,12 @@ fun Friend.getListOfSipAddressesAndPhoneNumbers(listener: ContactNumberOrAddress
var presenceAddress: Address? = null
if (presenceModel != null && hasPresenceInfo) {
// Show linked SIP address if not already stored as-is
val contact = presenceModel.contact
if (!contact.isNullOrEmpty()) {
val address = core.interpretUrl(contact, false)
if (address != null) {
address.clean() // To remove ;user=phone
presenceAddress = address
if (!corePreferences.hideSipAddresses && addressesAndNumbers.find { it.address?.weakEqual(address) == true } == null) {
val data = ContactNumberOrAddressModel(
this,
address,
address.asStringUriOnly(),
true, // SIP addresses are always enabled
listener,
true,
hasPresence = true
)
addressesAndNumbers.add(indexOfLastSipAddress, data)
}
} else {
Log.e("[Contacts Manager] Failed to parse phone number [$phoneNumber] contact address [$contact] from presence model!")
}

View file

@ -42,6 +42,7 @@ import org.linphone.ui.main.contacts.model.NewOrEditNumberOrAddressModel
import org.linphone.utils.Event
import org.linphone.utils.FileUtils
import androidx.core.net.toUri
import org.linphone.utils.LinphoneUtils
class ContactNewOrEditViewModel
@UiThread
@ -114,8 +115,13 @@ class ContactNewOrEditViewModel
}
for (address in friend.addresses) {
addSipAddress(address.asStringUriOnly())
val sipAddress = address.asStringUriOnly()
// Prevents showing presence address as editable when in fact it's not
if (!LinphoneUtils.isSipAddressLinkedToPhoneNumberByPresence(friend, sipAddress)) {
addSipAddress(sipAddress)
}
}
for (number in friend.phoneNumbersWithLabel) {
addPhoneNumber(number.phoneNumber, number.label)
}
@ -341,16 +347,20 @@ class ContactNewOrEditViewModel
if (jobTitle.value.orEmpty() != friend.jobTitle.orEmpty()) return true
for (address in friend.addresses) {
val sipAddress = address.asStringUriOnly()
if (LinphoneUtils.isSipAddressLinkedToPhoneNumberByPresence(friend, sipAddress)) continue
val found = sipAddresses.find {
it.isSip && it.value.value.orEmpty() == address.asStringUriOnly()
it.isSip && it.value.value.orEmpty() == sipAddress
}
if (found == null) return true
}
for (address in sipAddresses) {
if (address.value.value.orEmpty().isEmpty()) continue
val sipAddress = address.value.value.orEmpty()
if (sipAddress.isEmpty()) continue
val found = friend.addresses.find {
it.asStringUriOnly() == address.value.value.orEmpty()
it.asStringUriOnly() == sipAddress
}
if (found == null) return true
}

View file

@ -217,6 +217,21 @@ class LinphoneUtils {
return null
}
@WorkerThread
fun isSipAddressLinkedToPhoneNumberByPresence(friend: Friend, sipAddress: String): Boolean {
for (phoneNumber in friend.phoneNumbers) {
val presenceModel = friend.getPresenceModelForUriOrTel(phoneNumber)
if (presenceModel != null) {
val contact = presenceModel.contact
if (contact == sipAddress) {
Log.i("$TAG SIP address [$sipAddress] is presence contact address for phone number [$phoneNumber]")
return true
}
}
}
return false
}
@AnyThread
fun isCallIncoming(callState: Call.State): Boolean {
return when (callState) {