AvatarWorkerTask.java

  1package eu.siacs.conversations.ui.util;
  2
  3import android.content.Context;
  4import android.content.res.Resources;
  5import android.graphics.Bitmap;
  6import android.graphics.drawable.AnimatedImageDrawable;
  7import android.graphics.drawable.BitmapDrawable;
  8import android.graphics.drawable.Drawable;
  9import android.os.AsyncTask;
 10import android.os.Build;
 11import android.widget.ImageView;
 12
 13import androidx.annotation.DimenRes;
 14
 15import java.lang.ref.WeakReference;
 16import java.util.concurrent.RejectedExecutionException;
 17
 18import eu.siacs.conversations.R;
 19import eu.siacs.conversations.entities.Account;
 20import eu.siacs.conversations.services.AvatarService;
 21import eu.siacs.conversations.ui.XmppActivity;
 22
 23public class AvatarWorkerTask extends AsyncTask<AvatarService.Avatarable, Void, Drawable> {
 24    private final WeakReference<ImageView> imageViewReference;
 25    private final WeakReference<XmppActivity> activityReference;
 26    private AvatarService.Avatarable avatarable = null;
 27    private @DimenRes
 28    final int size;
 29
 30    public AvatarWorkerTask(ImageView imageView, @DimenRes int size) {
 31        imageViewReference = new WeakReference<>(imageView);
 32        activityReference = null;
 33        this.size = size;
 34    }
 35
 36
 37    public AvatarWorkerTask(XmppActivity activity, @DimenRes int size) {
 38        activityReference = new WeakReference<>(activity);
 39        imageViewReference = new WeakReference<>(null);
 40        this.size = size;
 41    }
 42
 43    @Override
 44    protected Drawable doInBackground(AvatarService.Avatarable... params) {
 45        this.avatarable = params[0];
 46        final XmppActivity activity = activityReference == null ? XmppActivity.find(imageViewReference) : activityReference.get();
 47        if (activity == null) {
 48            return null;
 49        }
 50        return activity.avatarService().get(avatarable, (int) activity.getResources().getDimension(size), isCancelled());
 51    }
 52
 53    @Override
 54    protected void onPostExecute(Drawable bitmap) {
 55        if (bitmap != null && !isCancelled()) {
 56            final ImageView imageView = imageViewReference.get();
 57            if (imageView != null) {
 58                imageView.setImageDrawable(bitmap);
 59                imageView.setBackgroundColor(0x00000000);
 60            }
 61            if (Build.VERSION.SDK_INT >= 28 && bitmap instanceof AnimatedImageDrawable) {
 62                ((AnimatedImageDrawable) bitmap).start();
 63            }
 64            if (activityReference != null) {
 65                final var activity = activityReference.get();
 66                if (activity != null) {
 67                    activity.refreshUi();
 68                }
 69            }
 70        }
 71    }
 72
 73    public static boolean cancelPotentialWork(AvatarService.Avatarable avatarable, ImageView imageView) {
 74        final AvatarWorkerTask workerTask = getBitmapWorkerTask(imageView);
 75
 76        if (workerTask != null) {
 77            final AvatarService.Avatarable old= workerTask.avatarable;
 78            if (old == null || avatarable != old) {
 79                workerTask.cancel(true);
 80            } else {
 81                return false;
 82            }
 83        }
 84        return true;
 85    }
 86
 87    public static AvatarWorkerTask getBitmapWorkerTask(ImageView imageView) {
 88        if (imageView != null) {
 89            final Drawable drawable = imageView.getDrawable();
 90            if (drawable instanceof AsyncDrawable) {
 91                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
 92                return asyncDrawable.getAvatarWorkerTask();
 93            }
 94        }
 95        return null;
 96    }
 97
 98    public static void loadAvatar(final AvatarService.Avatarable avatarable, final ImageView imageView, final @DimenRes int size) {
 99        if (cancelPotentialWork(avatarable, imageView)) {
100            final XmppActivity activity = XmppActivity.find(imageView);
101            if (activity == null) {
102                return;
103            }
104            final Drawable bm = activity.avatarService().get(avatarable, (int) activity.getResources().getDimension(size), true);
105            setContentDescription(avatarable, imageView);
106            if (bm != null) {
107                cancelPotentialWork(avatarable, imageView);
108                imageView.setImageDrawable(bm);
109                imageView.setBackgroundColor(0x00000000);
110                if (Build.VERSION.SDK_INT >= 28 && bm instanceof AnimatedImageDrawable) {
111                    ((AnimatedImageDrawable) bm).start();
112                }
113            } else {
114                imageView.setBackgroundColor(avatarable.getAvatarBackgroundColor());
115                imageView.setImageDrawable(null);
116                final AvatarWorkerTask task = new AvatarWorkerTask(imageView, size);
117                final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task);
118                imageView.setImageDrawable(asyncDrawable);
119                try {
120                    task.execute(avatarable);
121                } catch (final RejectedExecutionException ignored) {
122                }
123            }
124        }
125    }
126
127    private static void setContentDescription(final AvatarService.Avatarable avatarable, final ImageView imageView) {
128        final Context context = imageView.getContext();
129        if (avatarable instanceof Account) {
130            imageView.setContentDescription(context.getString(R.string.your_avatar));
131        } else {
132            imageView.setContentDescription(context.getString(R.string.avatar_for_x, avatarable.getAvatarName()));
133        }
134    }
135
136    static class AsyncDrawable extends BitmapDrawable {
137        private final WeakReference<AvatarWorkerTask> avatarWorkerTaskReference;
138
139        AsyncDrawable(Resources res, Bitmap bitmap, AvatarWorkerTask workerTask) {
140            super(res, bitmap);
141            avatarWorkerTaskReference = new WeakReference<>(workerTask);
142        }
143
144        AvatarWorkerTask getAvatarWorkerTask() {
145            return avatarWorkerTaskReference.get();
146        }
147    }
148}