diff --git a/app/src/main/java/org/linphone/contacts/AbstractAvatarModel.kt b/app/src/main/java/org/linphone/contacts/AbstractAvatarModel.kt index 4127ce139..67b49700c 100644 --- a/app/src/main/java/org/linphone/contacts/AbstractAvatarModel.kt +++ b/app/src/main/java/org/linphone/contacts/AbstractAvatarModel.kt @@ -30,7 +30,7 @@ abstract class AbstractAvatarModel { val initials = MutableLiveData() - val images = MutableLiveData>() + val picturePath = MutableLiveData() val forceConversationIcon = MutableLiveData() diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/ConversationModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/ConversationModel.kt index fb3d4e5da..10f8b5c2b 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/model/ConversationModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/model/ConversationModel.kt @@ -35,7 +35,6 @@ import org.linphone.core.Friend import org.linphone.core.tools.Log import org.linphone.ui.main.contacts.model.ContactAvatarModel import org.linphone.utils.AppUtils -import org.linphone.utils.ImageUtils import org.linphone.utils.LinphoneUtils import org.linphone.utils.ShortcutUtils import org.linphone.utils.TimestampUtils @@ -335,7 +334,6 @@ class ConversationModel @WorkerThread constructor( if (isGroup) { val fakeFriend = coreContext.core.createFriend() fakeFriend.name = chatRoom.subject - fakeFriend.photo = ImageUtils.generateBitmapForChatRoom(chatRoom) val model = ContactAvatarModel(fakeFriend) model.defaultToConversationIcon.postValue(true) avatarModel.postValue(model) diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationInfoViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationInfoViewModel.kt index 21e72ddd0..4576749ab 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationInfoViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationInfoViewModel.kt @@ -41,7 +41,6 @@ import org.linphone.ui.main.chat.model.ParticipantModel import org.linphone.ui.main.contacts.model.ContactAvatarModel import org.linphone.utils.AppUtils import org.linphone.utils.Event -import org.linphone.utils.ImageUtils import org.linphone.utils.LinphoneUtils class ConversationInfoViewModel @UiThread constructor() : AbstractConversationViewModel() { @@ -529,7 +528,6 @@ class ConversationInfoViewModel @UiThread constructor() : AbstractConversationVi val avatar = if (groupChatRoom) { val fakeFriend = coreContext.core.createFriend() fakeFriend.name = chatRoom.subject - fakeFriend.photo = ImageUtils.generateBitmapForChatRoom(chatRoom) val model = ContactAvatarModel(fakeFriend) model.defaultToConversationIcon.postValue(true) model diff --git a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt index 1fd35981a..d1620b5df 100644 --- a/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/chat/viewmodel/ConversationViewModel.kt @@ -43,7 +43,6 @@ import org.linphone.ui.main.contacts.model.ContactAvatarModel import org.linphone.ui.main.model.isEndToEndEncryptionMandatory import org.linphone.utils.AppUtils import org.linphone.utils.Event -import org.linphone.utils.ImageUtils import org.linphone.utils.LinphoneUtils class ConversationViewModel @UiThread constructor() : AbstractConversationViewModel() { @@ -538,7 +537,6 @@ class ConversationViewModel @UiThread constructor() : AbstractConversationViewMo val avatar = if (group) { val fakeFriend = coreContext.core.createFriend() fakeFriend.name = chatRoom.subject - fakeFriend.photo = ImageUtils.generateBitmapForChatRoom(chatRoom) val model = ContactAvatarModel(fakeFriend) model } else { diff --git a/app/src/main/java/org/linphone/ui/main/contacts/model/ContactAvatarModel.kt b/app/src/main/java/org/linphone/ui/main/contacts/model/ContactAvatarModel.kt index 4680438c9..f9d2ed1a1 100644 --- a/app/src/main/java/org/linphone/ui/main/contacts/model/ContactAvatarModel.kt +++ b/app/src/main/java/org/linphone/ui/main/contacts/model/ContactAvatarModel.kt @@ -88,7 +88,7 @@ class ContactAvatarModel @WorkerThread constructor(val friend: Friend, val addre isFavourite.postValue(friend.starred) initials.postValue(AppUtils.getInitials(friend.name.orEmpty())) showTrust.postValue(coreContext.core.defaultAccount?.isEndToEndEncryptionMandatory()) - images.postValue(arrayListOf(getAvatarUri(friend).toString())) + picturePath.postValue(getAvatarUri(friend).toString()) name.postValue(friend.name) computePresence(address) diff --git a/app/src/main/java/org/linphone/ui/main/model/AccountModel.kt b/app/src/main/java/org/linphone/ui/main/model/AccountModel.kt index 9414bb3fc..264512663 100644 --- a/app/src/main/java/org/linphone/ui/main/model/AccountModel.kt +++ b/app/src/main/java/org/linphone/ui/main/model/AccountModel.kt @@ -172,8 +172,8 @@ class AccountModel @WorkerThread constructor( initials.postValue(AppUtils.getInitials(name)) val pictureUri = account.params.pictureUri.orEmpty() - if (pictureUri != images.value?.firstOrNull()) { - images.postValue(arrayListOf(pictureUri)) + if (pictureUri != picturePath.value.orEmpty()) { + picturePath.postValue(pictureUri) Log.d("$TAG Account picture URI is [$pictureUri]") } diff --git a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt index 188cb74b4..ce8f93438 100644 --- a/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt +++ b/app/src/main/java/org/linphone/ui/main/settings/viewmodel/AccountProfileViewModel.kt @@ -195,7 +195,7 @@ class AccountProfileViewModel @UiThread constructor() : ViewModel() { // Create a new model to force UI to update val newModel = AccountModel(account) - newModel.images.postValue(arrayListOf(path)) + newModel.picturePath.postValue(path) accountModel.postValue(newModel) account.params = copy diff --git a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt index 673da9069..1acba743f 100644 --- a/app/src/main/java/org/linphone/utils/DataBindingUtils.kt +++ b/app/src/main/java/org/linphone/utils/DataBindingUtils.kt @@ -393,37 +393,18 @@ private fun loadContactPictureWithCoil( return } - val images = model.images.value.orEmpty() - val count = images.size - if (count == 1) { - val image = images.firstOrNull() - if (image != null) { - imageView.load(image) { - transformations(CircleCropTransformation()) - listener( - onError = { _, _ -> - imageView.load(getErrorImageLoader(context, model, size, textSize)) - } - ) - } - } else { - imageView.load(getErrorImageLoader(context, model, size, textSize)) + val image = model.picturePath.value.orEmpty() + if (image != null) { + imageView.load(image) { + transformations(CircleCropTransformation()) + listener( + onError = { _, _ -> + imageView.load(getErrorImageLoader(context, model, size, textSize)) + } + ) } } else { - val w = if (size > 0) { - AppUtils.getDimension(size).toInt() - } else { - AppUtils.getDimension(R.dimen.avatar_list_cell_size).toInt() - } - val bitmap = ImageUtils.getBitmapFromMultipleAvatars(imageView.context, w, images) - if (bitmap != null) { - imageView.load(bitmap) { - transformations(CircleCropTransformation()) - } - } else { - val initials = model.initials.value.orEmpty() - imageView.load(ImageUtils.getGeneratedAvatar(context, size, textSize, initials)) - } + imageView.load(getErrorImageLoader(context, model, size, textSize)) } } } diff --git a/app/src/main/java/org/linphone/utils/ImageUtils.kt b/app/src/main/java/org/linphone/utils/ImageUtils.kt index b12eb34e0..1acfe0367 100644 --- a/app/src/main/java/org/linphone/utils/ImageUtils.kt +++ b/app/src/main/java/org/linphone/utils/ImageUtils.kt @@ -21,21 +21,13 @@ package org.linphone.utils import android.content.Context import android.graphics.Bitmap -import android.graphics.BitmapFactory -import android.graphics.Canvas import android.graphics.ImageDecoder -import android.graphics.Rect import android.graphics.drawable.BitmapDrawable import android.net.Uri import androidx.annotation.AnyThread import androidx.annotation.WorkerThread import java.io.FileNotFoundException -import java.io.FileOutputStream -import java.io.OutputStream -import org.linphone.LinphoneApplication.Companion.coreContext -import org.linphone.R import org.linphone.contacts.AvatarGenerator -import org.linphone.core.ChatRoom import org.linphone.core.tools.Log class ImageUtils { @@ -90,129 +82,5 @@ class ImageUtils { Log.e("$TAG Can't get bitmap from null URI") return null } - - @WorkerThread - fun generateBitmapForChatRoom(chatRoom: ChatRoom): String { - val id = LinphoneUtils.getChatRoomId(chatRoom) - val hash = id.hashCode().toString() - val file = FileUtils.getFileStorageCacheDir("$hash.jpg", overrideExisting = true) - if (file.exists()) { - Log.i("$TAG Bitmap for conversation [$id]($hash) exists, using it") - return FileUtils.getProperFilePath(file.absolutePath) - } - - val list = arrayListOf() - for (participant in chatRoom.participants) { - val contact = - coreContext.contactsManager.findContactByAddress(participant.address) - val picture = contact?.photo - if (picture != null) { - list.add(picture) - } - } - if (list.isNotEmpty() && coreContext.contactsManager.areContactsAvailable()) { - Log.i( - "$TAG Found at [${list.size}] participant(s) with a picture for conversation [$id]($hash), creating avatar" - ) - val bitmap = generateBitmapFromList(list) - if (bitmap == null) { - Log.e("$TAG Avatar couldn't be generated") - return "" - } - val outputStream: OutputStream = FileOutputStream(file) - bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) - outputStream.close() - val generatedPath = FileUtils.getProperFilePath(file.absolutePath) - Log.i("$TAG Avatar for conversation [$id]($hash) was generated at [$generatedPath]") - return generatedPath - } else { - Log.w( - "$TAG Not once picture found for conversation [$id], couldn't generate avatar" - ) - } - return "" - } - - @WorkerThread - fun generateBitmapFromList(list: ArrayList): Bitmap? { - val size = AppUtils.getDimension(R.dimen.avatar_in_call_size).toInt() - return getBitmapFromMultipleAvatars(coreContext.context, size, list) - } - - @AnyThread - fun getBitmapFromMultipleAvatars(context: Context, size: Int, images: List): Bitmap? { - val drawables = images.mapNotNull { - try { - val uri = Uri.parse(it) - val stream = context.contentResolver.openInputStream(uri) - val bm = BitmapFactory.decodeStream(stream) - if (bm != null) { - Bitmap.createScaledBitmap(bm, size, size, false) - } else { - null - } - } catch (e: Exception) { - Log.e("$TAG Failed to get scaled bitmap for URI [$it]") - null - } - } - - if (drawables.isEmpty()) { - Log.e("$TAG Drawables list is empty, can't generate bitmap without at least one") - return null - } else { - Log.i("$TAG Generating avatar using [${drawables.size}] drawables") - } - - val rectangles = if (drawables.size == 2) { - arrayListOf( - Rect(0, 0, size / 2, size), - Rect(size / 2, 0, size, size) - ) - } else if (drawables.size == 3) { - arrayListOf( - Rect(0, 0, size / 2, size / 2), - Rect(size / 2, 0, size, size / 2), - Rect(0, size / 2, size, size) - ) - } else if (drawables.size >= 4) { - arrayListOf( - Rect(0, 0, size / 2, size / 2), - Rect(size / 2, 0, size, size / 2), - Rect(0, size / 2, size / 2, size), - Rect(size / 2, size / 2, size, size) - ) - } else { - arrayListOf(Rect(0, 0, size, size)) - } - - val bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - - for (i in 0 until rectangles.size) { - val src = if (drawables.size == 3 && i == 2) { - // To prevent deformation for the bottom image when merging 3 of them - val quarter = size / 4 - Rect(0, quarter, size, 3 * quarter) - } else if (drawables.size == 2) { - // To prevent deformation when two images are next to each other - val quarter = size / 4 - Rect(quarter, 0, 3 * quarter, size) - } else { - Rect(0, 0, size, size) - } - - try { - canvas.drawBitmap( - drawables[i]/*.toBitmap(size, size, Bitmap.Config.ARGB_8888)*/, - src, - rectangles[i], - null - ) - } catch (_: Exception) {} - } - - return bitmap - } } } diff --git a/app/src/main/java/org/linphone/utils/LinphoneUtils.kt b/app/src/main/java/org/linphone/utils/LinphoneUtils.kt index ed0de1d01..f3e2b7f21 100644 --- a/app/src/main/java/org/linphone/utils/LinphoneUtils.kt +++ b/app/src/main/java/org/linphone/utils/LinphoneUtils.kt @@ -19,13 +19,10 @@ */ package org.linphone.utils -import android.graphics.Bitmap import androidx.annotation.AnyThread import androidx.annotation.DrawableRes import androidx.annotation.IntegerRes import androidx.annotation.WorkerThread -import java.io.FileOutputStream -import java.io.OutputStream import java.text.DateFormat import java.text.SimpleDateFormat import java.util.Date @@ -415,46 +412,6 @@ class LinphoneUtils { fakeFriend.address = conferenceInfo.uri fakeFriend.name = conferenceInfo.subject - var avatarFound = true - val hash = conferenceInfo.uri?.asStringUriOnly().hashCode().toString() - val file = FileUtils.getFileStorageCacheDir("$hash.jpg", overrideExisting = true) - if (!file.exists()) { - avatarFound = false - Log.w("$TAG File [${file.absolutePath}] doesn't exist yet, trying to generate it") - - val list = arrayListOf() - for (participant in conferenceInfo.participantInfos) { - val friend = coreContext.contactsManager.findContactByAddress( - participant.address - ) - if (friend != null) { - val picture = friend.photo - if (picture != null) { - list.add(picture) - } - } - } - if (list.isNotEmpty()) { - val bitmap = ImageUtils.generateBitmapFromList(list) - if (bitmap != null) { - val outputStream: OutputStream = FileOutputStream(file) - bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) - outputStream.close() - avatarFound = true - Log.i("$TAG Generated avatar and stored it in [${file.absolutePath}]") - } else { - Log.w("$TAG Can't generate avatar from that participants list") - } - } else { - Log.w( - "$TAG Can't generate avatar as no participant was found with an available picture" - ) - } - } - - if (avatarFound) { - fakeFriend.photo = FileUtils.getProperFilePath(file.absolutePath) - } val avatarModel = ContactAvatarModel(fakeFriend) avatarModel.defaultToConferenceIcon.postValue(true) avatarModel.skipInitials.postValue(true) diff --git a/app/src/main/java/org/linphone/utils/ShortcutUtils.kt b/app/src/main/java/org/linphone/utils/ShortcutUtils.kt index c0534f2f0..0726d0b07 100644 --- a/app/src/main/java/org/linphone/utils/ShortcutUtils.kt +++ b/app/src/main/java/org/linphone/utils/ShortcutUtils.kt @@ -22,7 +22,6 @@ package org.linphone.utils import android.content.Context import android.content.Intent import android.content.pm.ShortcutInfo -import android.graphics.BitmapFactory import android.os.Bundle import androidx.annotation.WorkerThread import androidx.collection.ArraySet @@ -141,18 +140,7 @@ class ShortcutUtils { ).buildIcon() } else { subject = chatRoom.subject.orEmpty() - val picture = ImageUtils.generateBitmapForChatRoom(chatRoom) - if (picture.isNotEmpty()) { - // BitmapFactory.decodeFile() doesn't handle file:/ URIs - val file = if (picture.startsWith("file:/")) { - picture.substring("file:/".length) - } else { - picture - } - IconCompat.createWithAdaptiveBitmap(BitmapFactory.decodeFile(file)) - } else { - AvatarGenerator(context).setInitials(subject).buildIcon() - } + AvatarGenerator(context).setInitials(subject).buildIcon() } val persons = arrayOfNulls(personsList.size) diff --git a/app/src/main/res/layout/account_profile_fragment.xml b/app/src/main/res/layout/account_profile_fragment.xml index c9c84f135..453cf6104 100644 --- a/app/src/main/res/layout/account_profile_fragment.xml +++ b/app/src/main/res/layout/account_profile_fragment.xml @@ -115,7 +115,7 @@ android:textSize="14sp" android:drawableStart="@drawable/camera" android:drawablePadding="3dp" - android:visibility="@{viewModel.accountModel.images.size() == 0 ? View.VISIBLE : View.GONE, default=gone}" + android:visibility="@{viewModel.accountModel.picturePath.length() == 0 ? View.VISIBLE : View.GONE, default=gone}" app:layout_constraintTop_toBottomOf="@id/avatar" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/> @@ -131,7 +131,7 @@ android:textSize="14sp" android:drawableStart="@drawable/pencil_simple" android:drawablePadding="3dp" - android:visibility="@{viewModel.accountModel.images.size() == 0 ? View.GONE : View.VISIBLE}" + android:visibility="@{viewModel.accountModel.picturePath.length() == 0 ? View.GONE : View.VISIBLE}" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintTop_toBottomOf="@id/avatar" app:layout_constraintStart_toStartOf="parent" @@ -149,7 +149,7 @@ android:textSize="14sp" android:drawableStart="@drawable/trash_simple" android:drawablePadding="3dp" - android:visibility="@{viewModel.accountModel.images.size() == 0 ? View.GONE : View.VISIBLE}" + android:visibility="@{viewModel.accountModel.picturePath.length() == 0 ? View.GONE : View.VISIBLE}" app:layout_constraintTop_toBottomOf="@id/avatar" app:layout_constraintStart_toEndOf="@id/edit_picture_label" app:layout_constraintEnd_toEndOf="parent"/>