From 8615c578427ac7a06a0f2add5f9e81c31dea2a41 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Thu, 24 Oct 2024 14:46:39 +1100 Subject: [PATCH] Making sure the avatars refresh when changed by other users --- .../components/ProfilePictureView.kt | 4 ++- .../securesms/database/Storage.kt | 7 +---- .../sskenvironment/ProfileManager.kt | 11 +++----- .../libsession/database/StorageProtocol.kt | 1 - .../jobs/RetrieveProfileAvatarJob.kt | 27 ++++++++++++------- .../utilities/recipients/Recipient.java | 8 ++++-- 6 files changed, 32 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt b/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt index d390d82ec3..70834a02de 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/ProfilePictureView.kt @@ -131,8 +131,10 @@ class ProfilePictureView @JvmOverloads constructor( this.recipient = Recipient.from(context, Address.fromSerialized(publicKey), false) this.recipient!! } + if (profilePicturesCache[imageView] == recipient) return - profilePicturesCache[imageView] = recipient + // recipient is mutable so without cloning it the line above always returns true as the changes to the underlying recipient happens on both shared instances + profilePicturesCache[imageView] = recipient.clone() val signalProfilePicture = recipient.contactPhoto val avatar = (signalProfilePicture as? ProfileContactPhoto)?.avatarObject diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt index fc27d8ebd8..384be73cb3 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/Storage.kt @@ -191,11 +191,6 @@ open class Storage( return Profile(displayName, profileKey, profilePictureUrl) } - override fun setProfileAvatar(recipient: Recipient, profileAvatar: String?) { - val database = DatabaseComponent.get(context).recipientDatabase() - database.setProfileAvatar(recipient, profileAvatar) - } - override fun setProfilePicture(recipient: Recipient, newProfilePicture: String?, newProfileKey: ByteArray?) { val db = DatabaseComponent.get(context).recipientDatabase() db.setProfileAvatar(recipient, newProfilePicture) @@ -216,7 +211,7 @@ open class Storage( TextSecurePreferences.setProfilePictureURL(context, newProfilePicture) if (newProfileKey != null) { - JobQueue.shared.add(RetrieveProfileAvatarJob(newProfilePicture, ourRecipient.address)) + JobQueue.shared.add(RetrieveProfileAvatarJob(newProfilePicture, ourRecipient.address, newProfileKey)) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt b/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt index d6383ab7fc..67bcc32681 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/sskenvironment/ProfileManager.kt @@ -61,12 +61,9 @@ class ProfileManager(private val context: Context, private val configFactory: Co .getAllJobs(RetrieveProfileAvatarJob.KEY).any { (it.value as? RetrieveProfileAvatarJob)?.recipientAddress == recipient.address } - val resolved = recipient.resolve() - DatabaseComponent.get(context).storage().setProfilePicture( - recipient = resolved, - newProfileKey = profileKey, - newProfilePicture = profilePictureURL - ) + + recipient.resolve() + val accountID = recipient.address.serialize() val contactDatabase = DatabaseComponent.get(context).sessionContactDatabase() var contact = contactDatabase.getContactWithAccountID(accountID) @@ -79,7 +76,7 @@ class ProfileManager(private val context: Context, private val configFactory: Co } contactUpdatedInternal(contact) if (!hasPendingDownload) { - val job = RetrieveProfileAvatarJob(profilePictureURL, recipient.address) + val job = RetrieveProfileAvatarJob(profilePictureURL, recipient.address, profileKey) JobQueue.shared.add(job) } } diff --git a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt index 2cb9df77a6..777492601c 100644 --- a/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt +++ b/libsession/src/main/java/org/session/libsession/database/StorageProtocol.kt @@ -42,7 +42,6 @@ interface StorageProtocol { fun getUserPublicKey(): String? fun getUserX25519KeyPair(): ECKeyPair fun getUserProfile(): Profile - fun setProfileAvatar(recipient: Recipient, profileAvatar: String?) fun setProfilePicture(recipient: Recipient, newProfilePicture: String?, newProfileKey: ByteArray?) fun setBlocksCommunityMessageRequests(recipient: Recipient, blocksMessageRequests: Boolean) fun setUserProfilePicture(newProfilePicture: String?, newProfileKey: ByteArray?) diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt index 618a31b5e2..fbdd151b60 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/RetrieveProfileAvatarJob.kt @@ -19,7 +19,10 @@ import java.io.FileOutputStream import java.io.InputStream import java.util.concurrent.ConcurrentSkipListSet -class RetrieveProfileAvatarJob(private val profileAvatar: String?, val recipientAddress: Address): Job { +class RetrieveProfileAvatarJob( + private val profileAvatar: String?, val recipientAddress: Address, + private val profileKey: ByteArray? +): Job { override var delegate: JobDelegate? = null override var id: String? = null override var failureCount: Int = 0 @@ -32,6 +35,7 @@ class RetrieveProfileAvatarJob(private val profileAvatar: String?, val recipient // Keys used for database storage private const val PROFILE_AVATAR_KEY = "profileAvatar" private const val RECEIPIENT_ADDRESS_KEY = "recipient" + private const val PROFILE_KEY = "profileKey" val errorUrls = ConcurrentSkipListSet() @@ -43,7 +47,6 @@ class RetrieveProfileAvatarJob(private val profileAvatar: String?, val recipient val context = MessagingModuleConfiguration.shared.context val storage = MessagingModuleConfiguration.shared.storage val recipient = Recipient.from(context, recipientAddress, true) - val profileKey = recipient.resolve().profileKey if (profileKey == null || (profileKey.size != 32 && profileKey.size != 16)) { return delegate.handleJobFailedPermanently(this, dispatcherName, Exception("Recipient profile key is gone!")) @@ -69,7 +72,7 @@ class RetrieveProfileAvatarJob(private val profileAvatar: String?, val recipient } AvatarHelper.delete(context, recipient.address) - storage.setProfileAvatar(recipient, null) + storage.setProfilePicture(recipient, null, null) return } @@ -87,7 +90,7 @@ class RetrieveProfileAvatarJob(private val profileAvatar: String?, val recipient setProfilePictureURL(context, profileAvatar) } - storage.setProfileAvatar(recipient, profileAvatar) + storage.setProfilePicture(recipient, profileAvatar, profileKey) } catch (e: Exception) { Log.e("Loki", "Failed to download profile avatar", e) if (failureCount + 1 >= maxFailureCount) { @@ -101,10 +104,15 @@ class RetrieveProfileAvatarJob(private val profileAvatar: String?, val recipient } override fun serialize(): Data { - return Data.Builder() - .putString(PROFILE_AVATAR_KEY, profileAvatar) - .putString(RECEIPIENT_ADDRESS_KEY, recipientAddress.serialize()) - .build() + val data = Data.Builder() + .putString(PROFILE_AVATAR_KEY, profileAvatar) + .putString(RECEIPIENT_ADDRESS_KEY, recipientAddress.serialize()) + + if (profileKey != null) { + data.putByteArray(PROFILE_KEY, profileKey) + } + + return data.build() } override fun getFactoryKey(): String { @@ -115,7 +123,8 @@ class RetrieveProfileAvatarJob(private val profileAvatar: String?, val recipient override fun create(data: Data): RetrieveProfileAvatarJob { val profileAvatar = if (data.hasString(PROFILE_AVATAR_KEY)) { data.getString(PROFILE_AVATAR_KEY) } else { null } val recipientAddress = Address.fromSerialized(data.getString(RECEIPIENT_ADDRESS_KEY)) - return RetrieveProfileAvatarJob(profileAvatar, recipientAddress) + val profileKey = data.getByteArray(PROFILE_KEY) + return RetrieveProfileAvatarJob(profileAvatar, recipientAddress, profileKey) } } } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/utilities/recipients/Recipient.java b/libsession/src/main/java/org/session/libsession/utilities/recipients/Recipient.java index 8499ddf398..22a7de6f5a 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/recipients/Recipient.java +++ b/libsession/src/main/java/org/session/libsession/utilities/recipients/Recipient.java @@ -62,7 +62,7 @@ import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ExecutionException; -public class Recipient implements RecipientModifiedListener { +public class Recipient implements RecipientModifiedListener, Cloneable { private static final String TAG = Recipient.class.getSimpleName(); private static final RecipientProvider provider = new RecipientProvider(); @@ -1125,5 +1125,9 @@ public class Recipient implements RecipientModifiedListener { } - + @NonNull + @Override + public Recipient clone() throws CloneNotSupportedException { + return (Recipient) super.clone(); + } }