From cdbe2c1c719c37e00fa78c5c35864003a66e81fc Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Wed, 27 Aug 2025 11:11:13 -0400 Subject: [PATCH] Revert "Disable all fixes for large image loading." This reverts commit a16ac3394c9438af0203bb8db01a1e1832f1c3ca. --- .../DecryptableStreamLocalUriFetcher.java | 86 ------------------- .../glide/DecryptableStreamUriLoader.java | 55 ------------ .../glide/SignalGlideComponents.java | 29 ++++--- 3 files changed, 19 insertions(+), 151 deletions(-) delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/glide/DecryptableStreamLocalUriFetcher.java delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/glide/DecryptableStreamUriLoader.java diff --git a/app/src/main/java/org/thoughtcrime/securesms/glide/DecryptableStreamLocalUriFetcher.java b/app/src/main/java/org/thoughtcrime/securesms/glide/DecryptableStreamLocalUriFetcher.java deleted file mode 100644 index 75094f7e1d..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/glide/DecryptableStreamLocalUriFetcher.java +++ /dev/null @@ -1,86 +0,0 @@ -package org.thoughtcrime.securesms.glide; - -import android.content.ContentResolver; -import android.content.Context; -import android.graphics.Bitmap; -import android.net.Uri; -import android.util.Pair; - -import com.bumptech.glide.load.data.StreamLocalUriFetcher; - -import org.signal.core.util.logging.Log; -import org.thoughtcrime.securesms.attachments.AttachmentId; -import org.thoughtcrime.securesms.mms.PartAuthority; -import org.thoughtcrime.securesms.providers.BlobProvider; -import org.thoughtcrime.securesms.util.BitmapDecodingException; -import org.thoughtcrime.securesms.util.BitmapUtil; -import org.thoughtcrime.securesms.util.MediaUtil; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; - -class DecryptableStreamLocalUriFetcher extends StreamLocalUriFetcher { - - private static final String TAG = Log.tag(DecryptableStreamLocalUriFetcher.class); - - private static final int DIMENSION_LIMIT = 12_000; - - private Context context; - - DecryptableStreamLocalUriFetcher(Context context, Uri uri) { - super(context.getContentResolver(), uri); - this.context = context; - } - - @Override - protected InputStream loadResource(Uri uri, ContentResolver contentResolver) throws FileNotFoundException { - if (MediaUtil.hasVideoThumbnail(context, uri)) { - Bitmap thumbnail = MediaUtil.getVideoThumbnail(context, uri, 1000); - - if (thumbnail != null) { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, baos); - ByteArrayInputStream thumbnailStream = new ByteArrayInputStream(baos.toByteArray()); - thumbnail.recycle(); - return thumbnailStream; - } - if (PartAuthority.isAttachmentUri(uri) && MediaUtil.isVideoType(PartAuthority.getAttachmentContentType(context, uri))) { - try { - AttachmentId attachmentId = PartAuthority.requireAttachmentId(uri); - Uri thumbnailUri = PartAuthority.getAttachmentThumbnailUri(attachmentId); - InputStream thumbStream = PartAuthority.getAttachmentThumbnailStream(context, thumbnailUri); - if (thumbStream != null) { - return thumbStream; - } - } catch (IOException e) { - Log.i(TAG, "Failed to fetch thumbnail", e); - } - } - } - - try { - if (PartAuthority.isBlobUri(uri) && BlobProvider.isSingleUseMemoryBlob(uri)) { - return PartAuthority.getAttachmentThumbnailStream(context, uri); - } else if (isSafeSize(PartAuthority.getAttachmentThumbnailStream(context, uri))) { - return PartAuthority.getAttachmentThumbnailStream(context, uri); - } else { - throw new IOException("File dimensions are too large!"); - } - } catch (IOException ioe) { - Log.w(TAG, ioe); - throw new FileNotFoundException("PartAuthority couldn't load Uri resource."); - } - } - - private boolean isSafeSize(InputStream stream) { - try { - Pair size = BitmapUtil.getDimensions(stream); - return size.first < DIMENSION_LIMIT && size.second < DIMENSION_LIMIT; - } catch (BitmapDecodingException e) { - return false; - } - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/glide/DecryptableStreamUriLoader.java b/app/src/main/java/org/thoughtcrime/securesms/glide/DecryptableStreamUriLoader.java deleted file mode 100644 index f7b4a6d0b6..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/glide/DecryptableStreamUriLoader.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.thoughtcrime.securesms.glide; - -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.bumptech.glide.load.Options; -import com.bumptech.glide.load.model.ModelLoader; -import com.bumptech.glide.load.model.ModelLoaderFactory; -import com.bumptech.glide.load.model.MultiModelLoaderFactory; - -import org.thoughtcrime.securesms.mms.DecryptableUri; - -import java.io.InputStream; - -public class DecryptableStreamUriLoader implements ModelLoader { - - private final Context context; - - private DecryptableStreamUriLoader(Context context) { - this.context = context; - } - - @Nullable - @Override - public LoadData buildLoadData(@NonNull DecryptableUri decryptableUri, int width, int height, @NonNull Options options) { - return new LoadData<>(decryptableUri, new DecryptableStreamLocalUriFetcher(context, decryptableUri.getUri())); - } - - @Override - public boolean handles(@NonNull DecryptableUri decryptableUri) { - return true; - } - - public static class Factory implements ModelLoaderFactory { - - private final Context context; - - public Factory(Context context) { - this.context = context.getApplicationContext(); - } - - @Override - public @NonNull ModelLoader build(@NonNull MultiModelLoaderFactory multiFactory) { - return new DecryptableStreamUriLoader(context); - } - - @Override - public void teardown() { - // Do nothing. - } - } -} - diff --git a/app/src/main/java/org/thoughtcrime/securesms/glide/SignalGlideComponents.java b/app/src/main/java/org/thoughtcrime/securesms/glide/SignalGlideComponents.java index c2d81739d8..e68c0a60d9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/glide/SignalGlideComponents.java +++ b/app/src/main/java/org/thoughtcrime/securesms/glide/SignalGlideComponents.java @@ -12,12 +12,11 @@ import com.bumptech.glide.Registry; import com.bumptech.glide.load.model.GlideUrl; import com.bumptech.glide.load.model.UnitModelLoader; import com.bumptech.glide.load.resource.bitmap.BitmapDrawableEncoder; -import com.bumptech.glide.load.resource.bitmap.Downsampler; -import com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder; import com.bumptech.glide.load.resource.gif.ByteBufferGifDecoder; import com.bumptech.glide.load.resource.gif.GifDrawable; import com.bumptech.glide.load.resource.gif.StreamGifDecoder; +import org.signal.glide.common.io.InputStreamFactory; import org.signal.glide.load.resource.apng.decode.APNGDecoder; import org.thoughtcrime.securesms.badges.load.BadgeLoader; import org.thoughtcrime.securesms.badges.load.GiftBadgeModel; @@ -37,9 +36,14 @@ import org.thoughtcrime.securesms.glide.cache.EncryptedBitmapResourceEncoder; import org.thoughtcrime.securesms.glide.cache.EncryptedCacheDecoder; import org.thoughtcrime.securesms.glide.cache.EncryptedCacheEncoder; import org.thoughtcrime.securesms.glide.cache.EncryptedGifDrawableResourceEncoder; +import org.thoughtcrime.securesms.glide.cache.InputStreamFactoryBitmapDecoder; import org.thoughtcrime.securesms.glide.cache.StreamApngDecoder; +import org.thoughtcrime.securesms.glide.cache.StreamBitmapDecoder; +import org.thoughtcrime.securesms.glide.cache.StreamFactoryApngDecoder; +import org.thoughtcrime.securesms.glide.cache.StreamFactoryGifDecoder; import org.thoughtcrime.securesms.glide.cache.WebpSanDecoder; import org.thoughtcrime.securesms.mms.DecryptableUri; +import org.thoughtcrime.securesms.mms.DecryptableUriStreamLoader; import org.thoughtcrime.securesms.mms.RegisterGlideComponents; import org.thoughtcrime.securesms.mms.SignalGlideModule; import org.thoughtcrime.securesms.stickers.StickerRemoteUri; @@ -68,10 +72,12 @@ public class SignalGlideComponents implements RegisterGlideComponents { registry.prepend(InputStream.class, new EncryptedCacheEncoder(secret, glide.getArrayPool())); - registry.prepend(File.class, Bitmap.class, new EncryptedCacheDecoder<>(secret, new StreamBitmapDecoder(new Downsampler(registry.getImageHeaderParsers(), context.getResources().getDisplayMetrics(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool()))); + registry.prepend(File.class, Bitmap.class, new EncryptedCacheDecoder<>(secret, new StreamBitmapDecoder(context, glide, registry))); - StreamGifDecoder streamGifDecoder = new StreamGifDecoder(registry.getImageHeaderParsers(), new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool()); + StreamGifDecoder streamGifDecoder = new StreamGifDecoder(registry.getImageHeaderParsers(), new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool()); + StreamFactoryGifDecoder streamFactoryGifDecoder = new StreamFactoryGifDecoder(streamGifDecoder); registry.prepend(InputStream.class, GifDrawable.class, streamGifDecoder); + registry.prepend(InputStreamFactory.class, GifDrawable.class, streamFactoryGifDecoder); registry.prepend(GifDrawable.class, new EncryptedGifDrawableResourceEncoder(secret)); registry.prepend(File.class, GifDrawable.class, new EncryptedCacheDecoder<>(secret, streamGifDecoder)); @@ -79,13 +85,15 @@ public class SignalGlideComponents implements RegisterGlideComponents { registry.prepend(Bitmap.class, new EncryptedBitmapResourceEncoder(secret)); registry.prepend(BitmapDrawable.class, new BitmapDrawableEncoder(glide.getBitmapPool(), encryptedBitmapResourceEncoder)); - ByteBufferApngDecoder apngBufferCacheDecoder = new ByteBufferApngDecoder(); - StreamApngDecoder apngStreamCacheDecoder = new StreamApngDecoder(apngBufferCacheDecoder); + ByteBufferApngDecoder byteBufferApngDecoder = new ByteBufferApngDecoder(); + StreamApngDecoder streamApngDecoder = new StreamApngDecoder(byteBufferApngDecoder); + StreamFactoryApngDecoder streamFactoryApngDecoder = new StreamFactoryApngDecoder(byteBufferApngDecoder, glide, registry); - registry.prepend(InputStream.class, APNGDecoder.class, apngStreamCacheDecoder); - registry.prepend(ByteBuffer.class, APNGDecoder.class, apngBufferCacheDecoder); + registry.prepend(InputStream.class, APNGDecoder.class, streamApngDecoder); + registry.prepend(InputStreamFactory.class, APNGDecoder.class, streamFactoryApngDecoder); + registry.prepend(ByteBuffer.class, APNGDecoder.class, byteBufferApngDecoder); registry.prepend(APNGDecoder.class, new EncryptedApngCacheEncoder(secret)); - registry.prepend(File.class, APNGDecoder.class, new EncryptedCacheDecoder<>(secret, apngStreamCacheDecoder)); + registry.prepend(File.class, APNGDecoder.class, new EncryptedCacheDecoder<>(secret, streamApngDecoder)); registry.register(APNGDecoder.class, Drawable.class, new ApngFrameDrawableTranscoder()); registry.prepend(BlurHash.class, Bitmap.class, new BlurHashResourceDecoder()); @@ -94,7 +102,8 @@ public class SignalGlideComponents implements RegisterGlideComponents { registry.append(StoryTextPostModel.class, StoryTextPostModel.class, UnitModelLoader.Factory.getInstance()); registry.append(ConversationShortcutPhoto.class, Bitmap.class, new ConversationShortcutPhoto.Loader.Factory(context)); registry.append(ContactPhoto.class, InputStream.class, new ContactPhotoLoader.Factory(context)); - registry.append(DecryptableUri.class, InputStream.class, new DecryptableStreamUriLoader.Factory(context)); + registry.append(DecryptableUri.class, InputStreamFactory.class, new DecryptableUriStreamLoader.Factory(context)); + registry.append(InputStreamFactory.class, Bitmap.class, new InputStreamFactoryBitmapDecoder(context, glide, registry)); registry.append(ChunkedImageUrl.class, InputStream.class, new ChunkedImageUrlLoader.Factory()); registry.append(StickerRemoteUri.class, InputStream.class, new StickerRemoteUriLoader.Factory()); registry.append(BlurHash.class, BlurHash.class, new BlurHashModelLoader.Factory());