Revert emoji cache to old pattern.

This commit is contained in:
Alex Hart 2021-05-06 18:47:36 -03:00 committed by GitHub
parent cb9ab61b6b
commit 138f9476ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 103 deletions

View file

@ -15,22 +15,16 @@ import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; 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.ThreadUtil;
import org.signal.core.util.logging.Log; import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiDrawInfo; import org.thoughtcrime.securesms.components.emoji.parsing.EmojiDrawInfo;
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser; import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser;
import org.thoughtcrime.securesms.emoji.EmojiPage; import org.thoughtcrime.securesms.emoji.EmojiPageCache;
import org.thoughtcrime.securesms.emoji.EmojiSource; import org.thoughtcrime.securesms.emoji.EmojiSource;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.util.DeviceProperties; import org.thoughtcrime.securesms.util.DeviceProperties;
import org.thoughtcrime.securesms.util.FutureTaskListener;
import java.util.concurrent.ExecutionException;
class EmojiProvider { class EmojiProvider {
@ -96,27 +90,20 @@ class EmojiProvider {
final int lowMemoryDecodeScale = DeviceProperties.isLowMemoryDevice(context) ? 2 : 1; final int lowMemoryDecodeScale = DeviceProperties.isLowMemoryDevice(context) ? 2 : 1;
final EmojiSource source = EmojiSource.getLatest(); final EmojiSource source = EmojiSource.getLatest();
final EmojiDrawable drawable = new EmojiDrawable(source, drawInfo, lowMemoryDecodeScale); final EmojiDrawable drawable = new EmojiDrawable(source, drawInfo, lowMemoryDecodeScale);
GlideApp.with(context)
.asBitmap() EmojiPageCache.INSTANCE
.diskCacheStrategy(DiskCacheStrategy.NONE) .load(context, drawInfo.getPage(), lowMemoryDecodeScale)
.load(drawInfo.getPage()) .addListener(new FutureTaskListener<Bitmap>() {
.priority(Priority.HIGH)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.apply(new RequestOptions().set(EmojiPage.IN_SAMPLE_SIZE, lowMemoryDecodeScale))
.addListener(new RequestListener<Bitmap>() {
@Override @Override
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) { public void onSuccess(Bitmap result) {
Log.d(TAG, "Failed to load emoji bitmap resource", e); ThreadUtil.runOnMain(() -> drawable.setBitmap(result));
return false;
} }
@Override @Override
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) { public void onFailure(ExecutionException exception) {
ThreadUtil.runOnMain(() -> drawable.setBitmap(resource)); Log.d(TAG, "Failed to load emoji bitmap resource", exception);
return true;
} }
}) });
.submit();
return drawable; return drawable;
} }

View file

@ -1,85 +1,17 @@
package org.thoughtcrime.securesms.emoji package org.thoughtcrime.securesms.emoji
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import com.bumptech.glide.Priority
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.Key import com.bumptech.glide.load.Key
import com.bumptech.glide.load.Option
import com.bumptech.glide.load.Options
import com.bumptech.glide.load.data.DataFetcher
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.PartAuthority
import java.io.InputStream
import java.security.MessageDigest import java.security.MessageDigest
typealias EmojiPageFactory = (Uri) -> EmojiPage typealias EmojiPageFactory = (Uri) -> EmojiPage
sealed class EmojiPage(private val uri: Uri) : Key { sealed class EmojiPage(open val uri: Uri) : Key {
override fun updateDiskCacheKey(messageDigest: MessageDigest) { override fun updateDiskCacheKey(messageDigest: MessageDigest) {
messageDigest.update("EmojiPage".encodeToByteArray()) messageDigest.update("EmojiPage".encodeToByteArray())
messageDigest.update(uri.toString().encodeToByteArray()) messageDigest.update(uri.toString().encodeToByteArray())
} }
data class Asset(private val uri: Uri) : EmojiPage(uri) data class Asset(override val uri: Uri) : EmojiPage(uri)
data class Disk(private val uri: Uri) : EmojiPage(uri) data class Disk(override val uri: Uri) : EmojiPage(uri)
class Loader(private val context: Context) : ModelLoader<EmojiPage, Bitmap> {
override fun buildLoadData(
model: EmojiPage,
width: Int,
height: Int,
options: Options
): ModelLoader.LoadData<Bitmap> {
return ModelLoader.LoadData(model, Fetcher(context, model, options.get(IN_SAMPLE_SIZE) ?: 1))
}
override fun handles(model: EmojiPage): Boolean = true
class Factory(private val context: Context) : ModelLoaderFactory<EmojiPage, Bitmap> {
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<EmojiPage, Bitmap> {
return Loader(context)
}
override fun teardown() = Unit
}
}
class Fetcher(private val context: Context, private val model: EmojiPage, private val inSampleSize: Int) : DataFetcher<Bitmap> {
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in Bitmap>) {
try {
val inputStream: InputStream = when (model) {
is Asset -> context.assets.open(model.uri.toString().replace("file:///android_asset/", ""))
is Disk -> EmojiFiles.openForReading(context, PartAuthority.getEmojiFilename(model.uri))
}
val bitmapOptions = BitmapFactory.Options()
bitmapOptions.inSampleSize = inSampleSize
callback.onDataReady(BitmapFactory.decodeStream(inputStream, null, bitmapOptions))
} catch (e: Exception) {
callback.onLoadFailed(e)
}
}
override fun cleanup() = Unit
override fun cancel() = Unit
override fun getDataClass(): Class<Bitmap> {
return Bitmap::class.java
}
override fun getDataSource(): DataSource {
return DataSource.LOCAL
}
}
companion object {
@JvmField
val IN_SAMPLE_SIZE: Option<Int> = Option.memory("emoji_page_in_sample_size", 1)
}
} }

View file

@ -0,0 +1,73 @@
package org.thoughtcrime.securesms.emoji
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import androidx.annotation.MainThread
import androidx.annotation.WorkerThread
import org.signal.core.util.logging.Log
import org.thoughtcrime.securesms.mms.PartAuthority
import org.thoughtcrime.securesms.util.ListenableFutureTask
import org.thoughtcrime.securesms.util.SoftHashMap
import org.thoughtcrime.securesms.util.concurrent.SimpleTask
import java.io.IOException
import java.io.InputStream
object EmojiPageCache {
private val TAG = Log.tag(EmojiPageCache::class.java)
private val cache: SoftHashMap<EmojiPageRequest, Bitmap> = SoftHashMap()
private val tasks: HashMap<EmojiPageRequest, ListenableFutureTask<Bitmap>> = hashMapOf()
@MainThread
fun load(context: Context, emojiPage: EmojiPage, inSampleSize: Int): ListenableFutureTask<Bitmap> {
val applicationContext = context.applicationContext
val emojiPageRequest = EmojiPageRequest(emojiPage, inSampleSize)
val bitmap: Bitmap? = cache[emojiPageRequest]
val task: ListenableFutureTask<Bitmap>? = tasks[emojiPageRequest]
return when {
bitmap != null -> ListenableFutureTask(bitmap)
task != null -> task
else -> {
val newTask = ListenableFutureTask<Bitmap> {
try {
Log.i(TAG, "Loading page $emojiPageRequest")
loadInternal(applicationContext, emojiPageRequest)
} catch (e: IOException) {
Log.w(TAG, e)
null
}
}
tasks[emojiPageRequest] = newTask
SimpleTask.run(newTask::run) {
try {
cache[emojiPageRequest] = newTask.get()
} finally {
tasks.remove(emojiPageRequest)
}
}
newTask
}
}
}
@WorkerThread
private fun loadInternal(context: Context, emojiPageRequest: EmojiPageRequest): Bitmap? {
val inputStream: InputStream = when (emojiPageRequest.emojiPage) {
is EmojiPage.Asset -> context.assets.open(emojiPageRequest.emojiPage.uri.toString().replace("file:///android_asset/", ""))
is EmojiPage.Disk -> EmojiFiles.openForReading(context, PartAuthority.getEmojiFilename(emojiPageRequest.emojiPage.uri))
}
val bitmapOptions = BitmapFactory.Options()
bitmapOptions.inSampleSize = emojiPageRequest.inSampleSize
return BitmapFactory.decodeStream(inputStream, null, bitmapOptions)
}
private data class EmojiPageRequest(val emojiPage: EmojiPage, val inSampleSize: Int)
}

View file

@ -29,7 +29,6 @@ import org.thoughtcrime.securesms.blurhash.BlurHashResourceDecoder;
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto; import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
import org.thoughtcrime.securesms.crypto.AttachmentSecret; import org.thoughtcrime.securesms.crypto.AttachmentSecret;
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider; import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider;
import org.thoughtcrime.securesms.emoji.EmojiPage;
import org.thoughtcrime.securesms.giph.model.ChunkedImageUrl; import org.thoughtcrime.securesms.giph.model.ChunkedImageUrl;
import org.thoughtcrime.securesms.glide.ChunkedImageUrlLoader; import org.thoughtcrime.securesms.glide.ChunkedImageUrlLoader;
import org.thoughtcrime.securesms.glide.ContactPhotoLoader; import org.thoughtcrime.securesms.glide.ContactPhotoLoader;
@ -91,7 +90,6 @@ public class SignalGlideModule extends AppGlideModule {
registry.prepend(BlurHash.class, Bitmap.class, new BlurHashResourceDecoder()); registry.prepend(BlurHash.class, Bitmap.class, new BlurHashResourceDecoder());
registry.append(EmojiPage.class, Bitmap.class, new EmojiPage.Loader.Factory(context));
registry.append(ConversationShortcutPhoto.class, Bitmap.class, new ConversationShortcutPhoto.Loader.Factory(context)); registry.append(ConversationShortcutPhoto.class, Bitmap.class, new ConversationShortcutPhoto.Loader.Factory(context));
registry.append(ContactPhoto.class, InputStream.class, new ContactPhotoLoader.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, InputStream.class, new DecryptableStreamUriLoader.Factory(context));