resend presence to muc avatar update. fixes #3175

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/entities/Contact.java               |  6 
src/main/java/eu/siacs/conversations/parser/MessageParser.java           |  1 
src/main/java/eu/siacs/conversations/services/XmppConnectionService.java | 58 
src/main/java/eu/siacs/conversations/xml/Namespace.java                  |  1 
src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java            |  4 
5 files changed, 53 insertions(+), 17 deletions(-)

Detailed changes

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;

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();

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<Conversation> conversations = new CopyOnWriteArrayList<>();
     private final IqGenerator mIqGenerator = new IqGenerator(this);
-    private final List<String> mInProgressAvatarFetches = new ArrayList<>();
+    private final Set<String> mInProgressAvatarFetches = new HashSet<>();
+    private final Set<String> mOmittedPepAvatarFetches = new HashSet<>();
     private final HashSet<Jid> 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<Avatar> 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);

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";
 }

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);
         }