diff --git a/src/main/java/eu/siacs/conversations/entities/Contact.java b/src/main/java/eu/siacs/conversations/entities/Contact.java index 5ea714cd6..d090f4579 100644 --- a/src/main/java/eu/siacs/conversations/entities/Contact.java +++ b/src/main/java/eu/siacs/conversations/entities/Contact.java @@ -415,10 +415,14 @@ public class Contact implements ListItem, Blockable { } public boolean setAvatar(Avatar avatar) { + return setAvatar(avatar, false); + } + + public boolean setAvatar(Avatar avatar, boolean previouslyOmittedPepFetch) { if (this.avatar != null && this.avatar.equals(avatar)) { return false; } else { - if (this.avatar != null && this.avatar.origin == Avatar.Origin.PEP && avatar.origin == Avatar.Origin.VCARD) { + if (!previouslyOmittedPepFetch && this.avatar != null && this.avatar.origin == Avatar.Origin.PEP && avatar.origin == Avatar.Origin.VCARD) { return false; } this.avatar = avatar; diff --git a/src/main/java/eu/siacs/conversations/parser/MessageParser.java b/src/main/java/eu/siacs/conversations/parser/MessageParser.java index cf7c45366..481609ce3 100644 --- a/src/main/java/eu/siacs/conversations/parser/MessageParser.java +++ b/src/main/java/eu/siacs/conversations/parser/MessageParser.java @@ -185,6 +185,7 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece if (account.getJid().asBareJid().equals(from)) { if (account.setAvatar(avatar.getFilename())) { mXmppConnectionService.databaseBackend.updateAccount(account); + mXmppConnectionService.notifyAccountAvatarHasChanged(account); } mXmppConnectionService.getAvatarService().clear(account); mXmppConnectionService.updateConversationUi(); diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 55abf5028..47b9ef731 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -180,7 +180,8 @@ public class XmppConnectionService extends Service { private final IBinder mBinder = new XmppConnectionBinder(); private final List conversations = new CopyOnWriteArrayList<>(); private final IqGenerator mIqGenerator = new IqGenerator(this); - private final List mInProgressAvatarFetches = new ArrayList<>(); + private final Set mInProgressAvatarFetches = new HashSet<>(); + private final Set mOmittedPepAvatarFetches = new HashSet<>(); private final HashSet mLowPingTimeoutMode = new HashSet<>(); private final OnIqPacketReceived mDefaultIqHandler = (account, packet) -> { if (packet.getType() != IqPacket.TYPE.RESULT) { @@ -3122,6 +3123,7 @@ public class XmppConnectionService extends Service { if (account.setAvatar(avatar.getFilename())) { getAvatarService().clear(account); databaseBackend.updateAccount(account); + notifyAccountAvatarHasChanged(account); } Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": published avatar " + (avatar.size / 1024) + "KiB"); if (callback != null) { @@ -3201,18 +3203,22 @@ public class XmppConnectionService extends Service { public void fetchAvatar(Account account, final Avatar avatar, final UiCallback callback) { final String KEY = generateFetchKey(account, avatar); synchronized (this.mInProgressAvatarFetches) { - if (!this.mInProgressAvatarFetches.contains(KEY)) { - switch (avatar.origin) { - case PEP: - this.mInProgressAvatarFetches.add(KEY); - fetchAvatarPep(account, avatar, callback); - break; - case VCARD: - this.mInProgressAvatarFetches.add(KEY); - fetchAvatarVcard(account, avatar, callback); - break; - } - } + if (mInProgressAvatarFetches.add(KEY)) { + switch (avatar.origin) { + case PEP: + this.mInProgressAvatarFetches.add(KEY); + fetchAvatarPep(account, avatar, callback); + break; + case VCARD: + this.mInProgressAvatarFetches.add(KEY); + fetchAvatarVcard(account, avatar, callback); + break; + } + } else if (avatar.origin == Avatar.Origin.PEP) { + mOmittedPepAvatarFetches.add(KEY); + } else { + Log.d(Config.LOGTAG,account.getJid().asBareJid()+": already fetching "+avatar.origin+" avatar for "+avatar.owner); + } } } @@ -3274,8 +3280,11 @@ public class XmppConnectionService extends Service { this.sendIqPacket(account, packet, new OnIqPacketReceived() { @Override public void onIqPacketReceived(Account account, IqPacket packet) { + final boolean previouslyOmittedPepFetch; synchronized (mInProgressAvatarFetches) { - mInProgressAvatarFetches.remove(generateFetchKey(account, avatar)); + final String KEY = generateFetchKey(account, avatar); + mInProgressAvatarFetches.remove(KEY); + previouslyOmittedPepFetch = mOmittedPepAvatarFetches.remove(KEY); } if (packet.getType() == IqPacket.TYPE.RESULT) { Element vCard = packet.findChild("vCard", "vcard-temp"); @@ -3285,7 +3294,7 @@ public class XmppConnectionService extends Service { avatar.image = image; if (getFileBackend().save(avatar)) { Log.d(Config.LOGTAG, account.getJid().asBareJid() - + ": successfully fetched vCard avatar for " + avatar.owner); + + ": successfully fetched vCard avatar for " + avatar.owner+" omittedPep="+previouslyOmittedPepFetch); if (avatar.owner.isBareJid()) { if (account.getJid().asBareJid().equals(avatar.owner) && account.getAvatar() == null) { Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": had no avatar. replacing with vcard"); @@ -3295,7 +3304,7 @@ public class XmppConnectionService extends Service { updateAccountUi(); } else { Contact contact = account.getRoster().getContact(avatar.owner); - if (contact.setAvatar(avatar)) { + if (contact.setAvatar(avatar, previouslyOmittedPepFetch)) { syncRoster(account); getAvatarService().clear(contact); updateRosterUi(); @@ -3363,6 +3372,23 @@ public class XmppConnectionService extends Service { }); } + public void notifyAccountAvatarHasChanged(final Account account) { + final XmppConnection connection = account.getXmppConnection(); + if (connection != null && connection.getFeatures().bookmarksConversion()) { + Log.d(Config.LOGTAG,account.getJid().asBareJid()+": avatar changed. resending presence to online group chats"); + for(Conversation conversation : conversations) { + if (conversation.getAccount() == account && conversation.getMode() == Conversational.MODE_MULTI) { + final MucOptions mucOptions = conversation.getMucOptions(); + if (mucOptions.online()) { + PresencePacket packet = mPresenceGenerator.selfPresence(account, Presence.Status.ONLINE, mucOptions.nonanonymous()); + packet.setTo(mucOptions.getSelf().getFullJid()); + connection.sendPresencePacket(packet); + } + } + } + } + } + public void deleteContactOnServer(Contact contact) { contact.resetOption(Contact.Options.PREEMPTIVE_GRANT); contact.resetOption(Contact.Options.DIRTY_PUSH); diff --git a/src/main/java/eu/siacs/conversations/xml/Namespace.java b/src/main/java/eu/siacs/conversations/xml/Namespace.java index 501acf89c..f58f06373 100644 --- a/src/main/java/eu/siacs/conversations/xml/Namespace.java +++ b/src/main/java/eu/siacs/conversations/xml/Namespace.java @@ -24,4 +24,5 @@ public final class Namespace { public static final String BOOKMARKS_CONVERSION = "urn:xmpp:bookmarks-conversion:0"; public static final String BOOKMARKS = "storage:bookmarks"; public static final String SYNCHRONIZATION = "im.quicksy.synchronization:0"; + public static final String AVATAR_CONVERSION = "urn:xmpp:pep-vcard-conversion:0"; } diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 6355f6fa6..c42738ff3 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -1755,6 +1755,10 @@ public class XmppConnection implements Runnable { return hasDiscoFeature(account.getJid().asBareJid(), Namespace.BOOKMARKS_CONVERSION) && pepPublishOptions(); } + public boolean avatarConversion() { + return hasDiscoFeature(account.getJid().asBareJid(), Namespace.AVATAR_CONVERSION) && pepPublishOptions(); + } + public boolean blocking() { return hasDiscoFeature(Jid.of(account.getServer()), Namespace.BLOCKING); }