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 AvatarService.Avatarable avatarable = null;
 26    private @DimenRes
 27    final int size;
 28
 29    public AvatarWorkerTask(ImageView imageView, @DimenRes int size) {
 30        imageViewReference = new WeakReference<>(imageView);
 31        this.size = size;
 32    }
 33
 34    @Override
 35    protected Drawable doInBackground(AvatarService.Avatarable... params) {
 36        this.avatarable = params[0];
 37        final XmppActivity activity = XmppActivity.find(imageViewReference);
 38        if (activity == null) {
 39            return null;
 40        }
 41        return activity.avatarService().get(avatarable, (int) activity.getResources().getDimension(size), isCancelled());
 42    }
 43
 44    @Override
 45    protected void onPostExecute(Drawable bitmap) {
 46        if (bitmap != null && !isCancelled()) {
 47            final ImageView imageView = imageViewReference.get();
 48            if (imageView != null) {
 49                imageView.setImageDrawable(bitmap);
 50                imageView.setBackgroundColor(0x00000000);
 51                if (Build.VERSION.SDK_INT >= 28 && bitmap instanceof AnimatedImageDrawable) {
 52                    ((AnimatedImageDrawable) bitmap).start();
 53                }
 54            }
 55        }
 56    }
 57
 58    public static boolean cancelPotentialWork(AvatarService.Avatarable avatarable, ImageView imageView) {
 59        final AvatarWorkerTask workerTask = getBitmapWorkerTask(imageView);
 60
 61        if (workerTask != null) {
 62            final AvatarService.Avatarable old= workerTask.avatarable;
 63            if (old == null || avatarable != old) {
 64                workerTask.cancel(true);
 65            } else {
 66                return false;
 67            }
 68        }
 69        return true;
 70    }
 71
 72    public static AvatarWorkerTask getBitmapWorkerTask(ImageView imageView) {
 73        if (imageView != null) {
 74            final Drawable drawable = imageView.getDrawable();
 75            if (drawable instanceof AsyncDrawable) {
 76                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;
 77                return asyncDrawable.getAvatarWorkerTask();
 78            }
 79        }
 80        return null;
 81    }
 82
 83    public static void loadAvatar(final AvatarService.Avatarable avatarable, final ImageView imageView, final @DimenRes int size) {
 84        if (cancelPotentialWork(avatarable, imageView)) {
 85            final XmppActivity activity = XmppActivity.find(imageView);
 86            if (activity == null) {
 87                return;
 88            }
 89            final Drawable bm = activity.avatarService().get(avatarable, (int) activity.getResources().getDimension(size), true);
 90            setContentDescription(avatarable, imageView);
 91            if (bm != null) {
 92                cancelPotentialWork(avatarable, imageView);
 93                imageView.setImageDrawable(bm);
 94                imageView.setBackgroundColor(0x00000000);
 95                if (Build.VERSION.SDK_INT >= 28 && bm instanceof AnimatedImageDrawable) {
 96                    ((AnimatedImageDrawable) bm).start();
 97                }
 98            } else {
 99                imageView.setBackgroundColor(avatarable.getAvatarBackgroundColor());
100                imageView.setImageDrawable(null);
101                final AvatarWorkerTask task = new AvatarWorkerTask(imageView, size);
102                final AsyncDrawable asyncDrawable = new AsyncDrawable(activity.getResources(), null, task);
103                imageView.setImageDrawable(asyncDrawable);
104                try {
105                    task.execute(avatarable);
106                } catch (final RejectedExecutionException ignored) {
107                }
108            }
109        }
110    }
111
112    private static void setContentDescription(final AvatarService.Avatarable avatarable, final ImageView imageView) {
113        final Context context = imageView.getContext();
114        if (avatarable instanceof Account) {
115            imageView.setContentDescription(context.getString(R.string.your_avatar));
116        } else {
117            imageView.setContentDescription(context.getString(R.string.avatar_for_x, avatarable.getAvatarName()));
118        }
119    }
120
121    static class AsyncDrawable extends BitmapDrawable {
122        private final WeakReference<AvatarWorkerTask> avatarWorkerTaskReference;
123
124        AsyncDrawable(Resources res, Bitmap bitmap, AvatarWorkerTask workerTask) {
125            super(res, bitmap);
126            avatarWorkerTaskReference = new WeakReference<>(workerTask);
127        }
128
129        AvatarWorkerTask getAvatarWorkerTask() {
130            return avatarWorkerTaskReference.get();
131        }
132    }
133}