diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index 9fda047ecb..7a24c364a4 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -156,7 +156,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr .addNonBlocking(StorageSyncHelper::scheduleRoutineSync) .addNonBlocking(() -> ApplicationDependencies.getJobManager().beginJobLoop()) .addNonBlocking(EmojiSource::refresh) - .addNonBlocking(DownloadLatestEmojiDataJob::scheduleIfNecessary) + .addNonBlocking(() -> DownloadLatestEmojiDataJob.scheduleIfNecessary(this)) .addPostRender(() -> RateLimitUtil.retryAllRateLimitedMessages(this)) .addPostRender(this::initializeExpiringMessageManager) .execute(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiFiles.kt b/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiFiles.kt index a154bf90da..f05e07812b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiFiles.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiFiles.kt @@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.readValue import com.fasterxml.jackson.module.kotlin.registerKotlinModule +import okio.HashingSink import okio.Okio import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider @@ -96,8 +97,12 @@ object EmojiFiles { val file = version.getFile(context, uuid) try { - getInputStream(context, file).use { - return Okio.buffer(Okio.source(it)).buffer.md5().toByteArray() + HashingSink.md5(Okio.blackhole()).use { hashingSink -> + Okio.buffer(Okio.source(getInputStream(context, file))).use { source -> + source.readAll(hashingSink) + + return hashingSink.hash().toByteArray() + } } } catch (e: Exception) { Log.i(TAG, "Could not read emoji data file md5", e) @@ -129,18 +134,21 @@ object EmojiFiles { private val objectMapper = ObjectMapper().registerKotlinModule() - @JvmStatic - fun exists(context: Context): Boolean = context.getVersionFile().exists() - @JvmStatic fun readVersion(context: Context): Version? { - try { + val version = try { getInputStream(context, context.getVersionFile()).use { - return objectMapper.readValue(it, Version::class.java) + objectMapper.readValue(it, Version::class.java) } } catch (e: Exception) { Log.w(TAG, "Could not read current emoji version from disk.") - return null + null + } + + return if (isVersionValid(context, version)) { + version + } else { + null } } @@ -160,6 +168,30 @@ object EmojiFiles { Log.w(TAG, "Could not write current emoji version from disk.") } } + + @JvmStatic + fun isVersionValid(context: Context, version: Version?): Boolean { + if (version == null) { + Log.d(TAG, "Version does not exist.") + return false + } + + val nameCollection = NameCollection.read(context, version) + + return if (nameCollection.names.isEmpty()) { + Log.d(TAG, "NameCollection file is empty.") + false + } else { + Log.d(TAG, "Verifying all name files exist.") + val allNamesExist = nameCollection.names + .map { version.getFile(context, it.uuid) } + .all { it.exists() } + + Log.d(TAG, "All names exist? $allNamesExist") + + allNamesExist + } + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiPageCache.kt b/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiPageCache.kt index b29b1a098b..32564f1d7c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiPageCache.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/emoji/EmojiPageCache.kt @@ -45,7 +45,12 @@ object EmojiPageCache { SimpleTask.run(newTask::run) { try { - cache[emojiPageRequest] = newTask.get() + val newBitmap: Bitmap? = newTask.get() + if (newBitmap == null) { + Log.w(TAG, "Failed to load emoji bitmap for request $emojiPageRequest") + } else { + cache[emojiPageRequest] = newBitmap + } } finally { tasks.remove(emojiPageRequest) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob.java index 47aa01a6d7..f2682cfa12 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/DownloadLatestEmojiDataJob.java @@ -41,6 +41,7 @@ import okhttp3.Response; import okhttp3.ResponseBody; import okio.HashingSink; import okio.Okio; +import okio.Sink; import okio.Source; /** @@ -62,15 +63,17 @@ public class DownloadLatestEmojiDataJob extends BaseJob { private EmojiFiles.Version targetVersion; - public static void scheduleIfNecessary() { + public static void scheduleIfNecessary(@NonNull Context context) { long nextScheduledCheck = SignalStore.emojiValues().getNextScheduledCheck(); if (nextScheduledCheck <= System.currentTimeMillis()) { Log.i(TAG, "Scheduling DownloadLatestEmojiDataJob."); ApplicationDependencies.getJobManager().add(new DownloadLatestEmojiDataJob(false)); + EmojiFiles.Version version = EmojiFiles.Version.readVersion(context); + long interval; - if (EmojiFiles.Version.exists(ApplicationDependencies.getApplication())) { + if (EmojiFiles.Version.isVersionValid(context, version)) { interval = INTERVAL_WITH_REMOTE_DOWNLOAD; } else { interval = INTERVAL_WITHOUT_REMOTE_DOWNLOAD; @@ -364,12 +367,16 @@ public class DownloadLatestEmojiDataJob extends BaseJob { byte[] savedMd5; try (OutputStream outputStream = EmojiFiles.openForWriting(context, version, name.getUuid())) { - Source source = response.body().source(); - HashingSink sink = HashingSink.md5(Okio.sink(outputStream)); + Source source = response.body().source(); + Sink sink = Okio.sink(outputStream); Okio.buffer(source).readAll(sink); + outputStream.flush(); - savedMd5 = sink.hash().toByteArray(); + source.close(); + sink.close(); + + savedMd5 = EmojiFiles.getMd5(context, version, name.getUuid()); } if (!Arrays.equals(savedMd5, Hex.toByteArray(responseMD5))) {