r/o support for vcard avatars. pep avatars will be prefered
This commit is contained in:
parent
e6aa604ade
commit
5136bf9832
|
@ -15,6 +15,7 @@ import eu.siacs.conversations.utils.UIHelper;
|
|||
import eu.siacs.conversations.xml.Element;
|
||||
import eu.siacs.conversations.xmpp.jid.InvalidJidException;
|
||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||
import eu.siacs.conversations.xmpp.pep.Avatar;
|
||||
|
||||
public class Contact implements ListItem, Blockable {
|
||||
public static final String TABLENAME = "contacts";
|
||||
|
@ -40,11 +41,11 @@ public class Contact implements ListItem, Blockable {
|
|||
protected int subscription = 0;
|
||||
protected String systemAccount;
|
||||
protected String photoUri;
|
||||
protected String avatar;
|
||||
protected JSONObject keys = new JSONObject();
|
||||
protected JSONArray groups = new JSONArray();
|
||||
protected Presences presences = new Presences();
|
||||
protected Account account;
|
||||
protected Avatar avatar;
|
||||
|
||||
public Contact(final String account, final String systemName, final String serverName,
|
||||
final Jid jid, final int subscription, final String photoUri,
|
||||
|
@ -61,7 +62,11 @@ public class Contact implements ListItem, Blockable {
|
|||
} catch (JSONException e) {
|
||||
this.keys = new JSONObject();
|
||||
}
|
||||
this.avatar = avatar;
|
||||
if (avatar != null) {
|
||||
this.avatar = new Avatar();
|
||||
this.avatar.sha1sum = avatar;
|
||||
this.avatar.origin = Avatar.Origin.VCARD; //always assume worst
|
||||
}
|
||||
try {
|
||||
this.groups = (groups == null ? new JSONArray() : new JSONArray(groups));
|
||||
} catch (JSONException e) {
|
||||
|
@ -187,7 +192,7 @@ public class Contact implements ListItem, Blockable {
|
|||
values.put(SYSTEMACCOUNT, systemAccount);
|
||||
values.put(PHOTOURI, photoUri);
|
||||
values.put(KEYS, keys.toString());
|
||||
values.put(AVATAR, avatar);
|
||||
values.put(AVATAR, avatar == null ? null : avatar.getFilename());
|
||||
values.put(LAST_PRESENCE, lastseen.presence);
|
||||
values.put(LAST_TIME, lastseen.time);
|
||||
values.put(GROUPS, groups.toString());
|
||||
|
@ -411,17 +416,20 @@ public class Contact implements ListItem, Blockable {
|
|||
return getJid().toDomainJid();
|
||||
}
|
||||
|
||||
public boolean setAvatar(String filename) {
|
||||
if (this.avatar != null && this.avatar.equals(filename)) {
|
||||
public boolean setAvatar(Avatar avatar) {
|
||||
if (this.avatar != null && this.avatar.equals(avatar)) {
|
||||
return false;
|
||||
} else {
|
||||
this.avatar = filename;
|
||||
if (this.avatar != null && this.avatar.origin == Avatar.Origin.PEP && avatar.origin == Avatar.Origin.VCARD) {
|
||||
return false;
|
||||
}
|
||||
this.avatar = avatar;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public String getAvatar() {
|
||||
return this.avatar;
|
||||
return avatar == null ? null : avatar.getFilename();
|
||||
}
|
||||
|
||||
public boolean deleteOtrFingerprint(String fingerprint) {
|
||||
|
@ -478,6 +486,10 @@ public class Contact implements ListItem, Blockable {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isSelf() {
|
||||
return account.getJid().toBareJid().equals(getJid().toBareJid());
|
||||
}
|
||||
|
||||
public static class Lastseen {
|
||||
public long time;
|
||||
public String presence;
|
||||
|
|
|
@ -91,7 +91,7 @@ public class IqGenerator extends AbstractGenerator {
|
|||
return publish("urn:xmpp:avatar:metadata", item);
|
||||
}
|
||||
|
||||
public IqPacket retrieveAvatar(final Avatar avatar) {
|
||||
public IqPacket retrievePepAvatar(final Avatar avatar) {
|
||||
final Element item = new Element("item");
|
||||
item.setAttribute("id", avatar.sha1sum);
|
||||
final IqPacket packet = retrieve("urn:xmpp:avatar:data", item);
|
||||
|
@ -99,6 +99,13 @@ public class IqGenerator extends AbstractGenerator {
|
|||
return packet;
|
||||
}
|
||||
|
||||
public IqPacket retrieveVcardAvatar(final Avatar avatar) {
|
||||
final IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
|
||||
packet.setTo(avatar.owner);
|
||||
packet.addChild("vCard","vcard-temp");
|
||||
return packet;
|
||||
}
|
||||
|
||||
public IqPacket retrieveAvatarMetaData(final Jid to) {
|
||||
final IqPacket packet = retrieve("urn:xmpp:avatar:metadata", null);
|
||||
if (to != null) {
|
||||
|
|
|
@ -494,7 +494,7 @@ public class MessageParser extends AbstractParser implements
|
|||
} else {
|
||||
Contact contact = account.getRoster().getContact(
|
||||
from);
|
||||
contact.setAvatar(avatar.getFilename());
|
||||
contact.setAvatar(avatar);
|
||||
mXmppConnectionService.getAvatarService().clear(
|
||||
contact);
|
||||
mXmppConnectionService.updateConversationUi();
|
||||
|
|
|
@ -13,6 +13,7 @@ import eu.siacs.conversations.services.XmppConnectionService;
|
|||
import eu.siacs.conversations.xml.Element;
|
||||
import eu.siacs.conversations.xmpp.OnPresencePacketReceived;
|
||||
import eu.siacs.conversations.xmpp.jid.Jid;
|
||||
import eu.siacs.conversations.xmpp.pep.Avatar;
|
||||
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
|
||||
|
||||
public class PresenceParser extends AbstractParser implements
|
||||
|
@ -101,6 +102,20 @@ public class PresenceParser extends AbstractParser implements
|
|||
if (nick != null) {
|
||||
contact.setPresenceName(nick.getContent());
|
||||
}
|
||||
Element x = packet.findChild("x","vcard-temp:x:update");
|
||||
Avatar avatar = Avatar.parsePresence(x);
|
||||
if (avatar != null && !contact.isSelf()) {
|
||||
avatar.owner = from.toBareJid();
|
||||
if (mXmppConnectionService.getFileBackend().isAvatarCached(avatar)) {
|
||||
if (contact.setAvatar(avatar)) {
|
||||
mXmppConnectionService.getAvatarService().clear(contact);
|
||||
mXmppConnectionService.updateConversationUi();
|
||||
mXmppConnectionService.updateRosterUi();
|
||||
}
|
||||
} else {
|
||||
mXmppConnectionService.fetchAvatar(account,avatar);
|
||||
}
|
||||
}
|
||||
mXmppConnectionService.updateRosterUi();
|
||||
}
|
||||
|
||||
|
|
|
@ -1893,9 +1893,19 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
fetchAvatar(account, avatar, null);
|
||||
}
|
||||
|
||||
public void fetchAvatar(Account account, final Avatar avatar,
|
||||
final UiCallback<Avatar> callback) {
|
||||
IqPacket packet = this.mIqGenerator.retrieveAvatar(avatar);
|
||||
public void fetchAvatar(Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
|
||||
switch (avatar.origin) {
|
||||
case PEP:
|
||||
fetchAvatarPep(account,avatar,callback);
|
||||
break;
|
||||
case VCARD:
|
||||
fetchAvatarVcard(account, avatar, callback);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchAvatarPep(Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
|
||||
IqPacket packet = this.mIqGenerator.retrievePepAvatar(avatar);
|
||||
sendIqPacket(account, packet, new OnIqPacketReceived() {
|
||||
|
||||
@Override
|
||||
|
@ -1916,7 +1926,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
} else {
|
||||
Contact contact = account.getRoster()
|
||||
.getContact(avatar.owner);
|
||||
contact.setAvatar(avatar.getFilename());
|
||||
contact.setAvatar(avatar);
|
||||
getAvatarService().clear(contact);
|
||||
updateConversationUi();
|
||||
updateRosterUi();
|
||||
|
@ -1925,8 +1935,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
callback.success(avatar);
|
||||
}
|
||||
Log.d(Config.LOGTAG, account.getJid().toBareJid()
|
||||
+ ": succesfully fetched avatar for "
|
||||
+ avatar.owner);
|
||||
+ ": succesfuly fetched pep avatar for " + avatar.owner);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
@ -1949,8 +1958,34 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
});
|
||||
}
|
||||
|
||||
public void checkForAvatar(Account account,
|
||||
final UiCallback<Avatar> callback) {
|
||||
private void fetchAvatarVcard(final Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
|
||||
IqPacket packet = this.mIqGenerator.retrieveVcardAvatar(avatar);
|
||||
this.sendIqPacket(account,packet,new OnIqPacketReceived() {
|
||||
@Override
|
||||
public void onIqPacketReceived(Account account, IqPacket packet) {
|
||||
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
||||
Element vCard = packet.findChild("vCard","vcard-temp");
|
||||
Element photo = vCard != null ? vCard.findChild("PHOTO") : null;
|
||||
Element binval = photo != null ? photo.findChild("BINVAL") : null;
|
||||
if (binval != null) {
|
||||
avatar.image = binval.getContent();
|
||||
if (getFileBackend().save(avatar)) {
|
||||
Log.d(Config.LOGTAG, account.getJid().toBareJid()
|
||||
+ ": successfully fetched vCard avatar for " + avatar.owner);
|
||||
Contact contact = account.getRoster()
|
||||
.getContact(avatar.owner);
|
||||
contact.setAvatar(avatar);
|
||||
getAvatarService().clear(contact);
|
||||
updateConversationUi();
|
||||
updateRosterUi();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void checkForAvatar(Account account, final UiCallback<Avatar> callback) {
|
||||
IqPacket packet = this.mIqGenerator.retrieveAvatarMetaData(null);
|
||||
this.sendIqPacket(account, packet, new OnIqPacketReceived() {
|
||||
|
||||
|
@ -1972,7 +2007,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
|
|||
getAvatarService().clear(account);
|
||||
callback.success(avatar);
|
||||
} else {
|
||||
fetchAvatar(account, avatar, callback);
|
||||
fetchAvatarPep(account, avatar, callback);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@ import eu.siacs.conversations.xmpp.jid.Jid;
|
|||
import android.util.Base64;
|
||||
|
||||
public class Avatar {
|
||||
|
||||
public enum Origin { PEP, VCARD };
|
||||
|
||||
public String type;
|
||||
public String sha1sum;
|
||||
public String image;
|
||||
|
@ -13,21 +16,14 @@ public class Avatar {
|
|||
public int width;
|
||||
public long size;
|
||||
public Jid owner;
|
||||
public Origin origin = Origin.PEP; //default to maintain compat
|
||||
|
||||
public byte[] getImageAsBytes() {
|
||||
return Base64.decode(image, Base64.DEFAULT);
|
||||
}
|
||||
|
||||
public String getFilename() {
|
||||
if (type == null) {
|
||||
return sha1sum;
|
||||
} else if (type.equalsIgnoreCase("image/webp")) {
|
||||
return sha1sum + ".webp";
|
||||
} else if (type.equalsIgnoreCase("image/png")) {
|
||||
return sha1sum + ".png";
|
||||
} else {
|
||||
return sha1sum;
|
||||
}
|
||||
return sha1sum;
|
||||
}
|
||||
|
||||
public static Avatar parseMetadata(Element items) {
|
||||
|
@ -64,10 +60,44 @@ public class Avatar {
|
|||
return null;
|
||||
}
|
||||
avatar.type = child.getAttribute("type");
|
||||
avatar.sha1sum = child.getAttribute("id");
|
||||
String hash = child.getAttribute("id");
|
||||
if (!isValidSHA1(hash)) {
|
||||
return null;
|
||||
}
|
||||
avatar.sha1sum = hash;
|
||||
avatar.origin = Origin.PEP;
|
||||
return avatar;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (object != null && object instanceof Avatar) {
|
||||
Avatar other = (Avatar) object;
|
||||
return other.getFilename().equals(this.getFilename());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static Avatar parsePresence(Element x) {
|
||||
Element photo = x != null ? x.findChild("photo") : null;
|
||||
String hash = photo != null ? photo.getContent() : null;
|
||||
if (hash == null) {
|
||||
return null;
|
||||
}
|
||||
if (!isValidSHA1(hash)) {
|
||||
return null;
|
||||
}
|
||||
Avatar avatar = new Avatar();
|
||||
avatar.sha1sum = hash;
|
||||
avatar.origin = Origin.VCARD;
|
||||
return avatar;
|
||||
}
|
||||
|
||||
private static boolean isValidSHA1(String s) {
|
||||
return s != null && s.matches("[a-fA-F0-9]{40}");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue