diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SettingsValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SettingsValues.java index 36ab5eeeee..d3664df33c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SettingsValues.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SettingsValues.java @@ -13,6 +13,8 @@ public final class SettingsValues extends SignalStoreValues { public static final String LINK_PREVIEWS = "settings.link_previews"; public static final String KEEP_MESSAGES_DURATION = "settings.keep_messages_duration"; + public static final String PREFER_SYSTEM_CONTACT_PHOTOS = "settings.prefer.system.contact.photos"; + private static final String SIGNAL_BACKUP_DIRECTORY = "settings.signal.backup.directory"; private static final String SIGNAL_LATEST_BACKUP_DIRECTORY = "settings.signal.backup.directory,latest"; @@ -69,6 +71,14 @@ public final class SettingsValues extends SignalStoreValues { putString(SIGNAL_LATEST_BACKUP_DIRECTORY, uri.toString()); } + public void setPreferSystemContactPhotos(boolean preferSystemContactPhotos) { + putBoolean(PREFER_SYSTEM_CONTACT_PHOTOS, preferSystemContactPhotos); + } + + public boolean isPreferSystemContactPhotos() { + return getBoolean(PREFER_SYSTEM_CONTACT_PHOTOS, false); + } + public @Nullable Uri getSignalBackupDirectory() { return getUri(SIGNAL_BACKUP_DIRECTORY); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java index c03654f2fa..a51a662b9a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/ChatsPreferenceFragment.java @@ -2,29 +2,26 @@ package org.thoughtcrime.securesms.preferences; import android.content.Context; import android.os.Bundle; -import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.preference.ListPreference; -import androidx.preference.Preference; import org.greenrobot.eventbus.EventBus; -import org.signal.core.util.logging.Log; import org.thoughtcrime.securesms.ApplicationPreferencesActivity; import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.permissions.Permissions; -import org.thoughtcrime.securesms.service.WebRtcCallService; +import org.thoughtcrime.securesms.storage.StorageSyncHelper; +import org.thoughtcrime.securesms.util.ConversationUtil; import org.thoughtcrime.securesms.util.TextSecurePreferences; -import org.thoughtcrime.securesms.webrtc.CallBandwidthMode; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; +import org.thoughtcrime.securesms.util.ThrottledDebouncer; public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment { + private static final String PREFER_SYSTEM_CONTACT_PHOTOS = "pref_system_contact_photos"; + + private final ThrottledDebouncer refreshDebouncer = new ThrottledDebouncer(500); + @Override public void onCreate(Bundle paramBundle) { super.onCreate(paramBundle); @@ -37,6 +34,14 @@ public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment { return true; }); + findPreference(PREFER_SYSTEM_CONTACT_PHOTOS) + .setOnPreferenceChangeListener((preference, newValue) -> { + SignalStore.settings().setPreferSystemContactPhotos(newValue == Boolean.TRUE); + refreshDebouncer.publish(ConversationUtil::refreshRecipientShortcuts); + StorageSyncHelper.scheduleSyncForDataChange(); + return true; + }); + initializeListSummary((ListPreference) findPreference(TextSecurePreferences.MESSAGE_BODY_TEXT_SIZE_PREF)); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java index bef11d5a8e..a617bbd0e8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/Recipient.java @@ -34,12 +34,14 @@ import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessM import org.thoughtcrime.securesms.database.RecipientDatabase.VibrateState; import org.thoughtcrime.securesms.dependencies.ApplicationDependencies; import org.thoughtcrime.securesms.groups.GroupId; +import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.phonenumbers.NumberUtil; import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter; import org.thoughtcrime.securesms.profiles.ProfileName; import org.thoughtcrime.securesms.util.FeatureFlags; import org.thoughtcrime.securesms.util.StringUtil; +import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.whispersystems.libsignal.util.guava.Optional; import org.whispersystems.libsignal.util.guava.Preconditions; @@ -729,11 +731,12 @@ public class Recipient { } public @Nullable ContactPhoto getContactPhoto() { - if (isSelf) return null; - else if (isGroupInternal() && groupAvatarId.isPresent()) return new GroupRecordContactPhoto(groupId, groupAvatarId.get()); - else if (systemContactPhoto != null) return new SystemContactPhoto(id, systemContactPhoto, 0); - else if (profileAvatar != null && hasProfileImage) return new ProfileContactPhoto(this, profileAvatar); - else return null; + if (isSelf) return null; + else if (isGroupInternal() && groupAvatarId.isPresent()) return new GroupRecordContactPhoto(groupId, groupAvatarId.get()); + else if (systemContactPhoto != null && SignalStore.settings().isPreferSystemContactPhotos()) return new SystemContactPhoto(id, systemContactPhoto, 0); + else if (profileAvatar != null && hasProfileImage) return new ProfileContactPhoto(this, profileAvatar); + else if (systemContactPhoto != null) return new SystemContactPhoto(id, systemContactPhoto, 0); + else return null; } public @Nullable Uri getMessageRingtone() { diff --git a/app/src/main/java/org/thoughtcrime/securesms/storage/AccountConflictMerger.java b/app/src/main/java/org/thoughtcrime/securesms/storage/AccountConflictMerger.java index f4478a9cb1..e940796fdc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/storage/AccountConflictMerger.java +++ b/app/src/main/java/org/thoughtcrime/securesms/storage/AccountConflictMerger.java @@ -70,8 +70,9 @@ class AccountConflictMerger implements StorageSyncHelper.ConflictMerger pinnedConversations = remote.getPinnedConversations(); AccountRecord.PhoneNumberSharingMode phoneNumberSharingMode = remote.getPhoneNumberSharingMode(); - boolean matchesRemote = doParamsMatch(remote, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations); - boolean matchesLocal = doParamsMatch(local, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations); + boolean preferContactAvatars = remote.isPreferContactAvatars(); + boolean matchesRemote = doParamsMatch(remote, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars); + boolean matchesLocal = doParamsMatch(local, unknownFields, givenName, familyName, avatarUrlPath, profileKey, noteToSelfArchived, noteToSelfForcedUnread, readReceipts, typingIndicators, sealedSenderIndicators, linkPreviews, phoneNumberSharingMode, unlisted, pinnedConversations, preferContactAvatars); if (matchesRemote) { return remote; @@ -94,6 +95,7 @@ class AccountConflictMerger implements StorageSyncHelper.ConflictMerger pinnedConversations) + @NonNull List pinnedConversations, + boolean preferContactAvatars) { return Arrays.equals(contact.serializeUnknownFields(), unknownFields) && Objects.equals(contact.getGivenName().or(""), givenName) && @@ -127,6 +130,7 @@ class AccountConflictMerger implements StorageSyncHelper.ConflictMergerUse Signal for all incoming multimedia messages Enter key sends Pressing the Enter key will send text messages + Use address book photos + Display contact photos from your address book if available Generate link previews Retrieve link previews directly from websites for messages you send. Choose identity diff --git a/app/src/main/res/xml/preferences_chats.xml b/app/src/main/res/xml/preferences_chats.xml index d961a82ae1..3f6d55d0a5 100644 --- a/app/src/main/res/xml/preferences_chats.xml +++ b/app/src/main/res/xml/preferences_chats.xml @@ -30,6 +30,12 @@ android:summary="@string/preferences__pressing_the_enter_key_will_send_text_messages" android:title="@string/preferences__pref_enter_sends_title"/> + + diff --git a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalAccountRecord.java b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalAccountRecord.java index decaec341d..7dfbbf9e51 100644 --- a/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalAccountRecord.java +++ b/libsignal/service/src/main/java/org/whispersystems/signalservice/api/storage/SignalAccountRecord.java @@ -24,17 +24,19 @@ public final class SignalAccountRecord implements SignalRecord { private final Optional avatarUrlPath; private final Optional profileKey; private final List pinnedConversations; + private final boolean preferContactAvatars; public SignalAccountRecord(StorageId id, AccountRecord proto) { this.id = id; this.proto = proto; this.hasUnknownFields = ProtoUtil.hasUnknownFields(proto); - this.givenName = OptionalUtil.absentIfEmpty(proto.getGivenName()); - this.familyName = OptionalUtil.absentIfEmpty(proto.getFamilyName()); - this.profileKey = OptionalUtil.absentIfEmpty(proto.getProfileKey()); - this.avatarUrlPath = OptionalUtil.absentIfEmpty(proto.getAvatarUrlPath()); - this.pinnedConversations = new ArrayList<>(proto.getPinnedConversationsCount()); + this.givenName = OptionalUtil.absentIfEmpty(proto.getGivenName()); + this.familyName = OptionalUtil.absentIfEmpty(proto.getFamilyName()); + this.profileKey = OptionalUtil.absentIfEmpty(proto.getProfileKey()); + this.avatarUrlPath = OptionalUtil.absentIfEmpty(proto.getAvatarUrlPath()); + this.pinnedConversations = new ArrayList<>(proto.getPinnedConversationsCount()); + this.preferContactAvatars = proto.getPreferContactAvatars(); for (AccountRecord.PinnedConversation conversation : proto.getPinnedConversationsList()) { pinnedConversations.add(PinnedConversation.fromRemote(conversation)); @@ -106,6 +108,10 @@ public final class SignalAccountRecord implements SignalRecord { return pinnedConversations; } + public boolean isPreferContactAvatars() { + return preferContactAvatars; + } + AccountRecord toProto() { return proto; } @@ -300,6 +306,12 @@ public final class SignalAccountRecord implements SignalRecord { return this; } + public Builder setPreferContactAvatars(boolean preferContactAvatars) { + builder.setPreferContactAvatars(preferContactAvatars); + + return this; + } + public SignalAccountRecord build() { AccountRecord proto = builder.build(); diff --git a/libsignal/service/src/main/proto/SignalStorage.proto b/libsignal/service/src/main/proto/SignalStorage.proto index a614316d7e..d18b8c40b2 100644 --- a/libsignal/service/src/main/proto/SignalStorage.proto +++ b/libsignal/service/src/main/proto/SignalStorage.proto @@ -134,4 +134,5 @@ message AccountRecord { PhoneNumberSharingMode phoneNumberSharingMode = 12; bool unlistedPhoneNumber = 13; repeated PinnedConversation pinnedConversations = 14; + bool preferContactAvatars = 15; }