Revert emoji cache to old pattern.
This commit is contained in:
parent
cb9ab61b6b
commit
138f9476ac
4 changed files with 93 additions and 103 deletions
|
@ -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()
|
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
|
||||||
.load(drawInfo.getPage())
|
|
||||||
.priority(Priority.HIGH)
|
|
||||||
.diskCacheStrategy(DiskCacheStrategy.NONE)
|
|
||||||
.apply(new RequestOptions().set(EmojiPage.IN_SAMPLE_SIZE, lowMemoryDecodeScale))
|
|
||||||
.addListener(new RequestListener<Bitmap>() {
|
|
||||||
@Override
|
|
||||||
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
|
|
||||||
Log.d(TAG, "Failed to load emoji bitmap resource", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
EmojiPageCache.INSTANCE
|
||||||
public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
|
.load(context, drawInfo.getPage(), lowMemoryDecodeScale)
|
||||||
ThreadUtil.runOnMain(() -> drawable.setBitmap(resource));
|
.addListener(new FutureTaskListener<Bitmap>() {
|
||||||
return true;
|
@Override
|
||||||
}
|
public void onSuccess(Bitmap result) {
|
||||||
})
|
ThreadUtil.runOnMain(() -> drawable.setBitmap(result));
|
||||||
.submit();
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(ExecutionException exception) {
|
||||||
|
Log.d(TAG, "Failed to load emoji bitmap resource", exception);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return drawable;
|
return drawable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -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));
|
||||||
|
|
Loading…
Add table
Reference in a new issue