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}