Fix issue with gif search and emoji loading on lowmem devices.
This commit is contained in:
parent
5e2a3ac644
commit
02d060ca0a
5 changed files with 85 additions and 10 deletions
|
@ -135,6 +135,7 @@ android {
|
|||
buildConfigField "int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode"
|
||||
buildConfigField "String", "DEFAULT_CURRENCIES", "\"EUR,AUD,GBP,CAD,CNY\""
|
||||
buildConfigField "int[]", "MOBILE_COIN_REGIONS", "new int[]{44}"
|
||||
buildConfigField "String", "GIPHY_API_KEY", "\"3o6ZsYH6U6Eri53TXy\""
|
||||
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
|
|
|
@ -15,18 +15,22 @@ import android.widget.TextView;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bumptech.glide.Priority;
|
||||
import com.bumptech.glide.load.DataSource;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.load.engine.GlideException;
|
||||
import com.bumptech.glide.request.RequestListener;
|
||||
import com.bumptech.glide.request.RequestOptions;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiDrawInfo;
|
||||
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser;
|
||||
import org.thoughtcrime.securesms.emoji.EmojiBitmapDecoder;
|
||||
import org.thoughtcrime.securesms.emoji.EmojiSource;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.util.DeviceProperties;
|
||||
|
||||
class EmojiProvider {
|
||||
|
||||
|
@ -89,12 +93,16 @@ class EmojiProvider {
|
|||
return null;
|
||||
}
|
||||
|
||||
final EmojiSource source = EmojiSource.getLatest();
|
||||
final EmojiDrawable drawable = new EmojiDrawable(source, drawInfo);
|
||||
final int lowMemoryDecodeScale = DeviceProperties.isLowMemoryDevice(context) ? 2 : 1;
|
||||
final EmojiSource source = EmojiSource.getLatest();
|
||||
final EmojiDrawable drawable = new EmojiDrawable(source, drawInfo, lowMemoryDecodeScale);
|
||||
GlideApp.with(context)
|
||||
.asBitmap()
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.load(drawInfo.getPage().getModel())
|
||||
.priority(Priority.HIGH)
|
||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
||||
.apply(new RequestOptions().set(EmojiBitmapDecoder.OPTION, lowMemoryDecodeScale))
|
||||
.addListener(new RequestListener<Bitmap>() {
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
|
||||
|
@ -130,12 +138,12 @@ class EmojiProvider {
|
|||
return (int) intrinsicHeight;
|
||||
}
|
||||
|
||||
EmojiDrawable(@NonNull EmojiSource source, @NonNull EmojiDrawInfo info) {
|
||||
this.intrinsicWidth = source.getMetrics().getRawWidth() * source.getDecodeScale();
|
||||
this.intrinsicHeight = source.getMetrics().getRawHeight() * source.getDecodeScale();
|
||||
EmojiDrawable(@NonNull EmojiSource source, @NonNull EmojiDrawInfo info, int lowMemoryDecodeScale) {
|
||||
this.intrinsicWidth = (source.getMetrics().getRawWidth() * source.getDecodeScale()) / lowMemoryDecodeScale;
|
||||
this.intrinsicHeight = (source.getMetrics().getRawHeight() * source.getDecodeScale()) / lowMemoryDecodeScale;
|
||||
|
||||
final int glyphWidth = (int) (source.getMetrics().getRawWidth() * source.getDecodeScale());
|
||||
final int glyphHeight = (int) (source.getMetrics().getRawHeight() * source.getDecodeScale());
|
||||
final int glyphWidth = (int) (intrinsicWidth);
|
||||
final int glyphHeight = (int) (intrinsicHeight);
|
||||
final int index = info.getIndex();
|
||||
final int emojiPerRow = source.getMetrics().getPerRow();
|
||||
final int xStart = (index % emojiPerRow) * glyphWidth;
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package org.thoughtcrime.securesms.emoji
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import com.bumptech.glide.load.Option
|
||||
import com.bumptech.glide.load.Options
|
||||
import com.bumptech.glide.load.ResourceDecoder
|
||||
import com.bumptech.glide.load.engine.Resource
|
||||
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
|
||||
import com.bumptech.glide.load.resource.bitmap.BitmapResource
|
||||
import java.io.InputStream
|
||||
|
||||
/**
|
||||
* Allows fine grain control over how we decode Emoji pages via a scale factor.
|
||||
*
|
||||
* This can be set via RequestOptions on a Glide request:
|
||||
*
|
||||
* ```
|
||||
* .apply(RequestOptions().set(EmojiBitmapDecoder.OPTION, inSampleSize)
|
||||
* ```
|
||||
*/
|
||||
class EmojiBitmapDecoder(private val bitmapPool: BitmapPool) : ResourceDecoder<InputStream, Bitmap> {
|
||||
|
||||
override fun handles(source: InputStream, options: Options): Boolean {
|
||||
return options.get(OPTION)?.let { it > 1 } ?: false
|
||||
}
|
||||
|
||||
override fun decode(source: InputStream, width: Int, height: Int, options: Options): Resource<Bitmap>? {
|
||||
val bitmapOptions = BitmapFactory.Options()
|
||||
|
||||
bitmapOptions.inSampleSize = requireNotNull(options.get(OPTION))
|
||||
|
||||
return BitmapResource.obtain(BitmapFactory.decodeStream(source, null, bitmapOptions), bitmapPool)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val OPTION: Option<Int> = Option.memory("emoji_sample_size", 1)
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import androidx.annotation.Nullable;
|
|||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.paging.PagedDataSource;
|
||||
import org.thoughtcrime.securesms.BuildConfig;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.giph.model.GiphyImage;
|
||||
import org.thoughtcrime.securesms.giph.model.GiphyResponse;
|
||||
|
@ -27,6 +28,20 @@ import okhttp3.Response;
|
|||
*/
|
||||
final class GiphyMp4PagedDataSource implements PagedDataSource<GiphyImage> {
|
||||
|
||||
private static final Uri BASE_GIPHY_URI = Uri.parse("https://api.giphy.com/v1/gifs/")
|
||||
.buildUpon()
|
||||
.appendQueryParameter("api_key", BuildConfig.GIPHY_API_KEY)
|
||||
.build();
|
||||
|
||||
private static final Uri TRENDING_URI = BASE_GIPHY_URI.buildUpon()
|
||||
.appendPath("trending")
|
||||
.build();
|
||||
|
||||
private static final Uri SEARCH_URI = BASE_GIPHY_URI.buildUpon()
|
||||
.appendPath("search")
|
||||
.build();
|
||||
|
||||
|
||||
private static final String TAG = Log.tag(GiphyMp4PagedDataSource.class);
|
||||
|
||||
private final String searchString;
|
||||
|
@ -64,7 +79,7 @@ final class GiphyMp4PagedDataSource implements PagedDataSource<GiphyImage> {
|
|||
String url;
|
||||
|
||||
if (TextUtils.isEmpty(searchString)) url = getTrendingUrl(start, length);
|
||||
else url = getSearchUrl(start, length, Uri.encode(searchString));
|
||||
else url = getSearchUrl(start, length, searchString);
|
||||
|
||||
Request request = new Request.Builder().url(url).build();
|
||||
|
||||
|
@ -83,10 +98,19 @@ final class GiphyMp4PagedDataSource implements PagedDataSource<GiphyImage> {
|
|||
}
|
||||
|
||||
private String getTrendingUrl(int start, int length) {
|
||||
return "https://api.giphy.com/v1/gifs/trending?api_key=3o6ZsYH6U6Eri53TXy&offset=" + start + "&limit=" + length;
|
||||
return TRENDING_URI.buildUpon()
|
||||
.appendQueryParameter("offset", String.valueOf(start))
|
||||
.appendQueryParameter("limit", String.valueOf(length))
|
||||
.build()
|
||||
.toString();
|
||||
}
|
||||
|
||||
private String getSearchUrl(int start, int length, @NonNull String query) {
|
||||
return "https://api.giphy.com/v1/gifs/search?api_key=3o6ZsYH6U6Eri53TXy&offset=" + start + "&limit=" + length + "&q=" + Uri.encode(query);
|
||||
return SEARCH_URI.buildUpon()
|
||||
.appendQueryParameter("offset", String.valueOf(start))
|
||||
.appendQueryParameter("limit", String.valueOf(length))
|
||||
.appendQueryParameter("q", query)
|
||||
.build()
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.thoughtcrime.securesms.blurhash.BlurHashResourceDecoder;
|
|||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
|
||||
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
|
||||
import org.thoughtcrime.securesms.emoji.EmojiBitmapDecoder;
|
||||
import org.thoughtcrime.securesms.giph.model.ChunkedImageUrl;
|
||||
import org.thoughtcrime.securesms.glide.ChunkedImageUrlLoader;
|
||||
import org.thoughtcrime.securesms.glide.ContactPhotoLoader;
|
||||
|
@ -82,6 +83,7 @@ public class SignalGlideModule extends AppGlideModule {
|
|||
ApngBufferCacheDecoder apngBufferCacheDecoder = new ApngBufferCacheDecoder();
|
||||
ApngStreamCacheDecoder apngStreamCacheDecoder = new ApngStreamCacheDecoder(apngBufferCacheDecoder);
|
||||
|
||||
registry.prepend(InputStream.class, Bitmap.class, new EmojiBitmapDecoder(glide.getBitmapPool()));
|
||||
registry.prepend(InputStream.class, APNGDecoder.class, apngStreamCacheDecoder);
|
||||
registry.prepend(ByteBuffer.class, APNGDecoder.class, apngBufferCacheDecoder);
|
||||
registry.prepend(APNGDecoder.class, new EncryptedApngCacheEncoder(secret));
|
||||
|
|
Loading…
Add table
Reference in a new issue