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}