From 867afe4c5b888ce3f4f9a867906cc8edb86e7aba Mon Sep 17 00:00:00 2001 From: steckbrief Date: Sun, 6 Aug 2017 01:15:13 +0200 Subject: avatar handling refactored --- .../services/avatar/AvatarService.java | 210 +++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarService.java (limited to 'src/main/java/de/thedevstack/conversationsplus/services/avatar/AvatarService.java') 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 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 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 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 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 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 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 callback) { + IqPacket packet = AvatarVcardPacketGenerator.generateRetreivePacket(avatar); + XmppSendUtil.sendIqPacket(account, packet, new AvatarVcardReceived(avatar, callback)); + } + + public void checkForAvatar(Account account, final UiCallback 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 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; + } +} -- cgit v1.2.3