route MUC avatar upload through AvatarManager

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java   | 101 
src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java |   2 
src/main/java/eu/siacs/conversations/xmpp/manager/AvatarManager.java       |  26 
src/main/java/im/conversations/android/xmpp/processor/BindProcessor.java   |   3 
4 files changed, 42 insertions(+), 90 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/services/XmppConnectionService.java 🔗

@@ -57,7 +57,6 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Maps;
-import com.google.common.io.BaseEncoding;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
@@ -4298,42 +4297,32 @@ public class XmppConnectionService extends Service {
         connection.getManager(RosterManager.class).deleteRosterItem(contact);
     }
 
-    // TODO get thumbnail via AvatarManager
-    // TODO call AvatarManager.getInbandAvatar form vcard manager and simplify publication process
     public void publishMucAvatar(
             final Conversation conversation, final Uri image, final OnAvatarPublication callback) {
-        new Thread(
-                        () -> {
-                            final Bitmap.CompressFormat format = Config.AVATAR_FORMAT;
-                            final int size = Config.AVATAR_SIZE;
-                            final Avatar avatar =
-                                    getFileBackend().getPepAvatar(image, size, format);
-                            if (avatar != null) {
-                                if (!getFileBackend().save(avatar)) {
-                                    callback.onAvatarPublicationFailed(
-                                            R.string.error_saving_avatar);
-                                    return;
-                                }
-                                avatar.owner = conversation.getJid().asBareJid();
-                                publishMucAvatar(conversation, avatar, callback);
-                            } else {
-                                callback.onAvatarPublicationFailed(
-                                        R.string.error_publish_avatar_converting);
-                            }
-                        })
-                .start();
-    }
+        final var connection = conversation.getAccount().getXmppConnection();
+        final var future =
+                connection
+                        .getManager(AvatarManager.class)
+                        .publishVCard(conversation.getJid().asBareJid(), image);
+        Futures.addCallback(
+                future,
+                new FutureCallback<>() {
+                    @Override
+                    public void onSuccess(Void result) {
+                        callback.onAvatarPublicationSucceeded();
+                    }
 
-    // TODO get rid of the async part. Manager is already async
-    public void publishAvatarAsync(
-            final Account account,
-            final Uri image,
-            final boolean open,
-            final OnAvatarPublication callback) {
-        new Thread(() -> publishAvatar(account, image, open, callback)).start();
+                    @Override
+                    public void onFailure(@NonNull Throwable t) {
+                        Log.d(Config.LOGTAG, "could not publish MUC avatar", t);
+                        callback.onAvatarPublicationFailed(
+                                R.string.error_publish_avatar_server_reject);
+                    }
+                },
+                MoreExecutors.directExecutor());
     }
 
-    private void publishAvatar(
+    public void publishAvatar(
             final Account account,
             final Uri image,
             final boolean open,
@@ -4363,54 +4352,6 @@ public class XmppConnectionService extends Service {
                 MoreExecutors.directExecutor());
     }
 
-    private void publishMucAvatar(
-            final Conversation conversation,
-            final Avatar avatar,
-            final OnAvatarPublication callback) {
-        final var account = conversation.getAccount();
-        final var connection = account.getXmppConnection();
-        final var future =
-                connection
-                        .getManager(VCardManager.class)
-                        .publishPhoto(
-                                avatar.owner,
-                                avatar.type,
-                                BaseEncoding.base64().decode(avatar.image));
-        Futures.addCallback(
-                future,
-                new FutureCallback<>() {
-                    @Override
-                    public void onSuccess(Void result) {
-                        Log.d(Config.LOGTAG, "published muc avatar");
-                        final var c = account.getRoster().getContact(avatar.owner);
-                        c.setAvatar(avatar.sha1sum);
-                        getAvatarService().clear(c);
-                        getAvatarService().clear(conversation.getMucOptions());
-                        callback.onAvatarPublicationSucceeded();
-                    }
-
-                    @Override
-                    public void onFailure(@NonNull Throwable t) {
-                        Log.d(Config.LOGTAG, "could not publish muc avatar", t);
-                        callback.onAvatarPublicationFailed(
-                                R.string.error_publish_avatar_server_reject);
-                    }
-                },
-                MoreExecutors.directExecutor());
-    }
-
-    public void cancelAvatarFetches(final Account account) {
-        synchronized (mInProgressAvatarFetches) {
-            for (final Iterator<String> iterator = mInProgressAvatarFetches.iterator();
-                    iterator.hasNext(); ) {
-                final String KEY = iterator.next();
-                if (KEY.startsWith(account.getJid().asBareJid() + "_")) {
-                    iterator.remove();
-                }
-            }
-        }
-    }
-
     public ListenableFuture<Void> checkForAvatar(final Account account) {
         final var connection = account.getXmppConnection();
         return connection

src/main/java/eu/siacs/conversations/ui/PublishProfilePictureActivity.java 🔗

@@ -112,7 +112,7 @@ public class PublishProfilePictureActivity extends XmppActivity
                     }
                     publishing = true;
                     togglePublishButton(false, R.string.publishing);
-                    xmppConnectionService.publishAvatarAsync(account, uri, open, this);
+                    xmppConnectionService.publishAvatar(account, uri, open, this);
                 });
         this.binding.cancelButton.setOnClickListener(
                 v -> {

src/main/java/eu/siacs/conversations/xmpp/manager/AvatarManager.java 🔗

@@ -421,6 +421,7 @@ public class AvatarManager extends AbstractManager {
             final Uri image, final int size, final ImageFormat format, final Integer charLimit)
             throws Exception {
         final var centerSquare = FileBackend.cropCenterSquare(context, image, size);
+        // TODO do an alpha check. if alpha and format JPEG half size and use PNG
         if (charLimit == null || format == ImageFormat.PNG) {
             return resizeAndStoreAvatar(centerSquare, format, 90);
         } else {
@@ -525,7 +526,7 @@ public class AvatarManager extends AbstractManager {
                 String.format("Could not move file to %s", avatarFile.getAbsolutePath()));
     }
 
-    public ListenableFuture<List<Info>> uploadAvatar(final Uri image, final int size) {
+    private ListenableFuture<List<Info>> uploadAvatar(final Uri image, final int size) {
         final var avatarFutures = new ImmutableList.Builder<ListenableFuture<Info>>();
         final var avatarFuture = resizeAndStoreAvatarAsync(image, size, ImageFormat.JPEG);
         final var avatarWithUrlFuture =
@@ -580,7 +581,7 @@ public class AvatarManager extends AbstractManager {
                 AVATAR_COMPRESSION_EXECUTOR);
     }
 
-    public ListenableFuture<Void> publish(final Collection<Info> avatars, final boolean open) {
+    private ListenableFuture<Void> publish(final Collection<Info> avatars, final boolean open) {
         final Info mainAvatarInfo;
         final byte[] mainAvatar;
         try {
@@ -609,11 +610,24 @@ public class AvatarManager extends AbstractManager {
                 MoreExecutors.directExecutor());
     }
 
+    public ListenableFuture<Void> publishVCard(final Jid address, final Uri image) {
+        final var avatarThumbnailFuture =
+                resizeAndStoreAvatarAsync(
+                        image, Config.AVATAR_SIZE, ImageFormat.JPEG, Config.AVATAR_CHAR_LIMIT);
+        return Futures.transformAsync(
+                avatarThumbnailFuture,
+                info -> {
+                    final var avatar =
+                            Files.asByteSource(FileBackend.getAvatarFile(context, info.getId()))
+                                    .read();
+                    return getManager(VCardManager.class)
+                            .publishPhoto(address, info.getType(), avatar);
+                },
+                AVATAR_COMPRESSION_EXECUTOR);
+    }
+
     public ListenableFuture<Void> uploadAndPublish(final Uri image, final boolean open) {
-        final var infoFuture =
-                connection
-                        .getManager(AvatarManager.class)
-                        .uploadAvatar(image, Config.AVATAR_FULL_SIZE);
+        final var infoFuture = uploadAvatar(image, Config.AVATAR_FULL_SIZE);
         return Futures.transformAsync(
                 infoFuture, avatars -> publish(avatars, open), MoreExecutors.directExecutor());
     }

src/main/java/im/conversations/android/xmpp/processor/BindProcessor.java 🔗

@@ -26,10 +26,8 @@ public class BindProcessor extends XmppConnection.Delegate implements Runnable {
 
     @Override
     public void run() {
-        Log.d(Config.LOGTAG, "begin onBind()");
         final var account = connection.getAccount();
         final var features = connection.getFeatures();
-        service.cancelAvatarFetches(account);
         final boolean loggedInSuccessfully =
                 account.setOption(Account.OPTION_LOGGED_IN_SUCCESSFULLY, true);
         final boolean sosModified;
@@ -112,6 +110,5 @@ public class BindProcessor extends XmppConnection.Delegate implements Runnable {
         connection.getManager(RosterManager.class).syncDirtyContacts();
 
         service.getUnifiedPushBroker().renewUnifiedPushEndpointsOnBind(account);
-        Log.d(Config.LOGTAG, "end onBind()");
     }
 }