Skip to content

Commit 6257f29

Browse files
committed
Merge branch 'molly-7.53'
2 parents 6bf355c + c13a53f commit 6257f29

File tree

4 files changed

+155
-19
lines changed

4 files changed

+155
-19
lines changed

app/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ plugins {
99
}
1010

1111
val canonicalVersionCode = 1576
12-
val canonicalVersionName = "7.53.4"
13-
val currentHotfixVersion = 0
12+
val canonicalVersionName = "7.53.5"
13+
val currentHotfixVersion = 1
1414
val maxHotfixVersions = 100
15-
val mollyRevision = 2
15+
val mollyRevision = 1
1616

1717
// MOLLY: Use default debug keystore generated by Android Studio at $HOME/.android/debug.keystore
1818

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package org.thoughtcrime.securesms.glide;
2+
3+
import android.content.ContentResolver;
4+
import android.content.Context;
5+
import android.graphics.Bitmap;
6+
import android.net.Uri;
7+
import android.util.Pair;
8+
9+
import com.bumptech.glide.load.data.StreamLocalUriFetcher;
10+
11+
import org.signal.core.util.logging.Log;
12+
import org.thoughtcrime.securesms.attachments.AttachmentId;
13+
import org.thoughtcrime.securesms.mms.PartAuthority;
14+
import org.thoughtcrime.securesms.providers.BlobProvider;
15+
import org.thoughtcrime.securesms.util.BitmapDecodingException;
16+
import org.thoughtcrime.securesms.util.BitmapUtil;
17+
import org.thoughtcrime.securesms.util.MediaUtil;
18+
19+
import java.io.ByteArrayInputStream;
20+
import java.io.ByteArrayOutputStream;
21+
import java.io.FileNotFoundException;
22+
import java.io.IOException;
23+
import java.io.InputStream;
24+
25+
class DecryptableStreamLocalUriFetcher extends StreamLocalUriFetcher {
26+
27+
private static final String TAG = Log.tag(DecryptableStreamLocalUriFetcher.class);
28+
29+
private static final int DIMENSION_LIMIT = 12_000;
30+
31+
private Context context;
32+
33+
DecryptableStreamLocalUriFetcher(Context context, Uri uri) {
34+
super(context.getContentResolver(), uri);
35+
this.context = context;
36+
}
37+
38+
@Override
39+
protected InputStream loadResource(Uri uri, ContentResolver contentResolver) throws FileNotFoundException {
40+
if (MediaUtil.hasVideoThumbnail(context, uri)) {
41+
Bitmap thumbnail = MediaUtil.getVideoThumbnail(context, uri, 1000);
42+
43+
if (thumbnail != null) {
44+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
45+
thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, baos);
46+
ByteArrayInputStream thumbnailStream = new ByteArrayInputStream(baos.toByteArray());
47+
thumbnail.recycle();
48+
return thumbnailStream;
49+
}
50+
if (PartAuthority.isAttachmentUri(uri) && MediaUtil.isVideoType(PartAuthority.getAttachmentContentType(context, uri))) {
51+
try {
52+
AttachmentId attachmentId = PartAuthority.requireAttachmentId(uri);
53+
Uri thumbnailUri = PartAuthority.getAttachmentThumbnailUri(attachmentId);
54+
InputStream thumbStream = PartAuthority.getAttachmentThumbnailStream(context, thumbnailUri);
55+
if (thumbStream != null) {
56+
return thumbStream;
57+
}
58+
} catch (IOException e) {
59+
Log.i(TAG, "Failed to fetch thumbnail", e);
60+
}
61+
}
62+
}
63+
64+
try {
65+
if (PartAuthority.isBlobUri(uri) && BlobProvider.isSingleUseMemoryBlob(uri)) {
66+
return PartAuthority.getAttachmentThumbnailStream(context, uri);
67+
} else if (isSafeSize(PartAuthority.getAttachmentThumbnailStream(context, uri))) {
68+
return PartAuthority.getAttachmentThumbnailStream(context, uri);
69+
} else {
70+
throw new IOException("File dimensions are too large!");
71+
}
72+
} catch (IOException ioe) {
73+
Log.w(TAG, ioe);
74+
throw new FileNotFoundException("PartAuthority couldn't load Uri resource.");
75+
}
76+
}
77+
78+
private boolean isSafeSize(InputStream stream) {
79+
try {
80+
Pair<Integer, Integer> size = BitmapUtil.getDimensions(stream);
81+
return size.first < DIMENSION_LIMIT && size.second < DIMENSION_LIMIT;
82+
} catch (BitmapDecodingException e) {
83+
return false;
84+
}
85+
}
86+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package org.thoughtcrime.securesms.glide;
2+
3+
import android.content.Context;
4+
5+
import androidx.annotation.NonNull;
6+
import androidx.annotation.Nullable;
7+
8+
import com.bumptech.glide.load.Options;
9+
import com.bumptech.glide.load.model.ModelLoader;
10+
import com.bumptech.glide.load.model.ModelLoaderFactory;
11+
import com.bumptech.glide.load.model.MultiModelLoaderFactory;
12+
13+
import org.thoughtcrime.securesms.mms.DecryptableUri;
14+
15+
import java.io.InputStream;
16+
17+
public class DecryptableStreamUriLoader implements ModelLoader<DecryptableUri, InputStream> {
18+
19+
private final Context context;
20+
21+
private DecryptableStreamUriLoader(Context context) {
22+
this.context = context;
23+
}
24+
25+
@Nullable
26+
@Override
27+
public LoadData<InputStream> buildLoadData(@NonNull DecryptableUri decryptableUri, int width, int height, @NonNull Options options) {
28+
return new LoadData<>(decryptableUri, new DecryptableStreamLocalUriFetcher(context, decryptableUri.getUri()));
29+
}
30+
31+
@Override
32+
public boolean handles(@NonNull DecryptableUri decryptableUri) {
33+
return true;
34+
}
35+
36+
public static class Factory implements ModelLoaderFactory<DecryptableUri, InputStream> {
37+
38+
private final Context context;
39+
40+
public Factory(Context context) {
41+
this.context = context.getApplicationContext();
42+
}
43+
44+
@Override
45+
public @NonNull ModelLoader<DecryptableUri, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
46+
return new DecryptableStreamUriLoader(context);
47+
}
48+
49+
@Override
50+
public void teardown() {
51+
// Do nothing.
52+
}
53+
}
54+
}
55+

app/src/main/java/org/thoughtcrime/securesms/mms/SignalGlideComponents.java

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import com.bumptech.glide.load.model.GlideUrl;
1818
import com.bumptech.glide.load.model.UnitModelLoader;
1919
import com.bumptech.glide.load.resource.bitmap.BitmapDrawableEncoder;
20+
import com.bumptech.glide.load.resource.bitmap.Downsampler;
21+
import com.bumptech.glide.load.resource.bitmap.StreamBitmapDecoder;
2022
import com.bumptech.glide.load.resource.gif.ByteBufferGifDecoder;
2123
import com.bumptech.glide.load.resource.gif.GifDrawable;
2224
import com.bumptech.glide.load.resource.gif.StreamGifDecoder;
@@ -33,6 +35,7 @@
3335
import org.thoughtcrime.securesms.glide.BadgeLoader;
3436
import org.thoughtcrime.securesms.glide.ChunkedImageUrlLoader;
3537
import org.thoughtcrime.securesms.glide.ContactPhotoLoader;
38+
import org.thoughtcrime.securesms.glide.DecryptableStreamUriLoader;
3639
import org.thoughtcrime.securesms.glide.OkHttpUrlLoader;
3740
import org.thoughtcrime.securesms.glide.cache.ApngFrameDrawableTranscoder;
3841
import org.thoughtcrime.securesms.glide.cache.ByteBufferApngDecoder;
@@ -42,9 +45,6 @@
4245
import org.thoughtcrime.securesms.glide.cache.EncryptedCacheEncoder;
4346
import org.thoughtcrime.securesms.glide.cache.EncryptedGifDrawableResourceEncoder;
4447
import org.thoughtcrime.securesms.glide.cache.StreamApngDecoder;
45-
import org.thoughtcrime.securesms.glide.cache.StreamBitmapDecoder;
46-
import org.thoughtcrime.securesms.glide.cache.StreamFactoryApngDecoder;
47-
import org.thoughtcrime.securesms.glide.cache.StreamFactoryGifDecoder;
4848
import org.thoughtcrime.securesms.glide.cache.WebpSanDecoder;
4949
import org.thoughtcrime.securesms.stickers.StickerRemoteUri;
5050
import org.thoughtcrime.securesms.stickers.StickerRemoteUriLoader;
@@ -72,28 +72,24 @@ public void registerComponents(@NonNull Context context, @NonNull Glide glide, @
7272

7373
registry.prepend(InputStream.class, new EncryptedCacheEncoder(secret, glide.getArrayPool()));
7474

75-
registry.prepend(File.class, Bitmap.class, new EncryptedCacheDecoder<>(secret, new StreamBitmapDecoder(context, glide, registry)));
75+
registry.prepend(File.class, Bitmap.class, new EncryptedCacheDecoder<>(secret, new StreamBitmapDecoder(new Downsampler(registry.getImageHeaderParsers(), context.getResources().getDisplayMetrics(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool())));
7676

77-
StreamGifDecoder streamGifDecoder = new StreamGifDecoder(registry.getImageHeaderParsers(), new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool());
78-
StreamFactoryGifDecoder streamFactoryGifDecoder = new StreamFactoryGifDecoder(streamGifDecoder);
77+
StreamGifDecoder streamGifDecoder = new StreamGifDecoder(registry.getImageHeaderParsers(), new ByteBufferGifDecoder(context, registry.getImageHeaderParsers(), glide.getBitmapPool(), glide.getArrayPool()), glide.getArrayPool());
7978
registry.prepend(InputStream.class, GifDrawable.class, streamGifDecoder);
80-
registry.prepend(InputStreamFactory.class, GifDrawable.class, streamFactoryGifDecoder);
8179
registry.prepend(GifDrawable.class, new EncryptedGifDrawableResourceEncoder(secret));
8280
registry.prepend(File.class, GifDrawable.class, new EncryptedCacheDecoder<>(secret, streamGifDecoder));
8381

8482
EncryptedBitmapResourceEncoder encryptedBitmapResourceEncoder = new EncryptedBitmapResourceEncoder(secret);
8583
registry.prepend(Bitmap.class, new EncryptedBitmapResourceEncoder(secret));
8684
registry.prepend(BitmapDrawable.class, new BitmapDrawableEncoder(glide.getBitmapPool(), encryptedBitmapResourceEncoder));
8785

88-
ByteBufferApngDecoder byteBufferApngDecoder = new ByteBufferApngDecoder();
89-
StreamApngDecoder streamApngDecoder = new StreamApngDecoder(byteBufferApngDecoder);
90-
StreamFactoryApngDecoder streamFactoryApngDecoder = new StreamFactoryApngDecoder(byteBufferApngDecoder, glide, registry);
86+
ByteBufferApngDecoder apngBufferCacheDecoder = new ByteBufferApngDecoder();
87+
StreamApngDecoder apngStreamCacheDecoder = new StreamApngDecoder(apngBufferCacheDecoder);
9188

92-
registry.prepend(InputStream.class, APNGDecoder.class, streamApngDecoder);
93-
registry.prepend(InputStreamFactory.class, APNGDecoder.class, streamFactoryApngDecoder);
94-
registry.prepend(ByteBuffer.class, APNGDecoder.class, byteBufferApngDecoder);
89+
registry.prepend(InputStream.class, APNGDecoder.class, apngStreamCacheDecoder);
90+
registry.prepend(ByteBuffer.class, APNGDecoder.class, apngBufferCacheDecoder);
9591
registry.prepend(APNGDecoder.class, new EncryptedApngCacheEncoder(secret));
96-
registry.prepend(File.class, APNGDecoder.class, new EncryptedCacheDecoder<>(secret, streamApngDecoder));
92+
registry.prepend(File.class, APNGDecoder.class, new EncryptedCacheDecoder<>(secret, apngStreamCacheDecoder));
9793
registry.register(APNGDecoder.class, Drawable.class, new ApngFrameDrawableTranscoder());
9894

9995
registry.prepend(BlurHash.class, Bitmap.class, new BlurHashResourceDecoder());
@@ -102,8 +98,7 @@ public void registerComponents(@NonNull Context context, @NonNull Glide glide, @
10298
registry.append(StoryTextPostModel.class, StoryTextPostModel.class, UnitModelLoader.Factory.getInstance());
10399
registry.append(ConversationShortcutPhoto.class, Bitmap.class, new ConversationShortcutPhoto.Loader.Factory(context));
104100
registry.append(ContactPhoto.class, InputStream.class, new ContactPhotoLoader.Factory(context));
105-
registry.append(DecryptableUri.class, InputStreamFactory.class, new DecryptableUriStreamLoader.Factory(context));
106-
registry.append(InputStreamFactory.class, Bitmap.class, new InputStreamFactoryBitmapDecoder(context, glide, registry));
101+
registry.append(DecryptableUri.class, InputStream.class, new DecryptableStreamUriLoader.Factory(context));
107102
registry.append(ChunkedImageUrl.class, InputStream.class, new ChunkedImageUrlLoader.Factory());
108103
registry.append(StickerRemoteUri.class, InputStream.class, new StickerRemoteUriLoader.Factory());
109104
registry.append(BlurHash.class, BlurHash.class, new BlurHashModelLoader.Factory());

0 commit comments

Comments
 (0)