That fuck shit the fascists are using
at master 252 lines 9.9 kB view raw
1package org.tm.archive.util; 2 3import android.content.Context; 4import android.graphics.Bitmap; 5import android.graphics.drawable.Drawable; 6import android.os.Build; 7import android.view.View; 8import android.widget.ImageView; 9 10import androidx.annotation.NonNull; 11import androidx.annotation.Nullable; 12import androidx.annotation.WorkerThread; 13import androidx.appcompat.widget.AppCompatImageView; 14import androidx.core.content.ContextCompat; 15import androidx.core.graphics.drawable.IconCompat; 16 17import com.bumptech.glide.Glide; 18import com.bumptech.glide.RequestBuilder; 19import com.bumptech.glide.RequestManager; 20import com.bumptech.glide.load.engine.DiskCacheStrategy; 21import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; 22import com.bumptech.glide.load.resource.bitmap.CenterCrop; 23import com.bumptech.glide.load.resource.bitmap.CircleCrop; 24import com.bumptech.glide.request.target.CustomTarget; 25import com.bumptech.glide.request.target.CustomViewTarget; 26import com.bumptech.glide.request.transition.Transition; 27 28import org.signal.core.util.ThreadUtil; 29import org.signal.core.util.logging.Log; 30import org.tm.archive.R; 31import org.tm.archive.contacts.avatars.ContactPhoto; 32import org.tm.archive.contacts.avatars.GeneratedContactPhoto; 33import org.tm.archive.contacts.avatars.ProfileContactPhoto; 34import org.tm.archive.providers.AvatarProvider; 35import org.tm.archive.recipients.Recipient; 36 37import java.util.Objects; 38import java.util.Optional; 39import java.util.concurrent.CountDownLatch; 40import java.util.concurrent.ExecutionException; 41import java.util.concurrent.TimeUnit; 42import java.util.concurrent.atomic.AtomicReference; 43 44public final class AvatarUtil { 45 46 private static final String TAG = Log.tag(AvatarUtil.class); 47 48 public static final int UNDEFINED_SIZE = -1; 49 50 private AvatarUtil() { 51 } 52 53 public static void loadBlurredIconIntoImageView(@NonNull Recipient recipient, @NonNull AppCompatImageView target) { 54 Context context = target.getContext(); 55 56 ContactPhoto photo; 57 58 if (recipient.isSelf()) { 59 photo = new ProfileContactPhoto(Recipient.self()); 60 } else if (recipient.getContactPhoto() == null) { 61 target.setImageDrawable(null); 62 target.setBackgroundColor(ContextCompat.getColor(target.getContext(), R.color.black)); 63 return; 64 } else { 65 photo = recipient.getContactPhoto(); 66 } 67 68 Glide.with(target) 69 .load(photo) 70 .transform(new BlurTransformation(context, 0.25f, BlurTransformation.MAX_RADIUS), new CenterCrop()) 71 .into(new CustomViewTarget<View, Drawable>(target) { 72 @Override 73 public void onLoadFailed(@Nullable Drawable errorDrawable) { 74 target.setImageDrawable(null); 75 target.setBackgroundColor(ContextCompat.getColor(target.getContext(), R.color.black)); 76 } 77 78 @Override 79 public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) { 80 target.setImageDrawable(resource); 81 } 82 83 @Override 84 protected void onResourceCleared(@Nullable Drawable placeholder) { 85 target.setImageDrawable(placeholder); 86 } 87 }); 88 } 89 90 public static void loadIconIntoImageView(@NonNull Recipient recipient, @NonNull ImageView target) { 91 loadIconIntoImageView(recipient, target, -1); 92 } 93 94 public static void loadIconIntoImageView(@NonNull Recipient recipient, @NonNull ImageView target, int requestedSize) { 95 Context context = target.getContext(); 96 97 requestCircle(Glide.with(context).asDrawable(), context, recipient, requestedSize).into(target); 98 } 99 100 public static Bitmap loadIconBitmapSquareNoCache(@NonNull Context context, 101 @NonNull Recipient recipient, 102 int width, 103 int height) 104 throws ExecutionException, InterruptedException 105 { 106 return requestSquare(Glide.with(context).asBitmap(), context, recipient) 107 .skipMemoryCache(true) 108 .diskCacheStrategy(DiskCacheStrategy.NONE) 109 .submit(width, height) 110 .get(); 111 } 112 113 @WorkerThread 114 public static @NonNull IconCompat getIconCompat(@NonNull Context context, @NonNull Recipient recipient) { 115 if (Build.VERSION.SDK_INT > 29) { 116 return IconCompat.createWithContentUri(AvatarProvider.getContentUri(recipient.getId())); 117 } else { 118 return IconCompat.createWithBitmap(getBitmapForNotification(context, recipient, DrawableUtil.SHORTCUT_INFO_WRAPPED_SIZE)); 119 } 120 } 121 122 @WorkerThread 123 public static Bitmap getBitmapForNotification(@NonNull Context context, @NonNull Recipient recipient) { 124 return getBitmapForNotification(context, recipient, UNDEFINED_SIZE); 125 } 126 127 @WorkerThread 128 public static @NonNull Bitmap getBitmapForNotification(@NonNull Context context, @NonNull Recipient recipient, int size) { 129 ThreadUtil.assertNotMainThread(); 130 131 try { 132 AvatarTarget avatarTarget = new AvatarTarget(size); 133 RequestManager requestManager = Glide.with(context); 134 135 requestCircle(requestManager.asBitmap(), context, recipient, size).into(avatarTarget); 136 137 Bitmap bitmap = avatarTarget.await(); 138 return Objects.requireNonNullElseGet(bitmap, () -> DrawableUtil.toBitmap(getFallback(context, recipient, size), size, size)); 139 } catch (InterruptedException e) { 140 return DrawableUtil.toBitmap(getFallback(context, recipient, size), size, size); 141 } 142 } 143 144 private static <T> RequestBuilder<T> requestCircle(@NonNull RequestBuilder<T> requestBuilder, @NonNull Context context, @NonNull Recipient recipient, int targetSize) { 145 return request(requestBuilder, context, recipient, targetSize, new CircleCrop()); 146 } 147 148 private static <T> RequestBuilder<T> requestSquare(@NonNull RequestBuilder<T> requestBuilder, @NonNull Context context, @NonNull Recipient recipient) { 149 return request(requestBuilder, context, recipient, UNDEFINED_SIZE, new CenterCrop()); 150 } 151 152 private static <T> RequestBuilder<T> request(@NonNull RequestBuilder<T> requestBuilder, @NonNull Context context, @NonNull Recipient recipient, int targetSize, @Nullable BitmapTransformation transformation) { 153 return request(requestBuilder, context, recipient, true, targetSize, transformation); 154 } 155 156 private static <T> RequestBuilder<T> request(@NonNull RequestBuilder<T> requestBuilder, @NonNull Context context, @NonNull Recipient recipient, boolean loadSelf, int targetSize, @Nullable BitmapTransformation transformation) { 157 158 final ContactPhoto photo; 159 if (Recipient.self().equals(recipient) && loadSelf) { 160 photo = new ProfileContactPhoto(recipient); 161 } else { 162 photo = recipient.getContactPhoto(); 163 } 164 165 final int size = targetSize == -1 ? DrawableUtil.SHORTCUT_INFO_WRAPPED_SIZE : targetSize; 166 final RequestBuilder<T> request = requestBuilder.load(photo) 167 .error(getFallback(context, recipient, size)) 168 .diskCacheStrategy(DiskCacheStrategy.ALL) 169 .override(size); 170 171 if (recipient.shouldBlurAvatar()) { 172 BlurTransformation blur = new BlurTransformation(context, 0.25f, BlurTransformation.MAX_RADIUS); 173 if (transformation != null) { 174 return request.transform(blur, transformation); 175 } else { 176 return request.transform(blur); 177 } 178 } else if (transformation != null) { 179 return request.transform(transformation); 180 } else { 181 return request; 182 } 183 } 184 185 private static Drawable getFallback(@NonNull Context context, @NonNull Recipient recipient, int targetSize) { 186 String name = Optional.of(recipient.getDisplayName(context)).orElse(""); 187 188 return new GeneratedContactPhoto(name, R.drawable.ic_profile_outline_40, targetSize).asDrawable(context, recipient.getAvatarColor()); 189 } 190 191 /** 192 * Allows caller to synchronously await for a bitmap of an avatar. 193 */ 194 private static class AvatarTarget extends CustomTarget<Bitmap> { 195 196 private final CountDownLatch countDownLatch = new CountDownLatch(1); 197 private final AtomicReference<Bitmap> bitmap = new AtomicReference<>(); 198 199 private final int size; 200 201 private AvatarTarget(int size) { 202 this.size = size == UNDEFINED_SIZE ? DrawableUtil.SHORTCUT_INFO_WRAPPED_SIZE : size; 203 } 204 205 public @Nullable Bitmap await() throws InterruptedException { 206 if (countDownLatch.await(1, TimeUnit.SECONDS)) { 207 return bitmap.get(); 208 } else { 209 Log.w(TAG, "AvatarTarget#await: Failed to load avatar in time! Returning null"); 210 return null; 211 } 212 } 213 214 @Override 215 public void onDestroy() { 216 Log.d(TAG, "AvatarTarget: onDestroy"); 217 super.onDestroy(); 218 } 219 220 @Override 221 public void onLoadStarted(@Nullable Drawable placeholder) { 222 Log.d(TAG, "AvatarTarget: onLoadStarted"); 223 super.onLoadStarted(placeholder); 224 } 225 226 @Override 227 public void onResourceReady(@NonNull Bitmap resource, @Nullable Transition<? super Bitmap> transition) { 228 Log.d(TAG, "AvatarTarget: onResourceReady"); 229 bitmap.set(resource); 230 countDownLatch.countDown(); 231 } 232 233 @Override 234 public void onLoadFailed(@Nullable Drawable errorDrawable) { 235 Log.d(TAG, "AvatarTarget: onLoadFailed"); 236 if (errorDrawable == null) { 237 throw new AssertionError("Expected an error drawable."); 238 } 239 240 Bitmap errorBitmap = DrawableUtil.toBitmap(errorDrawable, size, size); 241 bitmap.set(errorBitmap); 242 countDownLatch.countDown(); 243 } 244 245 @Override 246 public void onLoadCleared(@Nullable Drawable placeholder) { 247 Log.d(TAG, "AvatarTarget: onLoadCleared"); 248 bitmap.set(null); 249 countDownLatch.countDown(); 250 } 251 } 252}