Prevent crash for call notification due to empty person name, using all identification fields from vCard (first & last names, organization, job title)

This commit is contained in:
Sylvain Berfini 2025-06-02 14:03:57 +02:00
parent 9e1d358f4e
commit dfdc26a575
2 changed files with 27 additions and 11 deletions

View file

@ -683,7 +683,7 @@ fun Friend.getAvatarBitmap(round: Boolean = false): Bitmap? {
photo ?: getNativeContactPictureUri()?.toString(), photo ?: getNativeContactPictureUri()?.toString(),
round round
) )
} catch (numberFormatException: NumberFormatException) { } catch (_: NumberFormatException) {
// Expected for contacts created by Linphone // Expected for contacts created by Linphone
} }
return null return null
@ -720,7 +720,7 @@ fun Friend.getNativeContactPictureUri(): Uri? {
lookupUri, lookupUri,
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY ContactsContract.Contacts.Photo.CONTENT_DIRECTORY
) )
} catch (numberFormatException: NumberFormatException) { } catch (_: NumberFormatException) {
// Expected for contacts created by Linphone // Expected for contacts created by Linphone
} }
} }
@ -729,7 +729,25 @@ fun Friend.getNativeContactPictureUri(): Uri? {
@WorkerThread @WorkerThread
fun Friend.getPerson(): Person { fun Friend.getPerson(): Person {
val personBuilder = Person.Builder().setName(name) val personBuilder = Person.Builder()
val personName = if (name.orEmpty().isNotEmpty()) {
name
} else {
if (!lastName.isNullOrEmpty() || !firstName.isNullOrEmpty()) {
Log.w("[Friend] Name is null or empty, using first and last name")
"$firstName $lastName".trim()
} else if (!organization.isNullOrEmpty()) {
Log.w("[Friend] Name, first name & last name are null or empty, using organization instead")
organization
} else if (!jobTitle.isNullOrEmpty()) {
Log.w("[Friend] Name, first and last names & organization are null or empty, using job title instead")
jobTitle
} else {
Log.e("[Friend] No identification field filled for this friend!")
"Unknown"
}
}
personBuilder.setName(personName)
val bm: Bitmap? = getAvatarBitmap() val bm: Bitmap? = getAvatarBitmap()
personBuilder.setIcon( personBuilder.setIcon(
@ -737,7 +755,7 @@ fun Friend.getPerson(): Person {
Log.i( Log.i(
"[Friend] Can't use friend [$name] picture path, generating avatar based on initials" "[Friend] Can't use friend [$name] picture path, generating avatar based on initials"
) )
AvatarGenerator(coreContext.context).setInitials(AppUtils.getInitials(name.orEmpty())).buildIcon() AvatarGenerator(coreContext.context).setInitials(AppUtils.getInitials(personName.orEmpty())).buildIcon()
} else { } else {
IconCompat.createWithAdaptiveBitmap(bm) IconCompat.createWithAdaptiveBitmap(bm)
} }

View file

@ -1220,9 +1220,7 @@ class NotificationsManager
} else { } else {
val contact = friend val contact = friend
?: coreContext.contactsManager.findContactByAddress(remoteAddress) ?: coreContext.contactsManager.findContactByAddress(remoteAddress)
val displayName = contact?.name ?: LinphoneUtils.getDisplayName(remoteAddress) getPerson(contact, LinphoneUtils.getDisplayName(remoteAddress))
getPerson(contact, displayName)
} }
val isVideo = LinphoneUtils.isVideoEnabled(call) val isVideo = LinphoneUtils.isVideoEnabled(call)
@ -1588,14 +1586,14 @@ class NotificationsManager
} }
@WorkerThread @WorkerThread
private fun getPerson(friend: Friend?, displayName: String): Person { private fun getPerson(friend: Friend?, fallbackDisplayName: String): Person {
return friend?.getPerson() return friend?.getPerson()
?: Person.Builder() ?: Person.Builder()
.setName(displayName) .setName(if (fallbackDisplayName.isEmpty()) "Unknown" else fallbackDisplayName)
.setIcon( .setIcon(
AvatarGenerator(context).setInitials(AppUtils.getInitials(displayName)).buildIcon() AvatarGenerator(context).setInitials(AppUtils.getInitials(fallbackDisplayName)).buildIcon()
) )
.setKey(displayName) .setKey(fallbackDisplayName)
.setImportant(false) .setImportant(false)
.build() .build()
} }