Fix Emoji crashes when downloaded bitmap files cannot be found.
This commit is contained in:
parent
276b757e2d
commit
1f3e131690
4 changed files with 59 additions and 15 deletions
|
@ -156,7 +156,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||||
.addNonBlocking(StorageSyncHelper::scheduleRoutineSync)
|
.addNonBlocking(StorageSyncHelper::scheduleRoutineSync)
|
||||||
.addNonBlocking(() -> ApplicationDependencies.getJobManager().beginJobLoop())
|
.addNonBlocking(() -> ApplicationDependencies.getJobManager().beginJobLoop())
|
||||||
.addNonBlocking(EmojiSource::refresh)
|
.addNonBlocking(EmojiSource::refresh)
|
||||||
.addNonBlocking(DownloadLatestEmojiDataJob::scheduleIfNecessary)
|
.addNonBlocking(() -> DownloadLatestEmojiDataJob.scheduleIfNecessary(this))
|
||||||
.addPostRender(() -> RateLimitUtil.retryAllRateLimitedMessages(this))
|
.addPostRender(() -> RateLimitUtil.retryAllRateLimitedMessages(this))
|
||||||
.addPostRender(this::initializeExpiringMessageManager)
|
.addPostRender(this::initializeExpiringMessageManager)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
|
@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.readValue
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
|
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
|
||||||
|
import okio.HashingSink
|
||||||
import okio.Okio
|
import okio.Okio
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider
|
import org.thoughtcrime.securesms.crypto.AttachmentSecretProvider
|
||||||
|
@ -96,8 +97,12 @@ object EmojiFiles {
|
||||||
val file = version.getFile(context, uuid)
|
val file = version.getFile(context, uuid)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
getInputStream(context, file).use {
|
HashingSink.md5(Okio.blackhole()).use { hashingSink ->
|
||||||
return Okio.buffer(Okio.source(it)).buffer.md5().toByteArray()
|
Okio.buffer(Okio.source(getInputStream(context, file))).use { source ->
|
||||||
|
source.readAll(hashingSink)
|
||||||
|
|
||||||
|
return hashingSink.hash().toByteArray()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.i(TAG, "Could not read emoji data file md5", e)
|
Log.i(TAG, "Could not read emoji data file md5", e)
|
||||||
|
@ -129,18 +134,21 @@ object EmojiFiles {
|
||||||
|
|
||||||
private val objectMapper = ObjectMapper().registerKotlinModule()
|
private val objectMapper = ObjectMapper().registerKotlinModule()
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun exists(context: Context): Boolean = context.getVersionFile().exists()
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun readVersion(context: Context): Version? {
|
fun readVersion(context: Context): Version? {
|
||||||
try {
|
val version = try {
|
||||||
getInputStream(context, context.getVersionFile()).use {
|
getInputStream(context, context.getVersionFile()).use {
|
||||||
return objectMapper.readValue(it, Version::class.java)
|
objectMapper.readValue(it, Version::class.java)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(TAG, "Could not read current emoji version from disk.")
|
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.")
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,12 @@ object EmojiPageCache {
|
||||||
|
|
||||||
SimpleTask.run(newTask::run) {
|
SimpleTask.run(newTask::run) {
|
||||||
try {
|
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 {
|
} finally {
|
||||||
tasks.remove(emojiPageRequest)
|
tasks.remove(emojiPageRequest)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ import okhttp3.Response;
|
||||||
import okhttp3.ResponseBody;
|
import okhttp3.ResponseBody;
|
||||||
import okio.HashingSink;
|
import okio.HashingSink;
|
||||||
import okio.Okio;
|
import okio.Okio;
|
||||||
|
import okio.Sink;
|
||||||
import okio.Source;
|
import okio.Source;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,15 +63,17 @@ public class DownloadLatestEmojiDataJob extends BaseJob {
|
||||||
|
|
||||||
private EmojiFiles.Version targetVersion;
|
private EmojiFiles.Version targetVersion;
|
||||||
|
|
||||||
public static void scheduleIfNecessary() {
|
public static void scheduleIfNecessary(@NonNull Context context) {
|
||||||
long nextScheduledCheck = SignalStore.emojiValues().getNextScheduledCheck();
|
long nextScheduledCheck = SignalStore.emojiValues().getNextScheduledCheck();
|
||||||
|
|
||||||
if (nextScheduledCheck <= System.currentTimeMillis()) {
|
if (nextScheduledCheck <= System.currentTimeMillis()) {
|
||||||
Log.i(TAG, "Scheduling DownloadLatestEmojiDataJob.");
|
Log.i(TAG, "Scheduling DownloadLatestEmojiDataJob.");
|
||||||
ApplicationDependencies.getJobManager().add(new DownloadLatestEmojiDataJob(false));
|
ApplicationDependencies.getJobManager().add(new DownloadLatestEmojiDataJob(false));
|
||||||
|
|
||||||
|
EmojiFiles.Version version = EmojiFiles.Version.readVersion(context);
|
||||||
|
|
||||||
long interval;
|
long interval;
|
||||||
if (EmojiFiles.Version.exists(ApplicationDependencies.getApplication())) {
|
if (EmojiFiles.Version.isVersionValid(context, version)) {
|
||||||
interval = INTERVAL_WITH_REMOTE_DOWNLOAD;
|
interval = INTERVAL_WITH_REMOTE_DOWNLOAD;
|
||||||
} else {
|
} else {
|
||||||
interval = INTERVAL_WITHOUT_REMOTE_DOWNLOAD;
|
interval = INTERVAL_WITHOUT_REMOTE_DOWNLOAD;
|
||||||
|
@ -365,11 +368,15 @@ public class DownloadLatestEmojiDataJob extends BaseJob {
|
||||||
|
|
||||||
try (OutputStream outputStream = EmojiFiles.openForWriting(context, version, name.getUuid())) {
|
try (OutputStream outputStream = EmojiFiles.openForWriting(context, version, name.getUuid())) {
|
||||||
Source source = response.body().source();
|
Source source = response.body().source();
|
||||||
HashingSink sink = HashingSink.md5(Okio.sink(outputStream));
|
Sink sink = Okio.sink(outputStream);
|
||||||
|
|
||||||
Okio.buffer(source).readAll(sink);
|
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))) {
|
if (!Arrays.equals(savedMd5, Hex.toByteArray(responseMD5))) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue