Fix issue where gifs would load as images.

fork-5.53.8
Alex Hart 2021-05-06 16:19:24 -03:00 zatwierdzone przez GitHub
rodzic bcbd365326
commit cb9ab61b6b
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
9 zmienionych plików z 101 dodań i 113 usunięć

Wyświetl plik

@ -27,7 +27,7 @@ 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.EmojiPage;
import org.thoughtcrime.securesms.emoji.EmojiSource;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.util.DeviceProperties;
@ -99,10 +99,10 @@ class EmojiProvider {
GlideApp.with(context)
.asBitmap()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.load(drawInfo.getPage().getModel())
.load(drawInfo.getPage())
.priority(Priority.HIGH)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.apply(new RequestOptions().set(EmojiBitmapDecoder.OPTION, lowMemoryDecodeScale))
.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) {

Wyświetl plik

@ -3,19 +3,19 @@ package org.thoughtcrime.securesms.components.emoji.parsing;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.emoji.EmojiPageReference;
import org.thoughtcrime.securesms.emoji.EmojiPage;
public class EmojiDrawInfo {
private final EmojiPageReference page;
private final int index;
private final EmojiPage page;
private final int index;
public EmojiDrawInfo(final @NonNull EmojiPageReference page, final int index) {
public EmojiDrawInfo(final @NonNull EmojiPage page, final int index) {
this.page = page;
this.index = index;
}
public @NonNull EmojiPageReference getPage() {
public @NonNull EmojiPage getPage() {
return page;
}

Wyświetl plik

@ -1,40 +0,0 @@
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)
}
}

Wyświetl plik

@ -1,34 +0,0 @@
package org.thoughtcrime.securesms.emoji
import android.content.Context
import android.content.Intent
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.jobs.DownloadLatestEmojiDataJob
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.service.PersistentAlarmManagerListener
import java.util.concurrent.TimeUnit
private val INTERVAL_WITHOUT_REMOTE_DOWNLOAD = TimeUnit.DAYS.toMillis(1)
private val INTERVAL_WITH_REMOTE_DOWNLOAD = TimeUnit.DAYS.toMillis(7)
class EmojiDownloadListener : PersistentAlarmManagerListener() {
override fun getNextScheduledExecutionTime(context: Context): Long = SignalStore.emojiValues().nextScheduledCheck
override fun onAlarm(context: Context, scheduledTime: Long): Long {
ApplicationDependencies.getJobManager().add(DownloadLatestEmojiDataJob(false))
val nextTime: Long = System.currentTimeMillis() + if (EmojiFiles.Version.exists(context)) INTERVAL_WITH_REMOTE_DOWNLOAD else INTERVAL_WITHOUT_REMOTE_DOWNLOAD
SignalStore.emojiValues().nextScheduledCheck = nextTime
return nextTime
}
companion object {
@JvmStatic
fun schedule(context: Context) {
EmojiDownloadListener().onReceive(context, Intent())
}
}
}

Wyświetl plik

@ -0,0 +1,85 @@
package org.thoughtcrime.securesms.emoji
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
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.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
typealias EmojiPageFactory = (Uri) -> EmojiPage
sealed class EmojiPage(private val uri: Uri) : Key {
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
messageDigest.update("EmojiPage".encodeToByteArray())
messageDigest.update(uri.toString().encodeToByteArray())
}
data class Asset(private val uri: Uri) : EmojiPage(uri)
data class Disk(private 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)
}
}

Wyświetl plik

@ -1,22 +0,0 @@
package org.thoughtcrime.securesms.emoji
import android.net.Uri
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader
/**
* Used by Emoji provider to set up a glide request.
*/
class EmojiPageReference {
val model: Any
constructor(uri: Uri) {
model = uri
}
constructor(decryptableUri: DecryptableStreamUriLoader.DecryptableUri) {
model = decryptableUri
}
}
typealias EmojiPageReferenceFactory = (uri: Uri) -> EmojiPageReference

Wyświetl plik

@ -9,7 +9,6 @@ import org.thoughtcrime.securesms.components.emoji.parsing.EmojiDrawInfo
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiTree
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader
import org.thoughtcrime.securesms.util.ScreenDensity
import java.io.InputStream
import java.util.concurrent.CountDownLatch
@ -21,7 +20,7 @@ import java.util.concurrent.atomic.AtomicReference
class EmojiSource(
val decodeScale: Float,
private val emojiData: EmojiData,
private val emojiPageReferenceFactory: EmojiPageReferenceFactory
private val emojiPageFactory: EmojiPageFactory
) : EmojiData by emojiData {
val variationMap: Map<String, String> by lazy {
@ -50,9 +49,9 @@ class EmojiSource(
dataPages
.filter { it.spriteUri != null }
.forEach { page ->
val reference = emojiPageReferenceFactory(page.spriteUri!!)
val emojiPage = emojiPageFactory(page.spriteUri!!)
page.emoji.forEachIndexed { idx, emoji ->
tree.add(emoji, EmojiDrawInfo(reference, idx))
tree.add(emoji, EmojiDrawInfo(emojiPage, idx))
}
}
@ -97,7 +96,7 @@ class EmojiSource(
val density = ScreenDensity.xhdpiRelativeDensityScaleFactor(version.density)
return emojiData?.let {
EmojiSource(density, it) { uri: Uri -> EmojiPageReference(DecryptableStreamUriLoader.DecryptableUri(uri)) }
EmojiSource(density, it) { uri: Uri -> EmojiPage.Disk(uri) }
}
}
@ -112,7 +111,7 @@ class EmojiSource(
displayPages = parsedData.displayPages + PAGE_EMOTICONS,
dataPages = parsedData.dataPages + PAGE_EMOTICONS
)
) { uri: Uri -> EmojiPageReference(uri) }
) { uri: Uri -> EmojiPage.Asset(uri) }
}
}
}

Wyświetl plik

@ -29,7 +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.emoji.EmojiPage;
import org.thoughtcrime.securesms.giph.model.ChunkedImageUrl;
import org.thoughtcrime.securesms.glide.ChunkedImageUrlLoader;
import org.thoughtcrime.securesms.glide.ContactPhotoLoader;
@ -83,7 +83,6 @@ 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));
@ -92,6 +91,7 @@ public class SignalGlideModule extends AppGlideModule {
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(ContactPhoto.class, InputStream.class, new ContactPhotoLoader.Factory(context));
registry.append(DecryptableUri.class, InputStream.class, new DecryptableStreamUriLoader.Factory(context));

Wyświetl plik

@ -11,7 +11,7 @@ class EmojiSourceTest {
@Test
fun `Given a bunch of data pages with max value 100100, when I get the maxEmojiLength, then I expect 6`() {
val emojiDataFake = ParsedEmojiData(EmojiMetrics(-1, -1, -1), listOf(), "png", listOf(), dataPages = generatePages(), listOf())
val testSubject = EmojiSource(0f, emojiDataFake, ::EmojiPageReference)
val testSubject = EmojiSource(0f, emojiDataFake) { uri -> EmojiPage.Disk(uri) }
Assert.assertEquals(6, testSubject.maxEmojiLength)
}