From ba63727f50c192e63e171bedca92d7003981800c Mon Sep 17 00:00:00 2001 From: iNPUTmice Date: Tue, 5 Aug 2014 22:58:46 +0200 Subject: [PATCH] fetch missing avatars from server --- .../siacs/conversations/entities/Contact.java | 20 ++++++++- .../conversations/entities/Conversation.java | 19 +++++---- .../conversations/generator/IqGenerator.java | 17 ++++++++ .../conversations/parser/AbstractParser.java | 12 ++++++ .../siacs/conversations/parser/IqParser.java | 12 ++++++ .../conversations/parser/MessageParser.java | 19 ++++++++- .../persistance/FileBackend.java | 5 +++ .../services/XmppConnectionService.java | 16 ++++++++ .../ui/ConversationActivity.java | 3 +- .../siacs/conversations/utils/UIHelper.java | 3 +- .../siacs/conversations/xmpp/pep/Avatar.java | 41 +++++++++++++++++++ 11 files changed, 152 insertions(+), 15 deletions(-) diff --git a/src/eu/siacs/conversations/entities/Contact.java b/src/eu/siacs/conversations/entities/Contact.java index 8f8e38a58..db1202009 100644 --- a/src/eu/siacs/conversations/entities/Contact.java +++ b/src/eu/siacs/conversations/entities/Contact.java @@ -8,12 +8,14 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import eu.siacs.conversations.persistance.FileBackend; import eu.siacs.conversations.utils.UIHelper; import eu.siacs.conversations.xml.Element; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; public class Contact implements ListItem { public static final String TABLENAME = "contacts"; @@ -34,6 +36,7 @@ public class Contact implements ListItem { protected int subscription = 0; protected String systemAccount; protected String photoUri; + protected String avatar; protected JSONObject keys = new JSONObject(); protected Presences presences = new Presences(); @@ -316,7 +319,20 @@ public class Contact implements ListItem { } @Override - public Bitmap getImage(int dpSize, Context context) { - return UIHelper.getContactPicture(this, dpSize, context, false); + public Bitmap getImage(int size, Context context) { + if (this.avatar!=null) { + Bitmap bm = BitmapFactory.decodeFile(FileBackend.getAvatarPath(context, avatar)); + if (bm==null) { + return UIHelper.getContactPicture(this, size, context, false); + } else { + return bm; + } + } else { + return UIHelper.getContactPicture(this, size, context, false); + } + } + + public void setAvatar(String filename) { + this.avatar = filename; } } diff --git a/src/eu/siacs/conversations/entities/Conversation.java b/src/eu/siacs/conversations/entities/Conversation.java index 29eb22b94..be641ea4f 100644 --- a/src/eu/siacs/conversations/entities/Conversation.java +++ b/src/eu/siacs/conversations/entities/Conversation.java @@ -4,6 +4,8 @@ import java.security.interfaces.DSAPublicKey; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; +import eu.siacs.conversations.utils.UIHelper; + import net.java.otr4j.OtrException; import net.java.otr4j.crypto.OtrCryptoEngineImpl; import net.java.otr4j.crypto.OtrCryptoException; @@ -13,7 +15,7 @@ import net.java.otr4j.session.SessionStatus; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; -import android.net.Uri; +import android.graphics.Bitmap; public class Conversation extends AbstractEntity { public static final String TABLENAME = "conversations"; @@ -174,13 +176,6 @@ public class Conversation extends AbstractEntity { return this.contactJid; } - public Uri getProfilePhotoUri() { - if (this.getProfilePhotoString() != null) { - return Uri.parse(this.getProfilePhotoString()); - } - return null; - } - public int getStatus() { return this.status; } @@ -396,4 +391,12 @@ public class Conversation extends AbstractEntity { public Bookmark getBookmark() { return this.bookmark; } + + public Bitmap getImage(Context context, int size) { + if (mode==MODE_SINGLE) { + return getContact().getImage(size, context); + } else { + return UIHelper.getContactPicture(this, size, context, false); + } + } } diff --git a/src/eu/siacs/conversations/generator/IqGenerator.java b/src/eu/siacs/conversations/generator/IqGenerator.java index 1a38347b1..c4d840200 100644 --- a/src/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/eu/siacs/conversations/generator/IqGenerator.java @@ -39,6 +39,15 @@ public class IqGenerator extends AbstractGenerator { return packet; } + protected IqPacket retrieve(String node, Element item) { + IqPacket packet = new IqPacket(IqPacket.TYPE_GET); + Element pubsub = packet.addChild("pubsub", "http://jabber.org/protocol/pubsub"); + Element items = pubsub.addChild("items"); + items.setAttribute("node", node); + items.addChild(item); + return packet; + } + public IqPacket publishAvatar(Avatar avatar) { Element item = new Element("item"); item.setAttribute("id", avatar.sha1sum); @@ -59,4 +68,12 @@ public class IqGenerator extends AbstractGenerator { info.setAttribute("type", avatar.type); return publish("urn:xmpp:avatar:metadata",item); } + + public IqPacket retrieveAvatar(Avatar avatar) { + Element item = new Element("item"); + item.setAttribute("id", avatar.sha1sum); + IqPacket packet = retrieve("urn:xmpp:avatar:data", item); + packet.setTo(avatar.owner); + return packet; + } } diff --git a/src/eu/siacs/conversations/parser/AbstractParser.java b/src/eu/siacs/conversations/parser/AbstractParser.java index c4c6720aa..e06f16e92 100644 --- a/src/eu/siacs/conversations/parser/AbstractParser.java +++ b/src/eu/siacs/conversations/parser/AbstractParser.java @@ -73,4 +73,16 @@ public abstract class AbstractParser { } } } + + protected String avatarData(Element items) { + Element item = items.findChild("item"); + if (item==null) { + return null; + } + Element data = item.findChild("data","urn:xmpp:avatar:data"); + if (data==null) { + return null; + } + return data.getContent(); + } } diff --git a/src/eu/siacs/conversations/parser/IqParser.java b/src/eu/siacs/conversations/parser/IqParser.java index 023fb4df3..492684503 100644 --- a/src/eu/siacs/conversations/parser/IqParser.java +++ b/src/eu/siacs/conversations/parser/IqParser.java @@ -40,6 +40,18 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived { } mXmppConnectionService.updateRosterUi(); } + + public String avatarData(IqPacket packet) { + Element pubsub = packet.findChild("pubsub", "http://jabber.org/protocol/pubsub"); + if (pubsub==null) { + return null; + } + Element items = pubsub.findChild("items"); + if (items==null) { + return null; + } + return super.avatarData(items); + } @Override public void onIqPacketReceived(Account account, IqPacket packet) { diff --git a/src/eu/siacs/conversations/parser/MessageParser.java b/src/eu/siacs/conversations/parser/MessageParser.java index 0a812669e..b54f6b989 100644 --- a/src/eu/siacs/conversations/parser/MessageParser.java +++ b/src/eu/siacs/conversations/parser/MessageParser.java @@ -5,12 +5,14 @@ import android.util.Log; import net.java.otr4j.session.Session; import net.java.otr4j.session.SessionStatus; import eu.siacs.conversations.entities.Account; +import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.services.XmppConnectionService; import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.xml.Element; import eu.siacs.conversations.xmpp.OnMessagePacketReceived; +import eu.siacs.conversations.xmpp.pep.Avatar; import eu.siacs.conversations.xmpp.stanzas.MessagePacket; public class MessageParser extends AbstractParser implements @@ -263,7 +265,22 @@ public class MessageParser extends AbstractParser implements Element items = event.findChild("items"); String node = items.getAttribute("node"); if (node!=null) { - Log.d("xmppService",account.getJid()+": "+node+" from "+from); + if (node.equals("urn:xmpp:avatar:metadata")) { + Avatar avatar = Avatar.parseMetadata(items); + avatar.owner = from; + if (mXmppConnectionService.getFileBackend().isAvatarCached(avatar)) { + if (account.getJid().equals(from)) { + account.setAvatar(avatar.getFilename()); + } else { + Contact contact = account.getRoster().getContact(from); + contact.setAvatar(avatar.getFilename()); + } + } else { + mXmppConnectionService.fetchAvatar(account, avatar); + } + } else { + Log.d("xmppService",account.getJid()+": "+node+" from "+from); + } } else { Log.d("xmppService",event.toString()); } diff --git a/src/eu/siacs/conversations/persistance/FileBackend.java b/src/eu/siacs/conversations/persistance/FileBackend.java index 4014cf608..c371e0398 100644 --- a/src/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/eu/siacs/conversations/persistance/FileBackend.java @@ -248,6 +248,11 @@ public class FileBackend { } } + public boolean isAvatarCached(Avatar avatar) { + File file = new File(getAvatarPath(context, avatar.getFilename())); + return file.exists(); + } + public void save(Avatar avatar) { File file = new File(getAvatarPath(context, avatar.getFilename())); file.getParentFile().mkdirs(); diff --git a/src/eu/siacs/conversations/services/XmppConnectionService.java b/src/eu/siacs/conversations/services/XmppConnectionService.java index 8c964517a..71f2cfc24 100644 --- a/src/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/eu/siacs/conversations/services/XmppConnectionService.java @@ -1231,6 +1231,22 @@ public class XmppConnectionService extends Service { } } + public void fetchAvatar(Account account, final Avatar avatar) { + IqPacket packet = this.mIqGenerator.retrieveAvatar(avatar); + sendIqPacket(account, packet, new OnIqPacketReceived() { + + @Override + public void onIqPacketReceived(Account account, IqPacket result) { + avatar.image = mIqParser.avatarData(result); + if (avatar.image!=null) { + getFileBackend().save(avatar); + Contact contact = account.getRoster().getContact(avatar.owner); + contact.setAvatar(avatar.getFilename()); + } + } + }); + } + public void deleteContactOnServer(Contact contact) { contact.resetOption(Contact.Options.PREEMPTIVE_GRANT); contact.resetOption(Contact.Options.DIRTY_PUSH); diff --git a/src/eu/siacs/conversations/ui/ConversationActivity.java b/src/eu/siacs/conversations/ui/ConversationActivity.java index b04fc131f..d7708b52a 100644 --- a/src/eu/siacs/conversations/ui/ConversationActivity.java +++ b/src/eu/siacs/conversations/ui/ConversationActivity.java @@ -229,8 +229,7 @@ public class ConversationActivity extends XmppActivity { ImageView profilePicture = (ImageView) view .findViewById(R.id.conversation_image); - profilePicture.setImageBitmap(UIHelper.getContactPicture(conv, - 56, activity.getApplicationContext(), false)); + profilePicture.setImageBitmap(conv.getImage(getApplicationContext(),56)); //;UIHelper.getContactPicture(conv,56, activity.getApplicationContext(), false)); return view; } diff --git a/src/eu/siacs/conversations/utils/UIHelper.java b/src/eu/siacs/conversations/utils/UIHelper.java index d14970f5c..5d959b172 100644 --- a/src/eu/siacs/conversations/utils/UIHelper.java +++ b/src/eu/siacs/conversations/utils/UIHelper.java @@ -488,8 +488,7 @@ public class UIHelper { long id = Long.parseLong(systemAccount[0]); badge.assignContactUri(Contacts.getLookupUri(id, systemAccount[1])); } - badge.setImageBitmap(UIHelper.getContactPicture(contact, 72, context, - false)); + badge.setImageBitmap(contact.getImage(72, context)); } public static AlertDialog getVerifyFingerprintDialog( diff --git a/src/eu/siacs/conversations/xmpp/pep/Avatar.java b/src/eu/siacs/conversations/xmpp/pep/Avatar.java index b000c0557..b99a2fe36 100644 --- a/src/eu/siacs/conversations/xmpp/pep/Avatar.java +++ b/src/eu/siacs/conversations/xmpp/pep/Avatar.java @@ -1,5 +1,6 @@ package eu.siacs.conversations.xmpp.pep; +import eu.siacs.conversations.xml.Element; import android.util.Base64; public class Avatar { @@ -9,6 +10,7 @@ public class Avatar { public int height; public int width; public long size; + public String owner; public byte[] getImageAsBytes() { return Base64.decode(image, Base64.DEFAULT); } @@ -23,4 +25,43 @@ public class Avatar { return sha1sum; } } + public static Avatar parseMetadata(Element items) { + Element item = items.findChild("item"); + if (item==null) { + return null; + } + Element metadata = item.findChild("metadata"); + if (metadata==null) { + return null; + } + String primaryId = item.getAttribute("id"); + if (primaryId==null) { + return null; + } + for(Element child : metadata.getChildren()) { + if (child.getName().equals("info") && primaryId.equals(child.getAttribute("id"))) { + Avatar avatar = new Avatar(); + String height = child.getAttribute("height"); + String width = child.getAttribute("width"); + String size = child.getAttribute("bytes"); + try { + if (height!=null) { + avatar.height = Integer.parseInt(height); + } + if (width!=null) { + avatar.width = Integer.parseInt(width); + } + if (size!=null) { + avatar.size = Long.parseLong(size); + } + } catch (NumberFormatException e) { + return null; + } + avatar.type = child.getAttribute("type"); + avatar.sha1sum = child.getAttribute("id"); + return avatar; + } + } + return null; + } }