mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-15 07:28:30 +00:00
Fix thumbnail rendering and refreshing on full download.
This commit is contained in:
committed by
Greyson Parrelli
parent
b74f04495e
commit
a1bf4d62ab
@@ -11,7 +11,6 @@ import org.thoughtcrime.securesms.attachments.DatabaseAttachment
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import org.thoughtcrime.securesms.util.MediaUtil.SlideType
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
|
||||
@SuppressLint("RecipientIdDatabaseReferenceUsage", "ThreadIdDatabaseReferenceUsage") // Not a real table, just a view
|
||||
class MediaTable internal constructor(context: Context?, databaseHelper: SignalDatabase?) : DatabaseTable(context, databaseHelper) {
|
||||
@@ -109,16 +108,6 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
)
|
||||
|
||||
private val GALLERY_MEDIA_QUERY_INCLUDING_TEMP_VIDEOS = String.format(
|
||||
BASE_MEDIA_QUERY,
|
||||
"""
|
||||
(${AttachmentTable.DATA_FILE} IS NOT NULL OR (${AttachmentTable.CONTENT_TYPE} LIKE 'video/%' AND ${AttachmentTable.REMOTE_INCREMENTAL_DIGEST} IS NOT NULL)) AND
|
||||
${AttachmentTable.CONTENT_TYPE} NOT LIKE 'image/svg%' AND
|
||||
(${AttachmentTable.CONTENT_TYPE} LIKE 'image/%' OR ${AttachmentTable.CONTENT_TYPE} LIKE 'video/%') AND
|
||||
${MessageTable.LINK_PREVIEWS} IS NULL
|
||||
"""
|
||||
)
|
||||
|
||||
private val GALLERY_MEDIA_QUERY_INCLUDING_TEMP_VIDEOS_AND_THUMBNAILS = String.format(
|
||||
BASE_MEDIA_QUERY,
|
||||
"""
|
||||
(${AttachmentTable.DATA_FILE} IS NOT NULL OR (${AttachmentTable.CONTENT_TYPE} LIKE 'video/%' AND ${AttachmentTable.REMOTE_INCREMENTAL_DIGEST} IS NOT NULL) OR (${AttachmentTable.THUMBNAIL_FILE} IS NOT NULL)) AND
|
||||
@@ -167,11 +156,7 @@ class MediaTable internal constructor(context: Context?, databaseHelper: SignalD
|
||||
|
||||
@JvmOverloads
|
||||
fun getGalleryMediaForThread(threadId: Long, sorting: Sorting, limit: Int = 0): Cursor {
|
||||
var query = if (RemoteConfig.messageBackups) {
|
||||
sorting.applyToQuery(applyEqualityOperator(threadId, GALLERY_MEDIA_QUERY_INCLUDING_TEMP_VIDEOS_AND_THUMBNAILS))
|
||||
} else {
|
||||
sorting.applyToQuery(applyEqualityOperator(threadId, GALLERY_MEDIA_QUERY_INCLUDING_TEMP_VIDEOS))
|
||||
}
|
||||
var query = sorting.applyToQuery(applyEqualityOperator(threadId, GALLERY_MEDIA_QUERY_INCLUDING_TEMP_VIDEOS))
|
||||
val args = arrayOf(threadId.toString() + "")
|
||||
|
||||
if (limit > 0) {
|
||||
|
||||
@@ -131,7 +131,6 @@ class ArchiveThumbnailUploadJob private constructor(
|
||||
val archiveMediaId = attachment.archiveMediaId ?: backupKey.deriveMediaId(attachment.getMediaName()).encode()
|
||||
SignalDatabase.attachments.finalizeAttachmentThumbnailAfterUpload(attachmentId, archiveMediaId, mediaSecrets.id, thumbnailResult.data)
|
||||
|
||||
Log.i(RestoreAttachmentJob.TAG, "Restore: Thumbnail mediaId=${mediaSecrets.id.encode()} backupDir=${backupDirectories.backupDir} mediaDir=${backupDirectories.mediaDir}")
|
||||
Log.d(TAG, "Successfully archived thumbnail for $attachmentId mediaName=${attachment.getThumbnailMediaName()}")
|
||||
Result.success()
|
||||
}
|
||||
|
||||
@@ -84,6 +84,8 @@ class AttachmentDownloadJob private constructor(
|
||||
@JvmStatic
|
||||
fun downloadAttachmentIfNeeded(databaseAttachment: DatabaseAttachment): String? {
|
||||
return when (val transferState = databaseAttachment.transferState) {
|
||||
AttachmentTable.TRANSFER_PROGRESS_DONE -> null
|
||||
|
||||
AttachmentTable.TRANSFER_RESTORE_OFFLOADED,
|
||||
AttachmentTable.TRANSFER_NEEDS_RESTORE -> RestoreAttachmentJob.restoreAttachment(databaseAttachment)
|
||||
|
||||
@@ -109,10 +111,9 @@ class AttachmentDownloadJob private constructor(
|
||||
}
|
||||
|
||||
AttachmentTable.TRANSFER_RESTORE_IN_PROGRESS,
|
||||
AttachmentTable.TRANSFER_PROGRESS_DONE,
|
||||
AttachmentTable.TRANSFER_PROGRESS_STARTED,
|
||||
AttachmentTable.TRANSFER_PROGRESS_PERMANENT_FAILURE -> {
|
||||
Log.d(TAG, "$databaseAttachment is downloading, downloaded already or permanently failed, transferState: $transferState")
|
||||
Log.d(TAG, "${databaseAttachment.attachmentId} is downloading or permanently failed, transferState: $transferState")
|
||||
null
|
||||
}
|
||||
|
||||
@@ -215,6 +216,7 @@ class AttachmentDownloadJob private constructor(
|
||||
retrieveAttachmentForReleaseChannel(messageId, attachmentId, attachment)
|
||||
false
|
||||
}
|
||||
|
||||
else -> {
|
||||
retrieveAttachment(messageId, attachmentId, attachment)
|
||||
}
|
||||
@@ -225,14 +227,17 @@ class AttachmentDownloadJob private constructor(
|
||||
attachment.archiveTransferState == AttachmentTable.ArchiveTransferState.FINISHED -> {
|
||||
Log.i(TAG, "[$attachmentId] Already archived. Skipping.")
|
||||
}
|
||||
|
||||
digestChanged -> {
|
||||
Log.i(TAG, "[$attachmentId] Digest for attachment changed after download. Re-uploading to archive.")
|
||||
AppDependencies.jobManager.add(UploadAttachmentToArchiveJob(attachmentId))
|
||||
}
|
||||
|
||||
attachment.cdn !in CopyAttachmentToArchiveJob.ALLOWED_SOURCE_CDNS -> {
|
||||
Log.i(TAG, "[$attachmentId] Attachment CDN doesn't support copying to archive. Re-uploading to archive.")
|
||||
AppDependencies.jobManager.add(UploadAttachmentToArchiveJob(attachmentId))
|
||||
}
|
||||
|
||||
else -> {
|
||||
Log.i(TAG, "[$attachmentId] Enqueuing job to copy to archive.")
|
||||
AppDependencies.jobManager.add(CopyAttachmentToArchiveJob(attachmentId))
|
||||
|
||||
@@ -48,7 +48,7 @@ class RestoreAttachmentJob private constructor(
|
||||
|
||||
companion object {
|
||||
const val KEY = "RestoreAttachmentJob"
|
||||
val TAG = Log.tag(RestoreAttachmentJob::class.java)
|
||||
private val TAG = Log.tag(RestoreAttachmentJob::class.java)
|
||||
|
||||
@JvmStatic
|
||||
fun constructQueueString(): String {
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment
|
||||
import org.whispersystems.signalservice.api.push.exceptions.MissingConfigurationException
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.TimeUnit
|
||||
@@ -142,6 +143,12 @@ class RestoreAttachmentThumbnailJob private constructor(
|
||||
}
|
||||
|
||||
override fun onShouldRetry(exception: Exception): Boolean {
|
||||
if (exception is NonSuccessfulResponseCodeException) {
|
||||
if (exception.code == 404) {
|
||||
Log.w(TAG, "[$attachmentId-thumbnail] Unable to find file")
|
||||
return false
|
||||
}
|
||||
}
|
||||
return exception is IOException
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ object MediaIntentFactory {
|
||||
MediaPreviewArgs(
|
||||
threadId = mediaRecord.threadId,
|
||||
date = mediaRecord.date,
|
||||
initialMediaUri = attachment.uri!!,
|
||||
initialMediaUri = attachment.displayUri!!,
|
||||
initialMediaType = attachment.contentType,
|
||||
initialMediaSize = attachment.size,
|
||||
initialCaption = attachment.caption,
|
||||
|
||||
@@ -64,7 +64,10 @@ class MediaPreviewRepository {
|
||||
|
||||
for (i in 0..limit) {
|
||||
val element = MediaTable.MediaRecord.from(cursor)
|
||||
if (element.attachment?.transferState == AttachmentTable.TRANSFER_PROGRESS_DONE || element.attachment?.transferState == AttachmentTable.TRANSFER_PROGRESS_STARTED) {
|
||||
if (element.attachment?.transferState == AttachmentTable.TRANSFER_PROGRESS_DONE ||
|
||||
element.attachment?.transferState == AttachmentTable.TRANSFER_PROGRESS_STARTED ||
|
||||
element.attachment?.thumbnailUri != null
|
||||
) {
|
||||
mediaRecords.add(element)
|
||||
|
||||
if (startingAttachmentId.id == cursor.requireLong(AttachmentTable.ID)) {
|
||||
@@ -87,7 +90,7 @@ class MediaPreviewRepository {
|
||||
.map { it as MmsMessageRecord }
|
||||
.associate { it.id to it.resolveBody(context).getDisplayBody(context) }
|
||||
|
||||
Result(itemPosition, mediaRecords.toList(), messages)
|
||||
Result(if (mediaRecords.isNotEmpty()) itemPosition.coerceIn(mediaRecords.indices) else itemPosition, mediaRecords, messages)
|
||||
}
|
||||
}.subscribeOn(Schedulers.io()).toFlowable()
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import androidx.fragment.app.Fragment
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.attachments.Attachment
|
||||
import org.thoughtcrime.securesms.attachments.DatabaseAttachment
|
||||
import org.thoughtcrime.securesms.jobs.AttachmentDownloadJob
|
||||
import org.thoughtcrime.securesms.mediasend.Media
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import org.thoughtcrime.securesms.util.adapter.StableIdGenerator
|
||||
@@ -44,6 +46,10 @@ class MediaPreviewV2Adapter(fragment: Fragment) : FragmentStateAdapter(fragment)
|
||||
|
||||
fragment.arguments = args
|
||||
|
||||
if (attachment is DatabaseAttachment) {
|
||||
AttachmentDownloadJob.downloadAttachmentIfNeeded(attachment)
|
||||
}
|
||||
|
||||
return fragment
|
||||
}
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ class MediaPreviewV2Fragment : LoggingFragment(R.layout.fragment_media_preview_v
|
||||
val startingAttachmentId = PartAuthority.requireAttachmentId(args.initialMediaUri)
|
||||
val threadId = args.threadId
|
||||
viewModel.fetchAttachments(requireContext(), startingAttachmentId, threadId, sorting)
|
||||
val dbObserver = DatabaseObserver.Observer { viewModel.fetchAttachments(requireContext(), startingAttachmentId, threadId, sorting, true) }
|
||||
val dbObserver = DatabaseObserver.Observer { viewModel.refetchAttachments(requireContext(), startingAttachmentId, threadId, sorting) }
|
||||
AppDependencies.databaseObserver.registerAttachmentUpdatedObserver(dbObserver)
|
||||
this.dbChangeObserver = dbObserver
|
||||
}
|
||||
|
||||
@@ -68,6 +68,17 @@ class MediaPreviewV2ViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
fun refetchAttachments(context: Context, startingAttachmentId: AttachmentId, threadId: Long, sorting: MediaTable.Sorting) {
|
||||
val state = store.state
|
||||
val currentAttachmentId = if (state.position in state.mediaRecords.indices) {
|
||||
state.mediaRecords[state.position].attachment?.attachmentId
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
fetchAttachments(context, currentAttachmentId ?: startingAttachmentId, threadId, sorting, true)
|
||||
}
|
||||
|
||||
fun initialize(showThread: Boolean, allMediaInAlbumRail: Boolean, leftIsRecent: Boolean) {
|
||||
if (store.state.loadState == MediaPreviewV2State.LoadState.INIT) {
|
||||
store.update { oldState ->
|
||||
|
||||
@@ -218,6 +218,7 @@ public class PartAuthority {
|
||||
int match = uriMatcher.match(uri);
|
||||
switch (match) {
|
||||
case PART_ROW:
|
||||
case THUMBNAIL_ROW:
|
||||
case PERSISTENT_ROW:
|
||||
case BLOB_ROW:
|
||||
return true;
|
||||
@@ -226,7 +227,8 @@ public class PartAuthority {
|
||||
}
|
||||
|
||||
public static boolean isAttachmentUri(@NonNull Uri uri) {
|
||||
return uriMatcher.match(uri) == PART_ROW;
|
||||
int match = uriMatcher.match(uri);
|
||||
return match == PART_ROW || match == THUMBNAIL_ROW;
|
||||
}
|
||||
|
||||
public static @NonNull AttachmentId requireAttachmentId(@NonNull Uri uri) {
|
||||
|
||||
Reference in New Issue
Block a user