aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsteckbrief <steckbrief@chefmail.de>2017-08-06 01:15:13 +0200
committersteckbrief <steckbrief@chefmail.de>2017-08-06 01:15:13 +0200
commit867afe4c5b888ce3f4f9a867906cc8edb86e7aba (patch)
tree82d17b5fcb4471ae884a548fa815a653cb00e000
parent6f588444a953a54543661f7603d45a9093b7196a (diff)
avatar handling refactored
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java8
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/parser/AbstractParser.java8
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/parser/IqParser.java18
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/parser/MessageParser.java12
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/parser/PresenceParser.java18
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/AvatarService.java767
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/ContactChooserTargetService.java3
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/NotificationService.java3
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java6
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarBitmapUtil.java158
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarCache.java266
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarService.java210
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AbstractAvatarIqPacketReceived.java18
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AvatarMetadataReceived.java47
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AvatarPepReceived.java75
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AvatarVcardReceived.java47
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/PublishAvatarMetadataResponseReceived.java37
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/PublishAvatarResponseReceived.java31
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/RepublishAvatarAfterMetadataReceived.java40
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/ConferenceDetailsActivity.java7
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/ContactDetailsActivity.java5
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/EditAccountActivity.java6
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/PublishProfilePictureActivity.java8
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/adapter/AccountAdapter.java5
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java2
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/adapter/ListItemAdapter.java7
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java5
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/ui/tasks/AvatarBitmapTask.java7
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketParser.java53
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarVcardPacketGenerator.java16
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarVcardParser.java29
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/pep/Avatar.java63
32 files changed, 1084 insertions, 901 deletions
diff --git a/src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java b/src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java
index 2d4c8f6a..e3e13328 100644
--- a/src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java
+++ b/src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java
@@ -25,7 +25,6 @@ import de.thedevstack.conversationsplus.utils.Xmlns;
import de.thedevstack.conversationsplus.xml.Element;
import de.thedevstack.conversationsplus.xmpp.forms.Data;
import de.thedevstack.conversationsplus.xmpp.jid.Jid;
-import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
public class IqGenerator extends AbstractGenerator {
@@ -83,13 +82,6 @@ public class IqGenerator extends AbstractGenerator {
return publish("http://jabber.org/protocol/nick", item);
}
- public static 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 retrieveDeviceIds(final Jid to) {
final IqPacket packet = retrieve(AxolotlService.PEP_DEVICE_LIST, null);
if(to != null) {
diff --git a/src/main/java/de/thedevstack/conversationsplus/parser/AbstractParser.java b/src/main/java/de/thedevstack/conversationsplus/parser/AbstractParser.java
index bebe41d0..cb5c9d83 100644
--- a/src/main/java/de/thedevstack/conversationsplus/parser/AbstractParser.java
+++ b/src/main/java/de/thedevstack/conversationsplus/parser/AbstractParser.java
@@ -85,12 +85,4 @@ public abstract class AbstractParser {
}
}
}
-
- protected String avatarData(Element items) {
- Element item = items.findChild("item");
- if (item == null) {
- return null;
- }
- return item.findChildContent("data", "urn:xmpp:avatar:data");
- }
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/parser/IqParser.java b/src/main/java/de/thedevstack/conversationsplus/parser/IqParser.java
index e13936c5..8af05df5 100644
--- a/src/main/java/de/thedevstack/conversationsplus/parser/IqParser.java
+++ b/src/main/java/de/thedevstack/conversationsplus/parser/IqParser.java
@@ -27,7 +27,8 @@ import de.thedevstack.conversationsplus.Config;
import de.thedevstack.conversationsplus.crypto.axolotl.AxolotlService;
import de.thedevstack.conversationsplus.entities.Account;
import de.thedevstack.conversationsplus.entities.Contact;
-import de.thedevstack.conversationsplus.services.AvatarService;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
import de.thedevstack.conversationsplus.services.XmppConnectionService;
import de.thedevstack.conversationsplus.utils.Xmlns;
import de.thedevstack.conversationsplus.xml.Element;
@@ -71,26 +72,13 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
contact.parseSubscriptionFromElement(item);
}
}
- AvatarService.getInstance().clear(contact);
+ AvatarCache.clear(contact);
}
}
mXmppConnectionService.updateConversationUi();
mXmppConnectionService.updateRosterUi();
}
- public String avatarData(final IqPacket packet) {
- final Element pubsub = packet.findChild("pubsub",
- "http://jabber.org/protocol/pubsub");
- if (pubsub == null) {
- return null;
- }
- final Element items = pubsub.findChild("items");
- if (items == null) {
- return null;
- }
- return super.avatarData(items);
- }
-
public Element getItem(final IqPacket packet) {
final Element pubsub = packet.findChild("pubsub",
"http://jabber.org/protocol/pubsub");
diff --git a/src/main/java/de/thedevstack/conversationsplus/parser/MessageParser.java b/src/main/java/de/thedevstack/conversationsplus/parser/MessageParser.java
index 4b6ed240..a8fa0128 100644
--- a/src/main/java/de/thedevstack/conversationsplus/parser/MessageParser.java
+++ b/src/main/java/de/thedevstack/conversationsplus/parser/MessageParser.java
@@ -5,9 +5,11 @@ import android.util.Pair;
import de.thedevstack.conversationsplus.entities.FileParams;
import de.thedevstack.conversationsplus.enums.FileStatus;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
import de.thedevstack.conversationsplus.services.filetransfer.http.download.AutomaticFileDownload;
import de.thedevstack.conversationsplus.services.filetransfer.http.download.HttpRetrieveHead;
import de.thedevstack.conversationsplus.utils.MessageUtil;
+import de.thedevstack.conversationsplus.xmpp.avatar.AvatarPacketParser;
import de.thedevstack.conversationsplus.xmpp.httpuploadim.HttpUploadHint;
import de.tzur.conversations.Settings;
@@ -31,7 +33,7 @@ import de.thedevstack.conversationsplus.entities.Contact;
import de.thedevstack.conversationsplus.entities.Conversation;
import de.thedevstack.conversationsplus.entities.Message;
import de.thedevstack.conversationsplus.entities.MucOptions;
-import de.thedevstack.conversationsplus.services.AvatarService;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
import de.thedevstack.conversationsplus.services.MessageArchiveService;
import de.thedevstack.conversationsplus.services.XmppConnectionService;
import de.thedevstack.conversationsplus.utils.CryptoHelper;
@@ -188,7 +190,7 @@ public class MessageParser extends AbstractParser implements
Element items = event.findChild("items");
String node = items == null ? null : items.getAttribute("node");
if ("urn:xmpp:avatar:metadata".equals(node)) {
- Avatar avatar = Avatar.parseMetadata(items);
+ Avatar avatar = AvatarPacketParser.parseMetadata(items);
if (avatar != null) {
avatar.owner = from.toBareJid();
if (AvatarUtil.isAvatarCached(avatar)) {
@@ -196,13 +198,13 @@ public class MessageParser extends AbstractParser implements
if (account.setAvatar(avatar.getFilename())) {
mXmppConnectionService.databaseBackend.updateAccount(account);
}
- AvatarService.getInstance().clear(account);
+ AvatarCache.clear(account);
mXmppConnectionService.updateConversationUi();
mXmppConnectionService.updateAccountUi();
} else {
Contact contact = account.getRoster().getContact(from);
contact.setAvatar(avatar);
- AvatarService.getInstance().clear(contact);
+ AvatarCache.clear(contact);
mXmppConnectionService.updateConversationUi();
mXmppConnectionService.updateRosterUi();
}
@@ -216,7 +218,7 @@ public class MessageParser extends AbstractParser implements
if (nick != null && nick.getContent() != null) {
Contact contact = account.getRoster().getContact(from);
contact.setPresenceName(nick.getContent());
- AvatarService.getInstance().clear(account);
+ AvatarCache.clear(account);
mXmppConnectionService.updateConversationUi();
mXmppConnectionService.updateAccountUi();
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/parser/PresenceParser.java b/src/main/java/de/thedevstack/conversationsplus/parser/PresenceParser.java
index 52e23bce..74e29393 100644
--- a/src/main/java/de/thedevstack/conversationsplus/parser/PresenceParser.java
+++ b/src/main/java/de/thedevstack/conversationsplus/parser/PresenceParser.java
@@ -7,6 +7,7 @@ import java.util.List;
import de.thedevstack.android.logcat.Logging;
import de.thedevstack.conversationsplus.persistance.DatabaseBackend;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
import de.thedevstack.conversationsplus.utils.AvatarUtil;
import de.thedevstack.conversationsplus.utils.UiUpdateHelper;
@@ -19,11 +20,12 @@ import de.thedevstack.conversationsplus.entities.Message;
import de.thedevstack.conversationsplus.entities.MucOptions;
import de.thedevstack.conversationsplus.entities.Presence;
import de.thedevstack.conversationsplus.generator.PresenceGenerator;
-import de.thedevstack.conversationsplus.services.AvatarService;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
import de.thedevstack.conversationsplus.services.XmppConnectionService;
import de.thedevstack.conversationsplus.utils.XmppSendUtil;
import de.thedevstack.conversationsplus.xml.Element;
import de.thedevstack.conversationsplus.xmpp.OnPresencePacketReceived;
+import de.thedevstack.conversationsplus.xmpp.avatar.AvatarVcardParser;
import de.thedevstack.conversationsplus.xmpp.jid.Jid;
import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
import de.thedevstack.conversationsplus.xmpp.stanzas.PresencePacket;
@@ -46,7 +48,7 @@ public class PresenceParser extends AbstractParser implements
final List<MucOptions.User> tileUserAfter = mucOptions.getUsers(5);
if (!tileUserAfter.equals(tileUserBefore)) {
Logging.d(Config.LOGTAG, account.getJid().toBareJid() + ": update tiles for " + conversation.getName());
- AvatarService.getInstance().clear(conversation);
+ AvatarCache.clear(conversation);
}
if (before != mucOptions.online() || (mucOptions.online() && count != mucOptions.getUserCount())) {
UiUpdateHelper.updateConversationUi();
@@ -61,7 +63,7 @@ public class PresenceParser extends AbstractParser implements
if (!from.isBareJid()) {
final String type = packet.getAttribute("type");
final Element x = packet.findChild("x", "http://jabber.org/protocol/muc#user");
- Avatar avatar = Avatar.parsePresence(packet.findChild("x", "vcard-temp:x:update"));
+ Avatar avatar = AvatarVcardParser.parseVcardPresenceInformation(packet);
final List<String> codes = getStatusCodes(x);
if (type == null) {
if (x != null) {
@@ -103,7 +105,7 @@ public class PresenceParser extends AbstractParser implements
avatar.owner = from;
if (AvatarUtil.isAvatarCached(avatar)) {
if (user.setAvatar(avatar)) {
- AvatarService.getInstance().clear(user);
+ AvatarCache.clear(user);
}
} else {
AvatarService.getInstance().fetchAvatar(mucOptions.getAccount(), avatar);
@@ -133,7 +135,7 @@ public class PresenceParser extends AbstractParser implements
} else if (!from.isBareJid()){
MucOptions.User user = mucOptions.deleteUser(from.getResourcepart());
if (user != null) {
- AvatarService.getInstance().clear(user);
+ AvatarCache.clear(user);
}
}
} else if (type.equals("error")) {
@@ -182,17 +184,17 @@ public class PresenceParser extends AbstractParser implements
if (type == null) {
final String resource = from.isBareJid() ? "" : from.getResourcepart();
contact.setPresenceName(packet.findChildContent("nick", "http://jabber.org/protocol/nick"));
- Avatar avatar = Avatar.parsePresence(packet.findChild("x", "vcard-temp:x:update"));
+ Avatar avatar = AvatarVcardParser.parseVcardPresenceInformation(packet);
if (avatar != null && (!contact.isSelf() || null == account.getAvatar())) {
avatar.owner = from.toBareJid();
if (AvatarUtil.isAvatarCached(avatar)) {
if (avatar.owner.equals(account.getJid().toBareJid())) {
account.setAvatar(avatar.getFilename());
DatabaseBackend.getInstance().updateAccount(account);
- AvatarService.getInstance().clear(account);
+ AvatarCache.clear(account);
UiUpdateHelper.updateAccountUi();
} else if (contact.setAvatar(avatar)) {
- AvatarService.getInstance().clear(contact);
+ AvatarCache.clear(contact);
UiUpdateHelper.updateRosterUi();
}
UiUpdateHelper.updateConversationUi();
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/AvatarService.java b/src/main/java/de/thedevstack/conversationsplus/services/AvatarService.java
deleted file mode 100644
index 0e10b883..00000000
--- a/src/main/java/de/thedevstack/conversationsplus/services/AvatarService.java
+++ /dev/null
@@ -1,767 +0,0 @@
-package de.thedevstack.conversationsplus.services;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.widget.ImageView;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.RejectedExecutionException;
-
-import de.thedevstack.android.logcat.Logging;
-import de.thedevstack.conversationsplus.ConversationsPlusApplication;
-import de.thedevstack.conversationsplus.dto.LoadAvatarFor;
-import de.thedevstack.conversationsplus.ui.AsyncDrawable;
-import de.thedevstack.conversationsplus.ui.adapter.ConversationAdapter;
-import de.thedevstack.conversationsplus.ui.tasks.AvatarBitmapTask;
-import de.thedevstack.conversationsplus.utils.AvatarUtil;
-import de.thedevstack.conversationsplus.utils.ImageUtil;
-import de.thedevstack.conversationsplus.utils.UiUpdateHelper;
-import de.thedevstack.conversationsplus.utils.XmppSendUtil;
-import de.thedevstack.conversationsplus.xmpp.avatar.AvatarPacketGenerator;
-import de.thedevstack.conversationsplus.xmpp.avatar.AvatarPacketParser;
-import de.thedevstack.conversationsplus.Config;
-import de.thedevstack.conversationsplus.R;
-import de.thedevstack.conversationsplus.entities.Account;
-import de.thedevstack.conversationsplus.entities.Bookmark;
-import de.thedevstack.conversationsplus.entities.Contact;
-import de.thedevstack.conversationsplus.entities.Conversation;
-import de.thedevstack.conversationsplus.entities.ListItem;
-import de.thedevstack.conversationsplus.entities.Message;
-import de.thedevstack.conversationsplus.entities.MucOptions;
-import de.thedevstack.conversationsplus.generator.IqGenerator;
-import de.thedevstack.conversationsplus.persistance.DatabaseBackend;
-import de.thedevstack.conversationsplus.persistance.FileBackend;
-import de.thedevstack.conversationsplus.ui.UiCallback;
-import de.thedevstack.conversationsplus.utils.UIHelper;
-import de.thedevstack.conversationsplus.xml.Element;
-import de.thedevstack.conversationsplus.xmpp.OnAdvancedStreamFeaturesLoaded;
-import de.thedevstack.conversationsplus.xmpp.OnIqPacketReceived;
-import de.thedevstack.conversationsplus.xmpp.XmppConnection;
-import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
-import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
-
-public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
-
- private static final int FG_COLOR = 0xFFFAFAFA;
- private static final int TRANSPARENT = 0x00000000;
- private static final int PLACEHOLDER_COLOR = 0xFF202020;
-
- private static final String PREFIX_CONTACT = "contact";
- private static final String PREFIX_CONVERSATION = "conversation";
- private static final String PREFIX_ACCOUNT = "account";
- private static final String PREFIX_GENERIC = "generic";
- private static final AvatarService INSTANCE = new AvatarService();
-
- final private ArrayList<Integer> sizes = new ArrayList<>();
- private final List<String> mInProgressAvatarFetches = new ArrayList<>();
-
- public static AvatarService getInstance() {
- return INSTANCE;
- }
-
- private Bitmap get(final Contact contact, final int size, boolean cachedOnly) {
- final String KEY = key(contact, size);
- Bitmap avatar = ImageUtil.getBitmapFromCache(KEY);
- if (avatar != null || cachedOnly) {
- return avatar;
- }
- if (contact.getProfilePhoto() != null) {
- avatar = ImageUtil.cropCenterSquare(Uri.parse(contact.getProfilePhoto()), size);
- }
- if (avatar == null && contact.getAvatar() != null) {
- avatar = AvatarUtil.getAvatar(contact.getAvatar(), size);
- }
- if (avatar == null) {
- avatar = get(contact.getDisplayName(), size, cachedOnly);
- }
- ImageUtil.addBitmapToCache(KEY, avatar);
- return avatar;
- }
-
- public Bitmap get(final MucOptions.User user, final int size, boolean cachedOnly) {
- Contact c = user.getContact();
- if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null)) {
- return get(c, size, cachedOnly);
- } else {
- return getImpl(user, size, cachedOnly);
- }
- }
-
- private Bitmap getImpl(final MucOptions.User user, final int size, boolean cachedOnly) {
- final String KEY = key(user, size);
- Bitmap avatar = ImageUtil.getBitmapFromCache(KEY);
- if (avatar != null || cachedOnly) {
- return avatar;
- }
- if (user.getAvatar() != null) {
- avatar = AvatarUtil.getAvatar(user.getAvatar(), size);
- }
- if (avatar == null) {
- Contact contact = user.getContact();
- if (contact != null) {
- avatar = get(contact, size, cachedOnly);
- } else {
- avatar = get(user.getName(), size, cachedOnly);
- }
- }
- ImageUtil.addBitmapToCache(KEY, avatar);
- return avatar;
- }
-
- public void clear(Contact contact) {
- synchronized (this.sizes) {
- for (Integer size : sizes) {
- ImageUtil.removeBitmapFromCache(key(contact, size));
- }
- }
- }
-
- private String key(Contact contact, int size) {
- synchronized (this.sizes) {
- if (!this.sizes.contains(size)) {
- this.sizes.add(size);
- }
- }
- return PREFIX_CONTACT + "_" + contact.getAccount().getJid().toBareJid() + "_"
- + contact.getJid() + "_" + String.valueOf(size);
- }
-
- private String key(MucOptions.User user, int size) {
- synchronized (this.sizes) {
- if (!this.sizes.contains(size)) {
- this.sizes.add(size);
- }
- }
- return PREFIX_CONTACT + "_" + user.getAccount().getJid().toBareJid() + "_"
- + user.getFullJid() + "_" + String.valueOf(size);
- }
-
- public Bitmap get(ListItem item, int size) {
- return get(item,size,false);
- }
-
- public Bitmap get(ListItem item, int size, boolean cachedOnly) {
- if (item instanceof Contact) {
- return get((Contact) item, size,cachedOnly);
- } else if (item instanceof Bookmark) {
- Bookmark bookmark = (Bookmark) item;
- if (bookmark.getConversation() != null) {
- return get(bookmark.getConversation(), size, cachedOnly);
- } else {
- return get(bookmark.getDisplayName(), size, cachedOnly);
- }
- } else {
- return get(item.getDisplayName(), size, cachedOnly);
- }
- }
-
- public Bitmap get(Conversation conversation, int size) {
- return get(conversation,size,false);
- }
-
- public Bitmap get(Conversation conversation, int size, boolean cachedOnly) {
- if (conversation.getMode() == Conversation.MODE_SINGLE) {
- return get(conversation.getContact(), size, cachedOnly);
- } else {
- return get(conversation.getMucOptions(), size, cachedOnly);
- }
- }
-
- public void clear(Conversation conversation) {
- if (conversation.getMode() == Conversation.MODE_SINGLE) {
- clear(conversation.getContact());
- } else {
- clear(conversation.getMucOptions());
- }
- }
-
- public void loadAvatar(LoadAvatarFor loadAvatarFor, ImageView imageView) {
- if (cancelPotentialWork(imageView)) {
- Resources resources = ConversationsPlusApplication.getAppContext().getResources();
- int avatarSize = resources.getDimensionPixelSize(R.dimen.avatar_size);
- final Bitmap bm;
- if (loadAvatarFor instanceof Conversation) {
- bm = AvatarService.getInstance().get((Conversation) loadAvatarFor, avatarSize, true);
- } else if (loadAvatarFor instanceof Message) {
- bm = AvatarService.getInstance().get((Message) loadAvatarFor, avatarSize, true);
- } else {
- bm = null;
- }
- if (bm != null) {
- imageView.setImageBitmap(bm);
- imageView.setBackgroundColor(0x00000000);
- } else {
- int color = 0x00000000;
- if (loadAvatarFor instanceof Conversation) {
- color = UIHelper.getColorForName(((Conversation) loadAvatarFor).getName());
- } else if (loadAvatarFor instanceof Message) {
- color = UIHelper.getColorForName(UIHelper.getMessageDisplayName((Message) loadAvatarFor));
- }
- imageView.setBackgroundColor(color);
- imageView.setImageDrawable(null);
- final AvatarBitmapTask<LoadAvatarFor> task = new AvatarBitmapTask<>(imageView, avatarSize);
- final AsyncDrawable asyncDrawable = new AsyncDrawable(resources, null, task);
- imageView.setImageDrawable(asyncDrawable);
- try {
- task.execute(loadAvatarFor);
- } catch (final RejectedExecutionException ignored) {
- }
- }
- }
- }
-
- public static boolean cancelPotentialWork(ImageView imageView) {
- return null == getBitmapWorkerTask(imageView);
- }
-
- private static AvatarBitmapTask<LoadAvatarFor> getBitmapWorkerTask(ImageView imageView) {
- if (imageView != null) {
- final Drawable drawable = imageView.getDrawable();
- if (drawable instanceof AsyncDrawable) {
- final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
- return asyncDrawable.getBitmapWorkerTask();
- }
- }
- return null;
- }
-
- private Bitmap get(MucOptions mucOptions, int size, boolean cachedOnly) {
- final String KEY = key(mucOptions, size);
- Bitmap bitmap = ImageUtil.getBitmapFromCache(KEY);
- if (bitmap != null || cachedOnly) {
- return bitmap;
- }
- final List<MucOptions.User> users = mucOptions.getUsers();
- int count = users.size();
- bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- bitmap.eraseColor(TRANSPARENT);
-
- if (count == 0) {
- String name = mucOptions.getConversation().getName();
- drawTile(canvas, name, 0, 0, size, size);
- } else if (count == 1) {
- drawTile(canvas, users.get(0), 0, 0, size / 2 - 1, size);
- drawTile(canvas, mucOptions.getConversation().getAccount(), size / 2 + 1, 0, size, size);
- } else if (count == 2) {
- drawTile(canvas, users.get(0), 0, 0, size / 2 - 1, size);
- drawTile(canvas, users.get(1), size / 2 + 1, 0, size, size);
- } else if (count == 3) {
- drawTile(canvas, users.get(0), 0, 0, size / 2 - 1, size);
- drawTile(canvas, users.get(1), size / 2 + 1, 0, size, size / 2 - 1);
- drawTile(canvas, users.get(2), size / 2 + 1, size / 2 + 1, size,
- size);
- } else if (count == 4) {
- drawTile(canvas, users.get(0), 0, 0, size / 2 - 1, size / 2 - 1);
- drawTile(canvas, users.get(1), 0, size / 2 + 1, size / 2 - 1, size);
- drawTile(canvas, users.get(2), size / 2 + 1, 0, size, size / 2 - 1);
- drawTile(canvas, users.get(3), size / 2 + 1, size / 2 + 1, size,
- size);
- } else {
- drawTile(canvas, users.get(0), 0, 0, size / 2 - 1, size / 2 - 1);
- drawTile(canvas, users.get(1), 0, size / 2 + 1, size / 2 - 1, size);
- drawTile(canvas, users.get(2), size / 2 + 1, 0, size, size / 2 - 1);
- drawTile(canvas, "\u2026", PLACEHOLDER_COLOR, size / 2 + 1, size / 2 + 1,
- size, size);
- }
- ImageUtil.addBitmapToCache(KEY, bitmap);
- return bitmap;
- }
-
- public void clear(MucOptions options) {
- synchronized (this.sizes) {
- for (Integer size : sizes) {
- ImageUtil.removeBitmapFromCache(key(options, size));
- }
- }
- }
-
- private String key(MucOptions options, int size) {
- synchronized (this.sizes) {
- if (!this.sizes.contains(size)) {
- this.sizes.add(size);
- }
- }
- return PREFIX_CONVERSATION + "_" + options.getConversation().getUuid()
- + "_" + String.valueOf(size);
- }
-
- public Bitmap get(Account account, int size) {
- return get(account, size, false);
- }
-
- public Bitmap get(Account account, int size, boolean cachedOnly) {
- final String KEY = key(account, size);
- Bitmap avatar = ImageUtil.getBitmapFromCache(KEY);
- if (avatar != null || cachedOnly) {
- return avatar;
- }
- avatar = AvatarUtil.getAvatar(account.getAvatar(), size);
- if (avatar == null) {
- avatar = get(account.getJid().toBareJid().toString(), size,false);
- }
- ImageUtil.addBitmapToCache(KEY, avatar);
- return avatar;
- }
-
- public Bitmap get(Message message, int size, boolean cachedOnly) {
- final Conversation conversation = message.getConversation();
- if (message.getStatus() == Message.STATUS_RECEIVED) {
- Contact c = message.getContact();
- if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null)) {
- return get(c, size, cachedOnly);
- } else if (message.getConversation().getMode() == Conversation.MODE_MULTI){
- MucOptions.User user = conversation.getMucOptions().findUser(message.getCounterpart().getResourcepart());
- if (user != null) {
- return getImpl(user,size,cachedOnly);
- }
- }
- return get(UIHelper.getMessageDisplayName(message), size, cachedOnly);
- } else {
- return get(conversation.getAccount(), size, cachedOnly);
- }
- }
-
- public void clear(Account account) {
- synchronized (this.sizes) {
- for (Integer size : sizes) {
- ImageUtil.removeBitmapFromCache(key(account, size));
- }
- }
- }
-
- public void clear(MucOptions.User user) {
- synchronized (this.sizes) {
- for (Integer size : sizes) {
- ImageUtil.removeBitmapFromCache(key(user, size));
- }
- }
- }
-
- private String key(Account account, int size) {
- synchronized (this.sizes) {
- if (!this.sizes.contains(size)) {
- this.sizes.add(size);
- }
- }
- return PREFIX_ACCOUNT + "_" + account.getUuid() + "_"
- + String.valueOf(size);
- }
-
- public Bitmap get(String name, int size) {
- return get(name,size,false);
- }
-
- public Bitmap get(final String name, final int size, boolean cachedOnly) {
- final String KEY = key(name, size);
- Bitmap bitmap = ImageUtil.getBitmapFromCache(KEY);
- if (bitmap != null || cachedOnly) {
- return bitmap;
- }
- bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- drawTile(canvas, name, 0, 0, size, size);
- ImageUtil.addBitmapToCache(KEY, bitmap);
- return bitmap;
- }
-
- private String key(String name, int size) {
- synchronized (this.sizes) {
- if (!this.sizes.contains(size)) {
- this.sizes.add(size);
- }
- }
- return PREFIX_GENERIC + "_" + name + "_" + String.valueOf(size);
- }
-
- private boolean drawTile(Canvas canvas, String letter, int tileColor,
- int left, int top, int right, int bottom) {
- letter = letter.toUpperCase(Locale.getDefault());
- Paint tilePaint = new Paint(), textPaint = new Paint();
- tilePaint.setColor(tileColor);
- textPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
- textPaint.setColor(FG_COLOR);
- textPaint.setTypeface(Typeface.create("sans-serif-light",
- Typeface.NORMAL));
- textPaint.setTextSize((float) ((right - left) * 0.8));
- Rect rect = new Rect();
-
- canvas.drawRect(new Rect(left, top, right, bottom), tilePaint);
- textPaint.getTextBounds(letter, 0, 1, rect);
- float width = textPaint.measureText(letter);
- canvas.drawText(letter, (right + left) / 2 - width / 2, (top + bottom)
- / 2 + rect.height() / 2, textPaint);
- return true;
- }
-
- private boolean drawTile(Canvas canvas, MucOptions.User user, int left,
- int top, int right, int bottom) {
- Contact contact = user.getContact();
- if (contact != null) {
- Uri uri = null;
- if (contact.getProfilePhoto() != null) {
- uri = Uri.parse(contact.getProfilePhoto());
- } else if (contact.getAvatar() != null) {
- uri = AvatarUtil.getAvatarUri(contact.getAvatar());
- }
- if (drawTile(canvas, uri, left, top, right, bottom)) {
- return true;
- }
- } else if (user.getAvatar() != null) {
- Uri uri = AvatarUtil.getAvatarUri(user.getAvatar());
- if (drawTile(canvas, uri, left, top, right, bottom)) {
- return true;
- }
- }
- String name = contact != null ? contact.getDisplayName() : user.getName();
- drawTile(canvas, name, left, top, right, bottom);
- return true;
- }
-
- private boolean drawTile(Canvas canvas, Account account, int left, int top, int right, int bottom) {
- String avatar = account.getAvatar();
- if (avatar != null) {
- Uri uri = AvatarUtil.getAvatarUri(avatar);
- if (uri != null) {
- if (drawTile(canvas, uri, left, top, right, bottom)) {
- return true;
- }
- }
- }
- return drawTile(canvas, account.getJid().toBareJid().toString(), left, top, right, bottom);
- }
-
- private boolean drawTile(Canvas canvas, String name, int left, int top, int right, int bottom) {
- if (name != null) {
- String trimmedName = name.trim();
- final String letter = trimmedName.isEmpty() ? "X" : trimmedName.substring(0, 1);
- final int color = UIHelper.getColorForName(name);
- drawTile(canvas, letter, color, left, top, right, bottom);
- return true;
- }
- return false;
- }
-
- private boolean drawTile(Canvas canvas, Uri uri, int left, int top, int right, int bottom) {
- if (uri != null) {
- Bitmap bitmap = ImageUtil.cropCenter(uri, bottom - top, right - left);
- if (bitmap != null) {
- drawTile(canvas, bitmap, left, top, right, bottom);
- return true;
- }
- }
- return false;
- }
-
- private boolean drawTile(Canvas canvas, Bitmap bm, int dstleft, int dsttop,
- int dstright, int dstbottom) {
- Rect dst = new Rect(dstleft, dsttop, dstright, dstbottom);
- canvas.drawBitmap(bm, null, dst, null);
- return true;
- }
-
- @Override
- public void onAdvancedStreamFeaturesAvailable(Account account) {
- XmppConnection.Features features = account.getXmppConnection().getFeatures();
- if (features.pep() && !features.pepPersistent()) {
- Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": has pep but is not persistent");
- if (account.getAvatar() != null) {
- republishAvatarIfNeeded(account);
- }
- }
- }
-
- public void publishAvatar(final Account account,
- final Uri image,
- final UiCallback<Avatar> callback) {
- final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
- final int size = Config.AVATAR_SIZE;
- final Avatar avatar = AvatarUtil.getPepAvatar(image, size, format);
- if (avatar != null) {
- avatar.height = size;
- avatar.width = size;
- if (format.equals(Bitmap.CompressFormat.WEBP)) {
- avatar.type = "image/webp";
- } else if (format.equals(Bitmap.CompressFormat.JPEG)) {
- avatar.type = "image/jpeg";
- } else if (format.equals(Bitmap.CompressFormat.PNG)) {
- avatar.type = "image/png";
- }
- if (!AvatarUtil.save(avatar)) {
- callback.error(R.string.error_saving_avatar, avatar);
- return;
- }
- sendAndReceiveIqPackages(avatar, account, callback);
- } else {
- callback.error(R.string.error_publish_avatar_converting, null);
- }
- }
-
- public void publishAvatar(Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
- final IqPacket packet = AvatarPacketGenerator.generatePublishAvatarPacket(avatar);
- XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
-
- @Override
- public void onIqPacketReceived(Account account, IqPacket result) {
- if (result.getType() == IqPacket.TYPE.RESULT) {
- sendAndReceiveIqPackages(avatar, account, callback);
- } else {
- if (callback != null) {
- callback.error(
- R.string.error_publish_avatar_server_reject,
- avatar);
- }
- }
- }
- });
- }
-
- private static String generateFetchKey(Account account, final Avatar avatar) {
- return account.getJid().toBareJid()+"_"+avatar.owner+"_"+avatar.sha1sum;
- }
-
- public void republishAvatarIfNeeded(Account account) {
- if (account.getAxolotlService().isPepBroken()) {
- Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": skipping republication of avatar because pep is broken");
- return;
- }
- IqPacket packet = AvatarPacketGenerator.generateRetrieveAvatarMetadataPacket(null);
- XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
-
- private Avatar parseAvatar(IqPacket packet) {
- Element pubsub = packet.findChild("pubsub", "http://jabber.org/protocol/pubsub");
- if (pubsub != null) {
- Element items = pubsub.findChild("items");
- if (items != null) {
- return Avatar.parseMetadata(items);
- }
- }
- return null;
- }
-
- private boolean errorIsItemNotFound(IqPacket packet) {
- Element error = packet.findChild("error");
- return packet.getType() == IqPacket.TYPE.ERROR
- && error != null
- && error.hasChild("item-not-found");
- }
-
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- if (packet.getType() == IqPacket.TYPE.RESULT || errorIsItemNotFound(packet)) {
- Avatar serverAvatar = parseAvatar(packet);
- if (serverAvatar == null && account.getAvatar() != null) {
- Avatar avatar = AvatarUtil.getStoredPepAvatar(account.getAvatar());
- if (avatar != null) {
- Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": avatar on server was null. republishing");
- publishAvatar(account, AvatarUtil.getStoredPepAvatar(account.getAvatar()), null);
- } else {
- Logging.e(Config.LOGTAG, account.getJid().toBareJid()+": error rereading avatar");
- }
- }
- }
- }
- });
- }
-
- 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)) {
- return;
- } else {
- 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;
- }
- }
- }
- }
-
- private void fetchAvatarPep(final Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
- IqPacket packet = AvatarPacketGenerator.generateRetrieveAvatarPacket(avatar);
- XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
-
- @Override
- public void onIqPacketReceived(Account account, IqPacket result) {
- synchronized (mInProgressAvatarFetches) {
- mInProgressAvatarFetches.remove(generateFetchKey(account, avatar));
- }
- final String ERROR = account.getJid().toBareJid()
- + ": fetching avatar for " + avatar.owner + " failed ";
- if (result.getType() == IqPacket.TYPE.RESULT) {
- avatar.image = AvatarPacketParser.parseAvatarData(result);
- if (avatar.image != null) {
- if (AvatarUtil.save(avatar)) {
- if (account.getJid().toBareJid().equals(avatar.owner)) {
- if (account.setAvatar(avatar.getFilename())) {
- DatabaseBackend.getInstance(ConversationsPlusApplication.getAppContext()).updateAccount(account);
- }
- AvatarService.this.clear(account);
- UiUpdateHelper.updateConversationUi();
- UiUpdateHelper.updateAccountUi();
- } else {
- Contact contact = account.getRoster()
- .getContact(avatar.owner);
- contact.setAvatar(avatar);
- AvatarService.this.clear(contact);
- UiUpdateHelper.updateConversationUi();
- UiUpdateHelper.updateRosterUi();
- }
- if (callback != null) {
- callback.success(avatar);
- }
- Logging.d(Config.LOGTAG, account.getJid().toBareJid()
- + ": succesfuly fetched pep avatar for " + avatar.owner);
- return;
- }
- } else {
-
- Logging.d(Config.LOGTAG, ERROR + "(parsing error)");
- }
- } else {
- Element error = result.findChild("error");
- if (error == null) {
- Logging.d(Config.LOGTAG, ERROR + "(server error)");
- } else {
- Logging.d(Config.LOGTAG, ERROR + error.toString());
- }
- }
- if (callback != null) {
- callback.error(0, null);
- }
-
- }
- });
- }
-
- private void fetchAvatarVcard(final Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
- IqPacket packet = IqGenerator.retrieveVcardAvatar(avatar);
- XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- synchronized (mInProgressAvatarFetches) {
- mInProgressAvatarFetches.remove(generateFetchKey(account, avatar));
- }
- if (packet.getType() == IqPacket.TYPE.RESULT) {
- Element vCard = packet.findChild("vCard", "vcard-temp");
- Element photo = vCard != null ? vCard.findChild("PHOTO") : null;
- String image = photo != null ? photo.findChildContent("BINVAL") : null;
- if (image != null) {
- avatar.image = image;
- if (AvatarUtil.save(avatar)) {
- Logging.d(Config.LOGTAG, account.getJid().toBareJid()
- + ": successfully fetched vCard avatar for " + avatar.owner);
- Contact contact = account.getRoster()
- .getContact(avatar.owner);
- contact.setAvatar(avatar);
- AvatarService.this.clear(contact);
- UiUpdateHelper.updateConversationUi();
- UiUpdateHelper.updateRosterUi();
- }
- }
- }
- }
- });
- }
-
- public void checkForAvatar(Account account, final UiCallback<Avatar> callback) {
- IqPacket packet = AvatarPacketGenerator.generateRetrieveAvatarMetadataPacket(null);
- XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
-
- @Override
- public void onIqPacketReceived(Account account, IqPacket packet) {
- if (packet.getType() == IqPacket.TYPE.RESULT) {
- Element pubsub = packet.findChild("pubsub",
- "http://jabber.org/protocol/pubsub");
- if (pubsub != null) {
- Element items = pubsub.findChild("items");
- if (items != null) {
- Avatar avatar = Avatar.parseMetadata(items);
- if (avatar != null) {
- avatar.owner = account.getJid().toBareJid();
- if (AvatarUtil.isAvatarCached(avatar)) {
- if (account.setAvatar(avatar.getFilename())) {
- DatabaseBackend.getInstance(ConversationsPlusApplication.getAppContext()).updateAccount(account);
- }
- AvatarService.this.clear(account);
- callback.success(avatar);
- } else {
- fetchAvatarPep(account, avatar, callback);
- }
- return;
- }
- }
- }
- }
- callback.error(0, null);
- }
- });
- }
-
- public void fetchAvatar(Account account, Avatar avatar) {
- fetchAvatar(account, avatar, null);
- }
-
- public void clearFetchInProgress(Account account) {
- synchronized (this.mInProgressAvatarFetches) {
- for(Iterator<String> iterator = this.mInProgressAvatarFetches.iterator(); iterator.hasNext();) {
- final String KEY = iterator.next();
- if (KEY.startsWith(account.getJid().toBareJid()+"_")) {
- iterator.remove();
- }
- }
- }
- }
-
- private void sendAndReceiveIqPackages(final Avatar avatar, final Account account, final UiCallback callback) {
-
- final IqPacket packet = AvatarPacketGenerator.generatePublishAvatarPacket(avatar);
- XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
-
- @Override
- public void onIqPacketReceived(Account account, IqPacket result) {
- if (result.getType() == IqPacket.TYPE.RESULT) {
- final IqPacket packet = AvatarPacketGenerator.generatePublishAvatarMetadataPacket(avatar);
- XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
-
- @Override
- public void onIqPacketReceived(Account account,
- IqPacket result) {
- if (result.getType() == IqPacket.TYPE.RESULT) {
- if (account.setAvatar(avatar.getFilename())) {
- AvatarService.getInstance().clear(account);
- DatabaseBackend.getInstance(ConversationsPlusApplication.getAppContext()).updateAccount(account);
- }
- callback.success(avatar);
- } else {
- callback.error(
- R.string.error_publish_avatar_server_reject,
- avatar);
- }
- }
- });
- } else {
- callback.error(
- R.string.error_publish_avatar_server_reject,
- avatar);
- }
- }
- });
- }
-}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/ContactChooserTargetService.java b/src/main/java/de/thedevstack/conversationsplus/services/ContactChooserTargetService.java
index 6256609c..84891052 100644
--- a/src/main/java/de/thedevstack/conversationsplus/services/ContactChooserTargetService.java
+++ b/src/main/java/de/thedevstack/conversationsplus/services/ContactChooserTargetService.java
@@ -17,6 +17,7 @@ import java.util.ArrayList;
import java.util.List;
import de.thedevstack.conversationsplus.entities.Conversation;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
import de.thedevstack.conversationsplus.ui.ShareWithActivity;
@TargetApi(Build.VERSION_CODES.M)
@@ -47,7 +48,7 @@ public class ContactChooserTargetService extends ChooserTargetService implements
for(int i = 0; i < Math.min(conversations.size(),MAX_TARGETS); ++i) {
final Conversation conversation = conversations.get(i);
final String name = conversation.getName();
- final Icon icon = Icon.createWithBitmap(AvatarService.getInstance().get(conversation, pixel));
+ final Icon icon = Icon.createWithBitmap(AvatarCache.get(conversation, pixel));
final float score = 1 - (1.0f / MAX_TARGETS) * i;
final Bundle extras = new Bundle();
extras.putString("uuid", conversation.getUuid());
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/NotificationService.java b/src/main/java/de/thedevstack/conversationsplus/services/NotificationService.java
index f4388b21..c21c90d1 100644
--- a/src/main/java/de/thedevstack/conversationsplus/services/NotificationService.java
+++ b/src/main/java/de/thedevstack/conversationsplus/services/NotificationService.java
@@ -29,6 +29,7 @@ import java.util.List;
import de.thedevstack.conversationsplus.ConversationsPlusApplication;
import de.thedevstack.conversationsplus.ConversationsPlusColors;
import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
import de.thedevstack.conversationsplus.utils.ImageUtil;
import de.thedevstack.conversationsplus.utils.MessageUtil;
import de.tzur.conversations.Settings;
@@ -261,7 +262,7 @@ public class NotificationService {
final ArrayList<Message> messages = notifications.values().iterator().next();
if (messages.size() >= 1) {
final Conversation conversation = messages.get(0).getConversation();
- mBuilder.setLargeIcon(AvatarService.getInstance().get(conversation, getPixel(64)));
+ mBuilder.setLargeIcon(AvatarCache.get(conversation, getPixel(64)));
mBuilder.setContentTitle(conversation.getName());
if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) {
int count = messages.size();
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java b/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java
index a7bd8006..51aee921 100644
--- a/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java
+++ b/src/main/java/de/thedevstack/conversationsplus/services/XmppConnectionService.java
@@ -55,6 +55,8 @@ import java.util.concurrent.CopyOnWriteArrayList;
import de.thedevstack.android.logcat.Logging;
import de.thedevstack.conversationsplus.ConversationsPlusApplication;
import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
import de.thedevstack.conversationsplus.services.filetransfer.FileTransferManager;
import de.thedevstack.conversationsplus.utils.AccountUtil;
import de.thedevstack.conversationsplus.utils.ImageUtil;
@@ -977,7 +979,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
+ phoneContact.getString("lookup");
contact.setSystemAccount(systemAccount);
if (contact.setPhotoUri(phoneContact.getString("photouri"))) {
- AvatarService.getInstance().clear(contact);
+ AvatarCache.clear(contact);
}
contact.setSystemName(phoneContact.getString("displayname"));
withSystemAccounts.remove(contact);
@@ -986,7 +988,7 @@ public class XmppConnectionService extends Service implements OnPhoneContactsLoa
contact.setSystemAccount(null);
contact.setSystemName(null);
if (contact.setPhotoUri(null)) {
- AvatarService.getInstance().clear(contact);
+ AvatarCache.clear(contact);
}
}
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarBitmapUtil.java b/src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarBitmapUtil.java
new file mode 100644
index 00000000..9d1546aa
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarBitmapUtil.java
@@ -0,0 +1,158 @@
+package de.thedevstack.conversationsplus.services.avatar;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.net.Uri;
+
+import java.util.List;
+import java.util.Locale;
+
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.entities.Contact;
+import de.thedevstack.conversationsplus.entities.MucOptions;
+import de.thedevstack.conversationsplus.utils.AvatarUtil;
+import de.thedevstack.conversationsplus.utils.ImageUtil;
+import de.thedevstack.conversationsplus.utils.UIHelper;
+
+/**
+ */
+public final class AvatarBitmapUtil {
+
+ private static final int FG_COLOR = 0xFFFAFAFA;
+ private static final int TRANSPARENT = 0x00000000;
+ private static final int PLACEHOLDER_COLOR = 0xFF202020;
+
+ public static Bitmap createAvatarBitmap(String name, int size) {
+ Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ drawTile(canvas, name, 0, 0, size, size);
+ return bitmap;
+ }
+
+ public static Bitmap createAvatarBitmap(MucOptions mucOptions, int size) {
+ final List<MucOptions.User> users = mucOptions.getUsers();
+ int count = users.size();
+ Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ bitmap.eraseColor(TRANSPARENT);
+
+ if (count == 0) {
+ String name = mucOptions.getConversation().getName();
+ drawTile(canvas, name, 0, 0, size, size);
+ } else if (count == 1) {
+ drawTile(canvas, users.get(0), 0, 0, size / 2 - 1, size);
+ drawTile(canvas, mucOptions.getConversation().getAccount(), size / 2 + 1, 0, size, size);
+ } else if (count == 2) {
+ drawTile(canvas, users.get(0), 0, 0, size / 2 - 1, size);
+ drawTile(canvas, users.get(1), size / 2 + 1, 0, size, size);
+ } else if (count == 3) {
+ drawTile(canvas, users.get(0), 0, 0, size / 2 - 1, size);
+ drawTile(canvas, users.get(1), size / 2 + 1, 0, size, size / 2 - 1);
+ drawTile(canvas, users.get(2), size / 2 + 1, size / 2 + 1, size,
+ size);
+ } else if (count == 4) {
+ drawTile(canvas, users.get(0), 0, 0, size / 2 - 1, size / 2 - 1);
+ drawTile(canvas, users.get(1), 0, size / 2 + 1, size / 2 - 1, size);
+ drawTile(canvas, users.get(2), size / 2 + 1, 0, size, size / 2 - 1);
+ drawTile(canvas, users.get(3), size / 2 + 1, size / 2 + 1, size,
+ size);
+ } else {
+ drawTile(canvas, users.get(0), 0, 0, size / 2 - 1, size / 2 - 1);
+ drawTile(canvas, users.get(1), 0, size / 2 + 1, size / 2 - 1, size);
+ drawTile(canvas, users.get(2), size / 2 + 1, 0, size, size / 2 - 1);
+ drawTile(canvas, "\u2026", PLACEHOLDER_COLOR, size / 2 + 1, size / 2 + 1,
+ size, size);
+ }
+
+ return bitmap;
+ }
+
+ private static boolean drawTile(Canvas canvas, String letter, int tileColor,
+ int left, int top, int right, int bottom) {
+ letter = letter.toUpperCase(Locale.getDefault());
+ Paint tilePaint = new Paint(), textPaint = new Paint();
+ tilePaint.setColor(tileColor);
+ textPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
+ textPaint.setColor(FG_COLOR);
+ textPaint.setTypeface(Typeface.create("sans-serif-light",
+ Typeface.NORMAL));
+ textPaint.setTextSize((float) ((right - left) * 0.8));
+ Rect rect = new Rect();
+
+ canvas.drawRect(new Rect(left, top, right, bottom), tilePaint);
+ textPaint.getTextBounds(letter, 0, 1, rect);
+ float width = textPaint.measureText(letter);
+ canvas.drawText(letter, (right + left) / 2 - width / 2, (top + bottom)
+ / 2 + rect.height() / 2, textPaint);
+ return true;
+ }
+
+ private static boolean drawTile(Canvas canvas, MucOptions.User user, int left,
+ int top, int right, int bottom) {
+ Contact contact = user.getContact();
+ if (contact != null) {
+ Uri uri = null;
+ if (contact.getProfilePhoto() != null) {
+ uri = Uri.parse(contact.getProfilePhoto());
+ } else if (contact.getAvatar() != null) {
+ uri = AvatarUtil.getAvatarUri(contact.getAvatar());
+ }
+ if (drawTile(canvas, uri, left, top, right, bottom)) {
+ return true;
+ }
+ } else if (user.getAvatar() != null) {
+ Uri uri = AvatarUtil.getAvatarUri(user.getAvatar());
+ if (drawTile(canvas, uri, left, top, right, bottom)) {
+ return true;
+ }
+ }
+ String name = contact != null ? contact.getDisplayName() : user.getName();
+ drawTile(canvas, name, left, top, right, bottom);
+ return true;
+ }
+
+ private static boolean drawTile(Canvas canvas, Account account, int left, int top, int right, int bottom) {
+ String avatar = account.getAvatar();
+ if (avatar != null) {
+ Uri uri = AvatarUtil.getAvatarUri(avatar);
+ if (uri != null) {
+ if (drawTile(canvas, uri, left, top, right, bottom)) {
+ return true;
+ }
+ }
+ }
+ return drawTile(canvas, account.getJid().toBareJid().toString(), left, top, right, bottom);
+ }
+
+ private static boolean drawTile(Canvas canvas, String name, int left, int top, int right, int bottom) {
+ if (name != null) {
+ String trimmedName = name.trim();
+ final String letter = trimmedName.isEmpty() ? "X" : trimmedName.substring(0, 1);
+ final int color = UIHelper.getColorForName(name);
+ drawTile(canvas, letter, color, left, top, right, bottom);
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean drawTile(Canvas canvas, Uri uri, int left, int top, int right, int bottom) {
+ if (uri != null) {
+ Bitmap bitmap = ImageUtil.cropCenter(uri, bottom - top, right - left);
+ if (bitmap != null) {
+ drawTile(canvas, bitmap, left, top, right, bottom);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean drawTile(Canvas canvas, Bitmap bm, int dstleft, int dsttop,
+ int dstright, int dstbottom) {
+ Rect dst = new Rect(dstleft, dsttop, dstright, dstbottom);
+ canvas.drawBitmap(bm, null, dst, null);
+ return true;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarCache.java b/src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarCache.java
new file mode 100644
index 00000000..a4def149
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarCache.java
@@ -0,0 +1,266 @@
+package de.thedevstack.conversationsplus.services.avatar;
+
+import android.graphics.Bitmap;
+import android.net.Uri;
+
+import java.util.ArrayList;
+
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.entities.Bookmark;
+import de.thedevstack.conversationsplus.entities.Contact;
+import de.thedevstack.conversationsplus.entities.Conversation;
+import de.thedevstack.conversationsplus.entities.ListItem;
+import de.thedevstack.conversationsplus.entities.Message;
+import de.thedevstack.conversationsplus.entities.MucOptions;
+import de.thedevstack.conversationsplus.utils.AvatarUtil;
+import de.thedevstack.conversationsplus.utils.ImageUtil;
+import de.thedevstack.conversationsplus.utils.UIHelper;
+
+/**
+ */
+public final class AvatarCache {
+
+ private static final String PREFIX_CONTACT = "contact";
+ private static final String PREFIX_CONVERSATION = "conversation";
+ private static final String PREFIX_ACCOUNT = "account";
+ private static final String PREFIX_GENERIC = "generic";
+
+ private final ArrayList<Integer> sizes = new ArrayList<>();
+ private final static AvatarCache INSTANCE = new AvatarCache();
+
+ private AvatarCache() {
+ }
+
+ private static Bitmap get(final Contact contact, final int size, boolean cachedOnly) {
+ final String KEY = key(contact, size);
+ Bitmap avatar = ImageUtil.getBitmapFromCache(KEY);
+ if (avatar != null || cachedOnly) {
+ return avatar;
+ }
+ if (contact.getProfilePhoto() != null) {
+ avatar = ImageUtil.cropCenterSquare(Uri.parse(contact.getProfilePhoto()), size);
+ }
+ if (avatar == null && contact.getAvatar() != null) {
+ avatar = AvatarUtil.getAvatar(contact.getAvatar(), size);
+ }
+ if (avatar == null) {
+ avatar = get(contact.getDisplayName(), size, cachedOnly);
+ }
+ ImageUtil.addBitmapToCache(KEY, avatar);
+ return avatar;
+ }
+
+ public static Bitmap get(final MucOptions.User user, final int size, boolean cachedOnly) {
+ Contact c = user.getContact();
+ if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null)) {
+ return get(c, size, cachedOnly);
+ } else {
+ return getImpl(user, size, cachedOnly);
+ }
+ }
+
+ private static Bitmap getImpl(final MucOptions.User user, final int size, boolean cachedOnly) {
+ final String KEY = key(user, size);
+ Bitmap avatar = ImageUtil.getBitmapFromCache(KEY);
+ if (avatar != null || cachedOnly) {
+ return avatar;
+ }
+ if (user.getAvatar() != null) {
+ avatar = AvatarUtil.getAvatar(user.getAvatar(), size);
+ }
+ if (avatar == null) {
+ Contact contact = user.getContact();
+ if (contact != null) {
+ avatar = get(contact, size, cachedOnly);
+ } else {
+ avatar = get(user.getName(), size, cachedOnly);
+ }
+ }
+ ImageUtil.addBitmapToCache(KEY, avatar);
+ return avatar;
+ }
+
+ public static void clear(Contact contact) {
+ synchronized (INSTANCE.sizes) {
+ for (Integer size : INSTANCE.sizes) {
+ ImageUtil.removeBitmapFromCache(key(contact, size));
+ }
+ }
+ }
+
+ private static String key(Contact contact, int size) {
+ synchronized (INSTANCE.sizes) {
+ if (!INSTANCE.sizes.contains(size)) {
+ INSTANCE.sizes.add(size);
+ }
+ }
+ return PREFIX_CONTACT + "_" + contact.getAccount().getJid().toBareJid() + "_"
+ + contact.getJid() + "_" + String.valueOf(size);
+ }
+
+ private static String key(MucOptions.User user, int size) {
+ synchronized (INSTANCE.sizes) {
+ if (!INSTANCE.sizes.contains(size)) {
+ INSTANCE.sizes.add(size);
+ }
+ }
+ return PREFIX_CONTACT + "_" + user.getAccount().getJid().toBareJid() + "_"
+ + user.getFullJid() + "_" + String.valueOf(size);
+ }
+
+ public static Bitmap get(ListItem item, int size) {
+ return get(item,size,false);
+ }
+
+ public static Bitmap get(ListItem item, int size, boolean cachedOnly) {
+ if (item instanceof Contact) {
+ return get((Contact) item, size,cachedOnly);
+ } else if (item instanceof Bookmark) {
+ Bookmark bookmark = (Bookmark) item;
+ if (bookmark.getConversation() != null) {
+ return get(bookmark.getConversation(), size, cachedOnly);
+ } else {
+ return get(bookmark.getDisplayName(), size, cachedOnly);
+ }
+ } else {
+ return get(item.getDisplayName(), size, cachedOnly);
+ }
+ }
+
+ public static Bitmap get(Conversation conversation, int size) {
+ return get(conversation,size,false);
+ }
+
+ public static Bitmap get(Conversation conversation, int size, boolean cachedOnly) {
+ if (conversation.getMode() == Conversation.MODE_SINGLE) {
+ return get(conversation.getContact(), size, cachedOnly);
+ } else {
+ return get(conversation.getMucOptions(), size, cachedOnly);
+ }
+ }
+
+ public static void clear(MucOptions options) {
+ synchronized (INSTANCE.sizes) {
+ for (Integer size : INSTANCE.sizes) {
+ ImageUtil.removeBitmapFromCache(key(options, size));
+ }
+ }
+ }
+
+ private static String key(MucOptions options, int size) {
+ synchronized (INSTANCE.sizes) {
+ if (!INSTANCE.sizes.contains(size)) {
+ INSTANCE.sizes.add(size);
+ }
+ }
+ return PREFIX_CONVERSATION + "_" + options.getConversation().getUuid()
+ + "_" + String.valueOf(size);
+ }
+
+ public static Bitmap get(Account account, int size) {
+ return get(account, size, false);
+ }
+
+ public static Bitmap get(Account account, int size, boolean cachedOnly) {
+ final String KEY = key(account, size);
+ Bitmap avatar = ImageUtil.getBitmapFromCache(KEY);
+ if (avatar != null || cachedOnly) {
+ return avatar;
+ }
+ avatar = AvatarUtil.getAvatar(account.getAvatar(), size);
+ if (avatar == null) {
+ avatar = get(account.getJid().toBareJid().toString(), size,false);
+ }
+ ImageUtil.addBitmapToCache(KEY, avatar);
+ return avatar;
+ }
+
+ public static Bitmap get(Message message, int size, boolean cachedOnly) {
+ final Conversation conversation = message.getConversation();
+ if (message.getStatus() == Message.STATUS_RECEIVED) {
+ Contact c = message.getContact();
+ if (c != null && (c.getProfilePhoto() != null || c.getAvatar() != null)) {
+ return get(c, size, cachedOnly);
+ } else if (message.getConversation().getMode() == Conversation.MODE_MULTI){
+ MucOptions.User user = conversation.getMucOptions().findUser(message.getCounterpart().getResourcepart());
+ if (user != null) {
+ return getImpl(user,size,cachedOnly);
+ }
+ }
+ return get(UIHelper.getMessageDisplayName(message), size, cachedOnly);
+ } else {
+ return get(conversation.getAccount(), size, cachedOnly);
+ }
+ }
+
+ public static void clear(Account account) {
+ synchronized (INSTANCE.sizes) {
+ for (Integer size : INSTANCE.sizes) {
+ ImageUtil.removeBitmapFromCache(key(account, size));
+ }
+ }
+ }
+
+ public static void clear(MucOptions.User user) {
+ synchronized (INSTANCE.sizes) {
+ for (Integer size : INSTANCE.sizes) {
+ ImageUtil.removeBitmapFromCache(key(user, size));
+ }
+ }
+ }
+
+ private static String key(Account account, int size) {
+ synchronized (INSTANCE.sizes) {
+ if (!INSTANCE.sizes.contains(size)) {
+ INSTANCE.sizes.add(size);
+ }
+ }
+ return PREFIX_ACCOUNT + "_" + account.getUuid() + "_"
+ + String.valueOf(size);
+ }
+
+ public static Bitmap get(String name, int size) {
+ return get(name,size,false);
+ }
+
+ public static Bitmap get(final String name, final int size, boolean cachedOnly) {
+ final String KEY = key(name, size);
+ Bitmap bitmap = ImageUtil.getBitmapFromCache(KEY);
+ if (bitmap != null || cachedOnly) {
+ return bitmap;
+ }
+
+ bitmap = AvatarBitmapUtil.createAvatarBitmap(name, size);
+ ImageUtil.addBitmapToCache(KEY, bitmap);
+ return bitmap;
+ }
+
+ private static String key(String name, int size) {
+ synchronized (INSTANCE.sizes) {
+ if (!INSTANCE.sizes.contains(size)) {
+ INSTANCE.sizes.add(size);
+ }
+ }
+ return PREFIX_GENERIC + "_" + name + "_" + String.valueOf(size);
+ }
+
+ public static void clear(Conversation conversation) {
+ if (conversation.getMode() == Conversation.MODE_SINGLE) {
+ clear(conversation.getContact());
+ } else {
+ clear(conversation.getMucOptions());
+ }
+ }
+
+ private static Bitmap get(MucOptions mucOptions, int size, boolean cachedOnly) {
+ final String KEY = key(mucOptions, size);
+ Bitmap bitmap = ImageUtil.getBitmapFromCache(KEY);
+ if (bitmap != null || cachedOnly) {
+ return bitmap;
+ }
+
+ bitmap = AvatarBitmapUtil.createAvatarBitmap(mucOptions, size);
+ ImageUtil.addBitmapToCache(KEY, bitmap);
+ return bitmap;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarService.java b/src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarService.java
new file mode 100644
index 00000000..47443488
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarService.java
@@ -0,0 +1,210 @@
+package de.thedevstack.conversationsplus.services.avatar;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.widget.ImageView;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.dto.LoadAvatarFor;
+import de.thedevstack.conversationsplus.services.avatar.listener.AvatarMetadataReceived;
+import de.thedevstack.conversationsplus.services.avatar.listener.AvatarPepReceived;
+import de.thedevstack.conversationsplus.services.avatar.listener.AvatarVcardReceived;
+import de.thedevstack.conversationsplus.services.avatar.listener.PublishAvatarResponseReceived;
+import de.thedevstack.conversationsplus.services.avatar.listener.RepublishAvatarAfterMetadataReceived;
+import de.thedevstack.conversationsplus.ui.AsyncDrawable;
+import de.thedevstack.conversationsplus.ui.tasks.AvatarBitmapTask;
+import de.thedevstack.conversationsplus.utils.AvatarUtil;
+import de.thedevstack.conversationsplus.utils.XmppSendUtil;
+import de.thedevstack.conversationsplus.xmpp.avatar.AvatarPacketGenerator;
+import de.thedevstack.conversationsplus.Config;
+import de.thedevstack.conversationsplus.R;
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.entities.Conversation;
+import de.thedevstack.conversationsplus.entities.Message;
+import de.thedevstack.conversationsplus.ui.UiCallback;
+import de.thedevstack.conversationsplus.utils.UIHelper;
+import de.thedevstack.conversationsplus.xmpp.OnAdvancedStreamFeaturesLoaded;
+import de.thedevstack.conversationsplus.xmpp.XmppConnection;
+import de.thedevstack.conversationsplus.xmpp.avatar.AvatarVcardPacketGenerator;
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+public class AvatarService implements OnAdvancedStreamFeaturesLoaded {
+
+ private static final AvatarService INSTANCE = new AvatarService();
+
+ private final List<String> mInProgressAvatarFetches = new ArrayList<>();
+
+ public static AvatarService getInstance() {
+ return INSTANCE;
+ }
+
+ public void loadAvatar(LoadAvatarFor loadAvatarFor, ImageView imageView) {
+ if (cancelPotentialWork(imageView)) {
+ Resources resources = ConversationsPlusApplication.getAppContext().getResources();
+ int avatarSize = resources.getDimensionPixelSize(R.dimen.avatar_size);
+ final Bitmap bm;
+ if (loadAvatarFor instanceof Conversation) {
+ bm = AvatarCache.get((Conversation) loadAvatarFor, avatarSize, true);
+ } else if (loadAvatarFor instanceof Message) {
+ bm = AvatarCache.get((Message) loadAvatarFor, avatarSize, true);
+ } else {
+ bm = null;
+ }
+ int backgroundColor = 0x00000000;
+ if (bm != null) {
+ imageView.setImageBitmap(bm);
+ imageView.setBackgroundColor(backgroundColor);
+ } else {
+ if (loadAvatarFor instanceof Conversation) {
+ backgroundColor = UIHelper.getColorForName(((Conversation) loadAvatarFor).getName());
+ } else if (loadAvatarFor instanceof Message) {
+ backgroundColor = UIHelper.getColorForName(UIHelper.getMessageDisplayName((Message) loadAvatarFor));
+ }
+ imageView.setBackgroundColor(backgroundColor);
+ imageView.setImageDrawable(null);
+ final AvatarBitmapTask<LoadAvatarFor> task = new AvatarBitmapTask<>(imageView, avatarSize);
+ final AsyncDrawable asyncDrawable = new AsyncDrawable(resources, null, task);
+ imageView.setImageDrawable(asyncDrawable);
+ try {
+ task.execute(loadAvatarFor);
+ } catch (final RejectedExecutionException ignored) {
+ }
+ }
+ }
+ }
+
+ public static boolean cancelPotentialWork(ImageView imageView) {
+ return null == getBitmapWorkerTask(imageView);
+ }
+
+ private static AvatarBitmapTask<LoadAvatarFor> getBitmapWorkerTask(ImageView imageView) {
+ if (imageView != null) {
+ final Drawable drawable = imageView.getDrawable();
+ if (drawable instanceof AsyncDrawable) {
+ final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
+ return asyncDrawable.getBitmapWorkerTask();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void onAdvancedStreamFeaturesAvailable(Account account) {
+ XmppConnection.Features features = account.getXmppConnection().getFeatures();
+ if (features.pep() && !features.pepPersistent()) {
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": has pep but is not persistent");
+ if (account.getAvatar() != null) {
+ republishAvatarIfNeeded(account);
+ }
+ }
+ }
+
+ public void publishAvatar(final Account account,
+ final Uri image,
+ final UiCallback<Avatar> callback) {
+ final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
+ final int size = Config.AVATAR_SIZE;
+ final Avatar avatar = AvatarUtil.getPepAvatar(image, size, format);
+ if (avatar != null) {
+ avatar.height = size;
+ avatar.width = size;
+ if (format.equals(Bitmap.CompressFormat.WEBP)) {
+ avatar.type = "image/webp";
+ } else if (format.equals(Bitmap.CompressFormat.JPEG)) {
+ avatar.type = "image/jpeg";
+ } else if (format.equals(Bitmap.CompressFormat.PNG)) {
+ avatar.type = "image/png";
+ }
+ if (!AvatarUtil.save(avatar)) {
+ callback.error(R.string.error_saving_avatar, avatar);
+ return;
+ }
+ publishAvatar(avatar, account, callback);
+ } else {
+ callback.error(R.string.error_publish_avatar_converting, null);
+ }
+ }
+
+ public void republishAvatarIfNeeded(Account account) {
+ if (account.getAxolotlService().isPepBroken()) {
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": skipping republication of avatar because pep is broken");
+ return;
+ }
+ IqPacket packet = AvatarPacketGenerator.generateRetrieveAvatarMetadataPacket(null);
+ XmppSendUtil.sendIqPacket(account, packet, new RepublishAvatarAfterMetadataReceived());
+ }
+
+ 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)) {
+ return;
+ } else {
+ 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;
+ }
+ }
+ }
+ }
+
+ public void fetchAvatarPep(final Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
+ IqPacket packet = AvatarPacketGenerator.generateRetrieveAvatarPacket(avatar);
+ XmppSendUtil.sendIqPacket(account, packet, new AvatarPepReceived(avatar, callback));
+ }
+
+ private void fetchAvatarVcard(final Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
+ IqPacket packet = AvatarVcardPacketGenerator.generateRetreivePacket(avatar);
+ XmppSendUtil.sendIqPacket(account, packet, new AvatarVcardReceived(avatar, callback));
+ }
+
+ public void checkForAvatar(Account account, final UiCallback<Avatar> callback) {
+ IqPacket packet = AvatarPacketGenerator.generateRetrieveAvatarMetadataPacket(null);
+ XmppSendUtil.sendIqPacket(account, packet, new AvatarMetadataReceived(callback));
+ }
+
+ public void fetchAvatar(Account account, Avatar avatar) {
+ fetchAvatar(account, avatar, null);
+ }
+
+ public void clearFetchInProgress(Account account) {
+ synchronized (this.mInProgressAvatarFetches) {
+ for(Iterator<String> iterator = this.mInProgressAvatarFetches.iterator(); iterator.hasNext();) {
+ final String KEY = iterator.next();
+ if (KEY.startsWith(account.getJid().toBareJid()+"_")) {
+ iterator.remove();
+ }
+ }
+ }
+ }
+
+ public void publishAvatar(final Avatar avatar, final Account account, final UiCallback callback) {
+ final IqPacket packet = AvatarPacketGenerator.generatePublishAvatarPacket(avatar);
+ XmppSendUtil.sendIqPacket(account, packet, new PublishAvatarResponseReceived(avatar, callback));
+ }
+
+ synchronized public void removeFromFetchInProgress(Account account, Avatar avatar) {
+ synchronized (mInProgressAvatarFetches) {
+ mInProgressAvatarFetches.remove(generateFetchKey(account, avatar));
+ }
+ }
+
+ private static String generateFetchKey(Account account, final Avatar avatar) {
+ return account.getJid().toBareJid()+"_"+avatar.owner+"_"+avatar.sha1sum;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AbstractAvatarIqPacketReceived.java b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AbstractAvatarIqPacketReceived.java
new file mode 100644
index 00000000..69dcdcc4
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AbstractAvatarIqPacketReceived.java
@@ -0,0 +1,18 @@
+package de.thedevstack.conversationsplus.services.avatar.listener;
+
+import de.thedevstack.conversationsplus.ui.UiCallback;
+import de.thedevstack.conversationsplus.xmpp.OnIqPacketReceived;
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
+
+/**
+ *
+ */
+public abstract class AbstractAvatarIqPacketReceived implements OnIqPacketReceived {
+ final protected UiCallback callback;
+ final protected Avatar avatar;
+
+ public AbstractAvatarIqPacketReceived(Avatar avatar, UiCallback uiCallback) {
+ this.callback = uiCallback;
+ this.avatar = avatar;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AvatarMetadataReceived.java b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AvatarMetadataReceived.java
new file mode 100644
index 00000000..b993ff18
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AvatarMetadataReceived.java
@@ -0,0 +1,47 @@
+package de.thedevstack.conversationsplus.services.avatar.listener;
+
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.persistance.DatabaseBackend;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
+import de.thedevstack.conversationsplus.ui.UiCallback;
+import de.thedevstack.conversationsplus.utils.AvatarUtil;
+import de.thedevstack.conversationsplus.xmpp.avatar.AvatarPacketParser;
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ *
+ */
+public class AvatarMetadataReceived extends AbstractAvatarIqPacketReceived {
+
+ public AvatarMetadataReceived(UiCallback uiCallback) {
+ super(null, uiCallback);
+ }
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE.RESULT) {
+ Avatar avatar = AvatarPacketParser.parseMetadata(packet);
+ if (avatar != null) {
+ avatar.owner = account.getJid().toBareJid();
+ if (AvatarUtil.isAvatarCached(avatar)) {
+ if (account.setAvatar(avatar.getFilename())) {
+ DatabaseBackend.getInstance(ConversationsPlusApplication.getAppContext()).updateAccount(account);
+ }
+ AvatarCache.clear(account);
+ if (null != callback) {
+ callback.success(avatar);
+ }
+ } else {
+ AvatarService.getInstance().fetchAvatarPep(account, avatar, callback);
+ }
+ return;
+ }
+ }
+ if (null != callback) {
+ callback.error(0, null);
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AvatarPepReceived.java b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AvatarPepReceived.java
new file mode 100644
index 00000000..c248d7c8
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AvatarPepReceived.java
@@ -0,0 +1,75 @@
+package de.thedevstack.conversationsplus.services.avatar.listener;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.Config;
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.entities.Contact;
+import de.thedevstack.conversationsplus.persistance.DatabaseBackend;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
+import de.thedevstack.conversationsplus.ui.UiCallback;
+import de.thedevstack.conversationsplus.utils.AvatarUtil;
+import de.thedevstack.conversationsplus.utils.UiUpdateHelper;
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.avatar.AvatarPacketParser;
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ *
+ */
+public class AvatarPepReceived extends AbstractAvatarIqPacketReceived {
+ public AvatarPepReceived(Avatar avatar, UiCallback uiCallback) {
+ super(avatar, uiCallback);
+ }
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket result) {
+ AvatarService.getInstance().removeFromFetchInProgress(account, avatar);
+
+ final String ERROR = account.getJid().toBareJid()
+ + ": fetching avatar for " + avatar.owner + " failed ";
+ if (result.getType() == IqPacket.TYPE.RESULT) {
+ avatar.image = AvatarPacketParser.parseAvatarData(result);
+ if (avatar.image != null) {
+ if (AvatarUtil.save(avatar)) {
+ if (account.getJid().toBareJid().equals(avatar.owner)) {
+ if (account.setAvatar(avatar.getFilename())) {
+ DatabaseBackend.getInstance(ConversationsPlusApplication.getAppContext()).updateAccount(account);
+ }
+ AvatarCache.clear(account);
+ UiUpdateHelper.updateConversationUi();
+ UiUpdateHelper.updateAccountUi();
+ } else {
+ Contact contact = account.getRoster().getContact(avatar.owner);
+ contact.setAvatar(avatar);
+ AvatarCache.clear(contact);
+ UiUpdateHelper.updateConversationUi();
+ UiUpdateHelper.updateRosterUi();
+ }
+ if (callback != null) {
+ callback.success(avatar);
+ }
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid()
+ + ": succesfuly fetched pep avatar for " + avatar.owner);
+ return;
+ }
+ } else {
+
+ Logging.d(Config.LOGTAG, ERROR + "(parsing error)");
+ }
+ } else {
+ Element error = result.findChild("error");
+ if (error == null) {
+ Logging.d(Config.LOGTAG, ERROR + "(server error)");
+ } else {
+ Logging.d(Config.LOGTAG, ERROR + error.toString());
+ }
+ }
+ if (callback != null) {
+ callback.error(0, null);
+ }
+
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AvatarVcardReceived.java b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AvatarVcardReceived.java
new file mode 100644
index 00000000..00036109
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/AvatarVcardReceived.java
@@ -0,0 +1,47 @@
+package de.thedevstack.conversationsplus.services.avatar.listener;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.Config;
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.entities.Contact;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
+import de.thedevstack.conversationsplus.ui.UiCallback;
+import de.thedevstack.conversationsplus.utils.AvatarUtil;
+import de.thedevstack.conversationsplus.utils.UiUpdateHelper;
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ *
+ */
+public class AvatarVcardReceived extends AbstractAvatarIqPacketReceived {
+ public AvatarVcardReceived(Avatar avatar, UiCallback uiCallback) {
+ super(avatar, uiCallback);
+ }
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ AvatarService.getInstance().removeFromFetchInProgress(account, avatar);
+
+ if (packet.getType() == IqPacket.TYPE.RESULT) {
+ Element vCard = packet.findChild("vCard", "vcard-temp");
+ Element photo = vCard != null ? vCard.findChild("PHOTO") : null;
+ String image = photo != null ? photo.findChildContent("BINVAL") : null;
+ if (image != null) {
+ avatar.image = image;
+ if (AvatarUtil.save(avatar)) {
+ Logging.d(Config.LOGTAG, account.getJid().toBareJid()
+ + ": successfully fetched vCard avatar for " + avatar.owner);
+ Contact contact = account.getRoster()
+ .getContact(avatar.owner);
+ contact.setAvatar(avatar);
+ AvatarCache.clear(contact);
+ UiUpdateHelper.updateConversationUi();
+ UiUpdateHelper.updateRosterUi();
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/PublishAvatarMetadataResponseReceived.java b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/PublishAvatarMetadataResponseReceived.java
new file mode 100644
index 00000000..79380dbf
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/PublishAvatarMetadataResponseReceived.java
@@ -0,0 +1,37 @@
+package de.thedevstack.conversationsplus.services.avatar.listener;
+
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.R;
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.persistance.DatabaseBackend;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
+import de.thedevstack.conversationsplus.ui.UiCallback;
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ *
+ */
+public class PublishAvatarMetadataResponseReceived extends AbstractAvatarIqPacketReceived {
+
+ public PublishAvatarMetadataResponseReceived(Avatar avatar, UiCallback uiCallback) {
+ super(avatar, uiCallback);
+ }
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket result) {
+ if (result.getType() == IqPacket.TYPE.RESULT) {
+ if (account.setAvatar(avatar.getFilename())) {
+ AvatarCache.clear(account);
+ DatabaseBackend.getInstance(ConversationsPlusApplication.getAppContext()).updateAccount(account);
+ }
+ if (null != callback) {
+ callback.success(avatar);
+ }
+ } else {
+ if (null != callback) {
+ callback.error(R.string.error_publish_avatar_server_reject, avatar);
+ }
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/PublishAvatarResponseReceived.java b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/PublishAvatarResponseReceived.java
new file mode 100644
index 00000000..e062fce6
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/PublishAvatarResponseReceived.java
@@ -0,0 +1,31 @@
+package de.thedevstack.conversationsplus.services.avatar.listener;
+
+import de.thedevstack.conversationsplus.R;
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.ui.UiCallback;
+import de.thedevstack.conversationsplus.utils.XmppSendUtil;
+import de.thedevstack.conversationsplus.xmpp.avatar.AvatarPacketGenerator;
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ *
+ */
+public class PublishAvatarResponseReceived extends AbstractAvatarIqPacketReceived {
+
+ public PublishAvatarResponseReceived(Avatar avatar, UiCallback uiCallback) {
+ super(avatar, uiCallback);
+ }
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket result) {
+ if (result.getType() == IqPacket.TYPE.RESULT) {
+ final IqPacket packet = AvatarPacketGenerator.generatePublishAvatarMetadataPacket(avatar);
+ XmppSendUtil.sendIqPacket(account, packet, new PublishAvatarMetadataResponseReceived(avatar, callback));
+ } else {
+ if (null != callback) {
+ callback.error(R.string.error_publish_avatar_server_reject, avatar);
+ }
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/RepublishAvatarAfterMetadataReceived.java b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/RepublishAvatarAfterMetadataReceived.java
new file mode 100644
index 00000000..16f4bf81
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/services/avatar/listener/RepublishAvatarAfterMetadataReceived.java
@@ -0,0 +1,40 @@
+package de.thedevstack.conversationsplus.services.avatar.listener;
+
+import de.thedevstack.android.logcat.Logging;
+import de.thedevstack.conversationsplus.Config;
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
+import de.thedevstack.conversationsplus.utils.AvatarUtil;
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.OnIqPacketReceived;
+import de.thedevstack.conversationsplus.xmpp.avatar.AvatarPacketParser;
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ */
+public class RepublishAvatarAfterMetadataReceived implements OnIqPacketReceived {
+
+ private boolean errorIsItemNotFound(IqPacket packet) {
+ Element error = packet.findChild("error");
+ return packet.getType() == IqPacket.TYPE.ERROR
+ && error != null
+ && error.hasChild("item-not-found");
+ }
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE.RESULT || errorIsItemNotFound(packet)) {
+ Avatar serverAvatar = AvatarPacketParser.parseMetadata(packet);
+ if (serverAvatar == null && account.getAvatar() != null) {
+ Avatar avatar = AvatarUtil.getStoredPepAvatar(account.getAvatar());
+ if (avatar != null) {
+ Logging.d(Config.LOGTAG,account.getJid().toBareJid()+": avatar on server was null. republishing");
+ AvatarService.getInstance().publishAvatar(avatar, account, null);
+ } else {
+ Logging.e(Config.LOGTAG, account.getJid().toBareJid()+": error rereading avatar");
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/ConferenceDetailsActivity.java b/src/main/java/de/thedevstack/conversationsplus/ui/ConferenceDetailsActivity.java
index 2a3cd7fe..7ea83b92 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/ConferenceDetailsActivity.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/ConferenceDetailsActivity.java
@@ -41,7 +41,8 @@ import de.thedevstack.conversationsplus.entities.Contact;
import de.thedevstack.conversationsplus.entities.Conversation;
import de.thedevstack.conversationsplus.entities.MucOptions;
import de.thedevstack.conversationsplus.entities.MucOptions.User;
-import de.thedevstack.conversationsplus.services.AvatarService;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
import de.thedevstack.conversationsplus.services.XmppConnectionService;
import de.thedevstack.conversationsplus.services.XmppConnectionService.OnConversationUpdate;
import de.thedevstack.conversationsplus.services.XmppConnectionService.OnMucRosterUpdate;
@@ -528,7 +529,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
account = mConversation.getAccount().getJid().toBareJid().toString();
}
mAccountJid.setText(getString(R.string.using_account, account));
- mYourPhoto.setImageBitmap(AvatarService.getInstance().get(mConversation.getAccount(), getPixel(48)));
+ mYourPhoto.setImageBitmap(AvatarCache.get(mConversation.getAccount(), getPixel(48)));
setTitle(mConversation.getName());
if (Config.LOCK_DOMAINS_IN_CONVERSATIONS && mConversation.getJid().getDomainpart().equals(Config.CONFERENCE_DOMAIN_LOCK)) {
mFullJid.setText(mConversation.getJid().getLocalpart());
@@ -622,7 +623,7 @@ public class ConferenceDetailsActivity extends XmppActivity implements OnConvers
}
ImageView iv = (ImageView) view.findViewById(R.id.contact_photo);
- iv.setImageBitmap(AvatarService.getInstance().get(user, getPixel(48), false));
+ iv.setImageBitmap(AvatarCache.get(user, getPixel(48), false));
membersView.addView(view);
if (mConversation.getMucOptions().canInvite()) {
mInviteButton.setVisibility(View.VISIBLE);
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/ContactDetailsActivity.java b/src/main/java/de/thedevstack/conversationsplus/ui/ContactDetailsActivity.java
index 6577c9ce..be6a5994 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/ContactDetailsActivity.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/ContactDetailsActivity.java
@@ -34,6 +34,7 @@ import java.util.List;
import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
import de.thedevstack.conversationsplus.generator.PresenceGenerator;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
import de.thedevstack.conversationsplus.ui.listeners.ShowResourcesListDialogListener;
import de.thedevstack.conversationsplus.Config;
import de.thedevstack.conversationsplus.R;
@@ -43,7 +44,7 @@ import de.thedevstack.conversationsplus.crypto.axolotl.XmppAxolotlSession;
import de.thedevstack.conversationsplus.entities.Account;
import de.thedevstack.conversationsplus.entities.Contact;
import de.thedevstack.conversationsplus.entities.ListItem;
-import de.thedevstack.conversationsplus.services.AvatarService;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
import de.thedevstack.conversationsplus.services.XmppConnectionService.OnAccountUpdate;
import de.thedevstack.conversationsplus.services.XmppConnectionService.OnRosterUpdate;
import de.thedevstack.conversationsplus.utils.CryptoHelper;
@@ -364,7 +365,7 @@ public class ContactDetailsActivity extends XmppActivity implements OnAccountUpd
}
contactJidTv.setOnClickListener(new ShowResourcesListDialogListener(ContactDetailsActivity.this, contact));
accountJidTv.setText(getString(R.string.using_account, account));
- badge.setImageBitmap(AvatarService.getInstance().get(contact, getPixel(72)));
+ badge.setImageBitmap(AvatarCache.get(contact, getPixel(72)));
badge.setOnClickListener(this.onBadgeClick);
keys.removeAllViews();
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/EditAccountActivity.java b/src/main/java/de/thedevstack/conversationsplus/ui/EditAccountActivity.java
index 1a868949..1e81603f 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/EditAccountActivity.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/EditAccountActivity.java
@@ -5,7 +5,6 @@ import android.app.AlertDialog.Builder;
import android.app.PendingIntent;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
@@ -40,12 +39,13 @@ import java.util.concurrent.atomic.AtomicInteger;
import de.thedevstack.conversationsplus.ConversationsPlusColors;
import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
import de.thedevstack.conversationsplus.ui.listeners.ShowResourcesListDialogListener;
import de.thedevstack.conversationsplus.Config;
import de.thedevstack.conversationsplus.R;
import de.thedevstack.conversationsplus.crypto.axolotl.AxolotlService;
import de.thedevstack.conversationsplus.entities.Account;
-import de.thedevstack.conversationsplus.services.AvatarService;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
import de.thedevstack.conversationsplus.services.XmppConnectionService;
import de.thedevstack.conversationsplus.services.XmppConnectionService.OnAccountUpdate;
import de.thedevstack.conversationsplus.services.XmppConnectionService.OnCaptchaRequested;
@@ -624,7 +624,7 @@ public class EditAccountActivity extends XmppActivity implements OnAccountUpdate
if (!mInitMode) {
this.mAvatar.setVisibility(View.VISIBLE);
- this.mAvatar.setImageBitmap(AvatarService.getInstance().get(this.mAccount, getPixel(72)));
+ this.mAvatar.setImageBitmap(AvatarCache.get(this.mAccount, getPixel(72)));
} else {
this.mAvatar.setVisibility(View.GONE);
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/PublishProfilePictureActivity.java b/src/main/java/de/thedevstack/conversationsplus/ui/PublishProfilePictureActivity.java
index 6793d882..b41511de 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/PublishProfilePictureActivity.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/PublishProfilePictureActivity.java
@@ -4,7 +4,6 @@ import android.app.PendingIntent;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
@@ -20,15 +19,14 @@ import android.widget.Toast;
import com.soundcloud.android.crop.Crop;
import java.io.File;
-import java.io.FileNotFoundException;
import de.thedevstack.conversationsplus.ConversationsPlusColors;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
import de.thedevstack.conversationsplus.utils.ImageUtil;
import de.thedevstack.conversationsplus.Config;
import de.thedevstack.conversationsplus.R;
import de.thedevstack.conversationsplus.entities.Account;
-import de.thedevstack.conversationsplus.services.AvatarService;
-import de.thedevstack.conversationsplus.utils.ExifHelper;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
import de.thedevstack.conversationsplus.utils.FileUtils;
import de.thedevstack.conversationsplus.utils.PhoneHelper;
import de.thedevstack.conversationsplus.utils.ui.TextViewUtil;
@@ -236,7 +234,7 @@ public class PublishProfilePictureActivity extends XmppActivity {
if (this.avatarUri == null) {
if (this.account.getAvatar() != null
|| this.defaultUri == null) {
- this.avatar.setImageBitmap(AvatarService.getInstance().get(account, getPixel(192)));
+ this.avatar.setImageBitmap(AvatarCache.get(account, getPixel(192)));
if (this.defaultUri != null) {
this.avatar
.setOnLongClickListener(this.backToDefaultListener);
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/AccountAdapter.java b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/AccountAdapter.java
index ee209576..960cb00d 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/AccountAdapter.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/AccountAdapter.java
@@ -16,7 +16,8 @@ import de.thedevstack.conversationsplus.Config;
import de.thedevstack.conversationsplus.ConversationsPlusColors;
import de.thedevstack.conversationsplus.R;
import de.thedevstack.conversationsplus.entities.Account;
-import de.thedevstack.conversationsplus.services.AvatarService;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
import de.thedevstack.conversationsplus.ui.ManageAccountActivity;
import de.thedevstack.conversationsplus.ui.XmppActivity;
@@ -45,7 +46,7 @@ public class AccountAdapter extends ArrayAdapter<Account> {
}
TextView statusView = (TextView) view.findViewById(R.id.account_status);
ImageView imageView = (ImageView) view.findViewById(R.id.account_image);
- imageView.setImageBitmap(AvatarService.getInstance().get(account, activity.getPixel(48)));
+ imageView.setImageBitmap(AvatarCache.get(account, activity.getPixel(48)));
statusView.setText(getContext().getString(account.getStatus().getReadableId()));
switch (account.getStatus()) {
case ONLINE:
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java
index 8388d449..e87cb052 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ConversationAdapter.java
@@ -23,7 +23,7 @@ import de.thedevstack.conversationsplus.entities.Account;
import de.thedevstack.conversationsplus.entities.Conversation;
import de.thedevstack.conversationsplus.entities.Message;
import de.thedevstack.conversationsplus.entities.Transferable;
-import de.thedevstack.conversationsplus.services.AvatarService;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
import de.thedevstack.conversationsplus.ui.ConversationActivity;
import de.thedevstack.conversationsplus.ui.XmppActivity;
import de.thedevstack.conversationsplus.utils.UIHelper;
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ListItemAdapter.java b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ListItemAdapter.java
index a67f5bcd..49d88712 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ListItemAdapter.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/ListItemAdapter.java
@@ -19,10 +19,11 @@ import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
import de.tzur.conversations.Settings;
import de.thedevstack.conversationsplus.R;
import de.thedevstack.conversationsplus.entities.ListItem;
-import de.thedevstack.conversationsplus.services.AvatarService;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
import de.thedevstack.conversationsplus.ui.XmppActivity;
import de.thedevstack.conversationsplus.utils.UIHelper;
@@ -111,7 +112,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
@Override
protected Bitmap doInBackground(ListItem... params) {
- return AvatarService.getInstance().get(params[0], activity.getPixel(48));
+ return AvatarCache.get(params[0], activity.getPixel(48));
}
@Override
@@ -128,7 +129,7 @@ public class ListItemAdapter extends ArrayAdapter<ListItem> {
public void loadAvatar(ListItem item, ImageView imageView) {
if (cancelPotentialWork(item, imageView)) {
- final Bitmap bm = AvatarService.getInstance().get(item,activity.getPixel(48),true);
+ final Bitmap bm = AvatarCache.get(item,activity.getPixel(48),true);
if (bm != null) {
imageView.setImageBitmap(bm);
imageView.setBackgroundColor(0x00000000);
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java
index 3cf50925..4c2917e3 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/adapter/MessageAdapter.java
@@ -47,7 +47,8 @@ import de.thedevstack.conversationsplus.entities.Transferable;
import de.thedevstack.conversationsplus.enums.FileStatus;
import de.thedevstack.conversationsplus.persistance.FileBackend;
import de.thedevstack.conversationsplus.providers.ConversationsPlusFileProvider;
-import de.thedevstack.conversationsplus.services.AvatarService;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
import de.thedevstack.conversationsplus.services.filetransfer.http.download.AutomaticFileDownload;
import de.thedevstack.conversationsplus.ui.ConversationActivity;
import de.thedevstack.conversationsplus.utils.CryptoHelper;
@@ -511,7 +512,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
viewHolder.status_message.setVisibility(View.VISIBLE);
viewHolder.contact_picture.setVisibility(View.VISIBLE);
if (conversation.getMode() == Conversation.MODE_SINGLE) {
- viewHolder.contact_picture.setImageBitmap(AvatarService.getInstance().get(conversation.getContact(),
+ viewHolder.contact_picture.setImageBitmap(AvatarCache.get(conversation.getContact(),
activity.getPixel(32)));
viewHolder.contact_picture.setAlpha(0.5f);
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/ui/tasks/AvatarBitmapTask.java b/src/main/java/de/thedevstack/conversationsplus/ui/tasks/AvatarBitmapTask.java
index ec89b001..b20985a4 100644
--- a/src/main/java/de/thedevstack/conversationsplus/ui/tasks/AvatarBitmapTask.java
+++ b/src/main/java/de/thedevstack/conversationsplus/ui/tasks/AvatarBitmapTask.java
@@ -9,7 +9,8 @@ import java.lang.ref.WeakReference;
import de.thedevstack.conversationsplus.dto.LoadAvatarFor;
import de.thedevstack.conversationsplus.entities.Conversation;
import de.thedevstack.conversationsplus.entities.Message;
-import de.thedevstack.conversationsplus.services.AvatarService;
+import de.thedevstack.conversationsplus.services.avatar.AvatarCache;
+import de.thedevstack.conversationsplus.services.avatar.AvatarService;
/**
*
@@ -26,9 +27,9 @@ public class AvatarBitmapTask<T extends LoadAvatarFor> extends AsyncTask<T, Void
@Override
protected Bitmap doInBackground(T... params) {
if (params[0] instanceof Conversation) {
- return AvatarService.getInstance().get((Conversation)params[0], this.avatarSize);
+ return AvatarCache.get((Conversation)params[0], this.avatarSize);
} else if (params[0] instanceof Message) {
- return AvatarService.getInstance().get((Message) params[0], this.avatarSize, isCancelled()); // Wirklich die richtige Nutzung von isCancelled()???
+ return AvatarCache.get((Message) params[0], this.avatarSize, isCancelled()); // Wirklich die richtige Nutzung von isCancelled()???
} else {
return null;
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketParser.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketParser.java
index 0867524b..78ab9288 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketParser.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketParser.java
@@ -1,5 +1,6 @@
package de.thedevstack.conversationsplus.xmpp.avatar;
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
import de.thedevstack.conversationsplus.xmpp.pubsub.PubSubPacketParser;
import de.thedevstack.conversationsplus.xml.Element;
import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
@@ -26,4 +27,56 @@ public class AvatarPacketParser {
}
return base64Avatar;
}
+
+ public static Avatar parseMetadata(Element items) {
+ if (null != 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");
+ String hash = child.getAttribute("id");
+ if (!Avatar.isValidSHA1(hash)) {
+ return null;
+ }
+ avatar.sha1sum = hash;
+ avatar.origin = Avatar.Origin.PEP;
+ return avatar;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static Avatar parseMetadata(IqPacket packet) {
+ return parseMetadata(PubSubPacketParser.findItems(packet));
+ }
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarVcardPacketGenerator.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarVcardPacketGenerator.java
new file mode 100644
index 00000000..375702df
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarVcardPacketGenerator.java
@@ -0,0 +1,16 @@
+package de.thedevstack.conversationsplus.xmpp.avatar;
+
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ *
+ */
+public class AvatarVcardPacketGenerator {
+ public static IqPacket generateRetreivePacket(Avatar avatar) {
+ final IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
+ packet.setTo(avatar.owner);
+ packet.addChild("vCard", "vcard-temp");
+ return packet;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarVcardParser.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarVcardParser.java
new file mode 100644
index 00000000..32ad6f26
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarVcardParser.java
@@ -0,0 +1,29 @@
+package de.thedevstack.conversationsplus.xmpp.avatar;
+
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
+import de.thedevstack.conversationsplus.xmpp.stanzas.PresencePacket;
+
+/**
+ */
+public final class AvatarVcardParser {
+ private AvatarVcardParser() {}
+
+ public static Avatar parseVcardPresenceInformation(PresencePacket packet) {
+ return AvatarVcardParser.parsePresence(packet.findChild("x", "vcard-temp:x:update"));
+ }
+
+ public static Avatar parsePresence(Element x) {
+ String hash = (x == null) ? null : x.findChildContent("photo");
+ if (hash == null) {
+ return null;
+ }
+ if (!Avatar.isValidSHA1(hash)) {
+ return null;
+ }
+ Avatar avatar = new Avatar();
+ avatar.sha1sum = hash;
+ avatar.origin = Avatar.Origin.VCARD;
+ return avatar;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/pep/Avatar.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/pep/Avatar.java
index 9c1c8b9c..acf2a730 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/pep/Avatar.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/pep/Avatar.java
@@ -2,7 +2,6 @@ package de.thedevstack.conversationsplus.xmpp.pep;
import android.util.Base64;
-import de.thedevstack.conversationsplus.xml.Element;
import de.thedevstack.conversationsplus.xmpp.jid.Jid;
public class Avatar {
@@ -26,52 +25,6 @@ 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");
- 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) {
@@ -82,21 +35,7 @@ public class Avatar {
}
}
- public static Avatar parsePresence(Element x) {
- String hash = x == null ? null : x.findChildContent("photo");
- 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) {
+ public static boolean isValidSHA1(String s) {
return s != null && s.matches("[a-fA-F0-9]{40}");
}
}