diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt index d6b65f65ab..1c9bc25465 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt @@ -1941,6 +1941,10 @@ class ConversationFragment : onComplete = { onSendComplete() afterSendComplete() + }, + onError = { + Log.w(TAG, "Error received during send!", it) + toast(R.string.ConversationActivity_error_sending_media) } ) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationRepository.kt index 888c1fa820..f947963c3a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationRepository.kt @@ -225,7 +225,7 @@ class ConversationRepository( emitter.onComplete() } } else { - MessageSender.sendPushWithPreUploadedMedia( + val sendSuccessful = MessageSender.sendPushWithPreUploadedMedia( AppDependencies.application, message, preUploadResults, @@ -233,6 +233,10 @@ class ConversationRepository( ) { emitter.onComplete() } + + if (!sendSuccessful) { + emitter.tryOnError(IllegalStateException("Could not send pre-uploaded attachments because they did not exist!")) + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt index ecfb35378f..e7ad7290a0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentTable.kt @@ -36,6 +36,7 @@ import org.signal.core.util.Base64 import org.signal.core.util.SqlUtil import org.signal.core.util.StreamUtil import org.signal.core.util.ThreadUtil +import org.signal.core.util.count import org.signal.core.util.delete import org.signal.core.util.deleteAll import org.signal.core.util.drain @@ -45,6 +46,7 @@ import org.signal.core.util.groupBy import org.signal.core.util.isNull import org.signal.core.util.logging.Log import org.signal.core.util.readToList +import org.signal.core.util.readToSingleInt import org.signal.core.util.readToSingleLong import org.signal.core.util.readToSingleObject import org.signal.core.util.requireBlob @@ -433,6 +435,20 @@ class AttachmentTable( .run() } + /** + * Takes a list of attachment IDs and confirms they exist in the database. + */ + fun hasAttachments(ids: List): Boolean { + return ids.size == SqlUtil.buildCollectionQuery(ID, ids.map { it.id }).sumOf { query -> + readableDatabase + .count() + .from(TABLE_NAME) + .where(query.where, query.whereArgs) + .run() + .readToSingleInt(defaultValue = 0) + } + } + fun getPendingAttachments(): List { return readableDatabase .select(*PROJECTION) @@ -1103,7 +1119,7 @@ class AttachmentTable( @Throws(MmsException::class) fun insertAttachmentForPreUpload(attachment: Attachment): DatabaseAttachment { - Log.d(TAG, "Inserting attachment $attachment for pre-upload.") + Log.d(TAG, "Inserting attachment ${attachment.uri} for pre-upload.") val result = insertAttachmentsForMessage(PREUPLOAD_MESSAGE_ID, listOf(attachment), emptyList()) if (result.values.isEmpty()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentCompressionJob.java b/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentCompressionJob.java index 4d8dfa8746..67b158197b 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentCompressionJob.java +++ b/app/src/main/java/org/thoughtcrime/securesms/jobs/AttachmentCompressionJob.java @@ -227,12 +227,17 @@ public final class AttachmentCompressionJob extends BaseJob { @NonNull TranscoderCancelationSignal cancelationSignal) throws UndeliverableMessageException { + + if (cancelationSignal.isCanceled()) { + throw new UndeliverableMessageException("Job is canceled!"); + } + AttachmentTable.TransformProperties transformProperties = attachment.transformProperties; boolean allowSkipOnFailure = false; if (!MediaConstraints.isVideoTranscodeAvailable()) { - if (transformProperties.getVideoEdited()) { + if (transformProperties != null && transformProperties.getVideoEdited()) { throw new UndeliverableMessageException("Video edited, but transcode is not available"); } return attachment; @@ -284,6 +289,9 @@ public final class AttachmentCompressionJob extends BaseJob { PartProgressEvent.Type.COMPRESSION, 100, 100)); + if (cancelationSignal.isCanceled()) { + throw new UndeliverableMessageException("Job is canceled!"); + } final Mp4FaststartPostProcessor postProcessor = new Mp4FaststartPostProcessor(() -> { try { @@ -355,7 +363,7 @@ public final class AttachmentCompressionJob extends BaseJob { } } } catch (VideoSourceException | EncodingException | MemoryFileException e) { - if (attachment.size > constraints.getVideoMaxSize(context)) { + if (attachment.size > constraints.getVideoMaxSize()) { throw new UndeliverableMessageException("Duration not found, attachment too large to skip transcode", e); } else { if (allowSkipOnFailure) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaUploadRepository.java b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaUploadRepository.java index 1789d163ad..affa2c3508 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaUploadRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/MediaUploadRepository.java @@ -166,7 +166,7 @@ public class MediaUploadRepository { PreUploadResult result = uploadResults.get(media); if (result != null) { - Log.d(TAG, "Canceling upload jobs for " + result.getJobIds().size() + " media items."); + Log.d(TAG, "Canceling attachment upload job for " + result.getAttachmentId()); Stream.of(result.getJobIds()).forEach(jobManager::cancel); uploadResults.remove(media); SignalDatabase.attachments().deleteAttachment(result.getAttachmentId()); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionState.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionState.kt index 3f107a07f9..6537014819 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionState.kt @@ -12,6 +12,7 @@ import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.util.MediaUtil import org.thoughtcrime.securesms.util.RemoteConfig import org.thoughtcrime.securesms.video.TranscodingPreset +import kotlin.time.Duration.Companion.seconds data class MediaSelectionState( val sendType: MessageSendType, @@ -44,6 +45,14 @@ data class MediaSelectionState( return editorStateMap[uri] as? VideoTrimData ?: VideoTrimData() } + fun calculateMaxVideoDurationUs(maxFileSize: Long): Long { + return if (isStory && !MediaConstraints.isVideoTranscodeAvailable()) { + Stories.MAX_VIDEO_DURATION_MILLIS + } else { + transcodingPreset.calculateMaxVideoUploadDurationInSeconds(maxFileSize).seconds.inWholeMicroseconds + } + } + enum class ViewOnceToggleState(val code: Int) { INFINITE(0), ONCE(1); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt index ca4354eab2..26ddcc505c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/MediaSelectionViewModel.kt @@ -46,7 +46,6 @@ import org.thoughtcrime.securesms.util.livedata.Store import java.util.Collections import kotlin.math.max import kotlin.time.Duration.Companion.milliseconds -import kotlin.time.Duration.Companion.seconds /** * ViewModel which maintains the list of selected media and other shared values. @@ -127,7 +126,7 @@ class MediaSelectionViewModel( } if (initialMedia.isNotEmpty()) { - addMedia(initialMedia) + addMedia(initialMedia.toSet()) } disposables += selectedMediaSubject @@ -165,7 +164,7 @@ class MediaSelectionViewModel( } fun addMedia(media: Media) { - addMedia(listOf(media)) + addMedia(setOf(media)) } fun isStory(): Boolean { @@ -176,7 +175,7 @@ class MediaSelectionViewModel( return store.state.storySendRequirements } - private fun addMedia(media: List) { + private fun addMedia(media: Set) { val newSelectionList: List = linkedSetOf().apply { addAll(store.state.selectedMedia) addAll(media) @@ -188,11 +187,16 @@ class MediaSelectionViewModel( .subscribe { filterResult -> if (filterResult.filteredMedia.isNotEmpty()) { store.update { + val maxDuration = it.calculateMaxVideoDurationUs(getMediaConstraints().getVideoMaxSize()) val initializedVideoEditorStates = filterResult.filteredMedia.filterNot { media -> it.editorStateMap.containsKey(media.uri) } .filter { media -> MediaUtil.isNonGifVideo(media) } .associate { video: Media -> val duration = video.duration.milliseconds.inWholeMicroseconds - video.uri to VideoTrimData(false, duration, 0, duration) + if (duration < maxDuration) { + video.uri to VideoTrimData(false, duration, 0, duration) + } else { + video.uri to VideoTrimData(true, duration, 0, maxDuration) + } } it.copy( selectedMedia = filterResult.filteredMedia, @@ -341,7 +345,7 @@ class MediaSelectionViewModel( store.update { it.copy(viewOnceToggleState = it.viewOnceToggleState.next()) } } - fun onEditVideoDuration(context: Context, totalDurationUs: Long, startTimeUs: Long, endTimeUs: Long, touchEnabled: Boolean) { + fun onEditVideoDuration(totalDurationUs: Long, startTimeUs: Long, endTimeUs: Long, touchEnabled: Boolean) { store.update { val uri = it.focusedMedia?.uri ?: return@update it val data = it.getOrCreateVideoTrimData(uri) @@ -351,27 +355,30 @@ class MediaSelectionViewModel( val durationEdited = clampedStartTime > 0 || endTimeUs < totalDurationUs val isEntireDuration = startTimeUs == 0L && endTimeUs == totalDurationUs val endMoved = !isEntireDuration && data.endTimeUs != endTimeUs - val maxVideoDurationUs: Long = if (it.isStory && !MediaConstraints.isVideoTranscodeAvailable()) { - Stories.MAX_VIDEO_DURATION_MILLIS - } else { - it.transcodingPreset.calculateMaxVideoUploadDurationInSeconds(getMediaConstraints().getVideoMaxSize(context)).seconds.inWholeMicroseconds - } + val maxVideoDurationUs: Long = it.calculateMaxVideoDurationUs(getMediaConstraints().getVideoMaxSize()) val preserveStartTime = unedited || !endMoved val videoTrimData = VideoTrimData(durationEdited, totalDurationUs, clampedStartTime, endTimeUs) val updatedData = clampToMaxClipDuration(videoTrimData, maxVideoDurationUs, preserveStartTime) if (updatedData != videoTrimData) { - Log.d(TAG, "Video trim clamped from ${videoTrimData.startTimeUs}, ${videoTrimData.endTimeUs} to ${updatedData.startTimeUs}, ${updatedData.endTimeUs}") + Log.d(TAG, "Video attachment trim clamped from ${videoTrimData.startTimeUs}, ${videoTrimData.endTimeUs} to ${updatedData.startTimeUs}, ${updatedData.endTimeUs}") } if (unedited && durationEdited) { - Log.d(TAG, "Canceling upload because the duration has been edited for the first time..") + Log.d(TAG, "Canceling attachment upload because the duration has been edited for the first time..") cancelUpload(MediaBuilder.buildMedia(uri)) } - it.copy( - isTouchEnabled = touchEnabled, - editorStateMap = it.editorStateMap + (uri to updatedData) - ) + + if (updatedData != data) { + Log.d(TAG, "Updating video attachment trim data for $uri") + it.copy( + isTouchEnabled = touchEnabled, + editorStateMap = it.editorStateMap + (uri to updatedData) + ) + } else { + Log.d(TAG, "Preserving video attachment trim data for $uri") + it.copy(isTouchEnabled = touchEnabled) + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/review/MediaReviewFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/review/MediaReviewFragment.kt index 8455318176..f5380db64d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/review/MediaReviewFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/review/MediaReviewFragment.kt @@ -114,8 +114,8 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul private var disposables: LifecycleDisposable = LifecycleDisposable() private var sentMediaQuality: SentMediaQuality = SignalStore.settings.sentMediaQuality private var viewOnceToggleState: MediaSelectionState.ViewOnceToggleState = MediaSelectionState.ViewOnceToggleState.default - private var scheduledSendTime: Long? = null + private var readyToSend = true override fun onViewCreated(view: View, savedInstanceState: Bundle?) { postponeEnterTransition() @@ -202,6 +202,14 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } sendButton.setOnClickListener { + if (!readyToSend) { + Log.d(TAG, "Attachment send button not currently enabled. Ignoring click event.") + return@setOnClickListener + } else { + Log.d(TAG, "Attachment send button enabled. Processing click event.") + readyToSend = false + } + val viewOnce: Boolean = sharedViewModel.state.value?.viewOnceToggleState == MediaSelectionState.ViewOnceToggleState.ONCE if (sharedViewModel.isContactSelectionRequired) { @@ -216,7 +224,7 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul val snapshot = sharedViewModel.state.value if (snapshot != null) { - sendButton.isEnabled = false + readyToSend = false SimpleTask.run(viewLifecycleOwner.lifecycle, { snapshot.selectedMedia.take(2).map { media -> val editorData = snapshot.editorStateMap[media.uri] @@ -232,7 +240,6 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } } }, { - sendButton.isEnabled = true storiesLauncher.launch(StoriesMultiselectForwardActivity.Args(args, it)) }) } else { @@ -249,7 +256,15 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul Log.d(TAG, "Performing send add to group story dialog.") performSend() } - .setNegativeButton(android.R.string.cancel) { _, _ -> } + .setNegativeButton(android.R.string.cancel) { _, _ -> + readyToSend = true + } + .setOnCancelListener { + readyToSend = true + } + .setOnDismissListener { + readyToSend = true + } .show() scheduledSendTime = null } else { @@ -325,7 +340,7 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul state.selectedMedia.map { MediaReviewSelectedItem.Model(it, state.focusedMedia == it) } + MediaReviewAddItem.Model ) - presentSendButton(state.sendType, state.recipient) + presentSendButton(readyToSend, state.sendType, state.recipient) presentPager(state) presentAddMessageEntry(state.viewOnceToggleState, state.message) presentImageQualityToggle(state) @@ -449,6 +464,8 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } private fun performSend(selection: List = listOf()) { + Log.d(TAG, "Performing attachment send.") + readyToSend = false progressWrapper.visible = true progressWrapper.animate() .setStartDelay(300) @@ -456,11 +473,20 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul .alpha(1f) disposables += sharedViewModel - .send(selection.filterIsInstance(ContactSearchKey.RecipientSearchKey::class.java), scheduledSendTime) + .send(selection.filterIsInstance(), scheduledSendTime) .subscribe( - { result -> callback.onSentWithResult(result) }, - { error -> callback.onSendError(error) }, - { callback.onSentWithoutResult() } + { result -> + callback.onSentWithResult(result) + readyToSend = true + }, + { error -> + callback.onSendError(error) + readyToSend = true + }, + { + callback.onSentWithoutResult() + readyToSend = true + } ) } @@ -500,8 +526,9 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul ) } - private fun presentSendButton(sendType: MessageSendType, recipient: Recipient?) { + private fun presentSendButton(enabled: Boolean, sendType: MessageSendType, recipient: Recipient?) { val sendButtonBackgroundTint = when { + !enabled -> ContextCompat.getColor(requireContext(), R.color.core_grey_50) recipient != null -> recipient.chatColors.asSingleColor() sendType.usesSignalTransport -> ContextCompat.getColor(requireContext(), R.color.signal_colorOnSecondaryContainer) else -> ContextCompat.getColor(requireContext(), R.color.core_grey_50) @@ -513,6 +540,7 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } val sendButtonForegroundTint = when { + !enabled -> ContextCompat.getColor(requireContext(), R.color.signal_colorSecondaryContainer) recipient != null -> ContextCompat.getColor(requireContext(), R.color.signal_colorOnCustom) else -> ContextCompat.getColor(requireContext(), R.color.signal_colorSecondaryContainer) } @@ -549,7 +577,7 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul videoTimeLine.unregisterDragListener() } val size: Long = tryGetUriSize(requireContext(), uri, Long.MAX_VALUE) - val maxSend = sharedViewModel.getMediaConstraints().getVideoMaxSize(requireContext()) + val maxSend = sharedViewModel.getMediaConstraints().getVideoMaxSize() if (size > maxSend) { videoTimeLine.setTimeLimit(state.transcodingPreset.calculateMaxVideoUploadDurationInSeconds(maxSend), TimeUnit.SECONDS) } @@ -791,6 +819,6 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment), Schedul } override fun onRangeDrag(minValue: Long, maxValue: Long, duration: Long, end: Boolean) { - sharedViewModel.onEditVideoDuration(context = requireContext(), totalDurationUs = duration, startTimeUs = minValue, endTimeUs = maxValue, touchEnabled = end) + sharedViewModel.onEditVideoDuration(totalDurationUs = duration, startTimeUs = minValue, endTimeUs = maxValue, touchEnabled = end) } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/videos/MediaReviewVideoPageFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/videos/MediaReviewVideoPageFragment.kt index 0bcad54282..9e35a73f30 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/videos/MediaReviewVideoPageFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/videos/MediaReviewVideoPageFragment.kt @@ -76,7 +76,7 @@ class MediaReviewVideoPageFragment : Fragment(R.layout.fragment_container), Vide } private fun requireUri(): Uri = requireNotNull(requireArguments().getParcelableCompat(ARG_URI, Uri::class.java)) - private fun requireMaxAttachmentSize(): Long = sharedViewModel.getMediaConstraints().getVideoMaxSize(requireContext()) + private fun requireMaxAttachmentSize(): Long = sharedViewModel.getMediaConstraints().getVideoMaxSize() private fun requireIsVideoGif(): Boolean = requireNotNull(requireArguments().getBoolean(ARG_IS_VIDEO_GIF)) companion object { diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/MediaConstraints.java b/app/src/main/java/org/thoughtcrime/securesms/mms/MediaConstraints.java index 5e49e0a70a..3c5fb5fccd 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/MediaConstraints.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/MediaConstraints.java @@ -49,18 +49,18 @@ public abstract class MediaConstraints { public abstract int[] getImageDimensionTargets(Context context); public abstract long getGifMaxSize(Context context); - public abstract long getVideoMaxSize(Context context); + public abstract long getVideoMaxSize(); public @IntRange(from = 0, to = 100) int getImageCompressionQualitySetting(@NonNull Context context) { return 70; } public long getUncompressedVideoMaxSize(Context context) { - return getVideoMaxSize(context); + return getVideoMaxSize(); } public long getCompressedVideoMaxSize(Context context) { - return getVideoMaxSize(context); + return getVideoMaxSize(); } public abstract long getAudioMaxSize(Context context); @@ -79,7 +79,7 @@ public abstract class MediaConstraints { return (MediaUtil.isGif(attachment) && size <= getGifMaxSize(context) && isWithinBounds(context, attachment.getUri())) || (MediaUtil.isImage(attachment) && size <= getImageMaxSize(context) && isWithinBounds(context, attachment.getUri())) || (MediaUtil.isAudio(attachment) && size <= getAudioMaxSize(context)) || - (MediaUtil.isVideo(attachment) && size <= getVideoMaxSize(context)) || + (MediaUtil.isVideo(attachment) && size <= getVideoMaxSize()) || (MediaUtil.isFile(attachment) && size <= getDocumentMaxSize(context)); } catch (IOException ioe) { Log.w(TAG, "Failed to determine if media's constraints are satisfied.", ioe); @@ -95,7 +95,7 @@ public abstract class MediaConstraints { return (MediaUtil.isGif(contentType) && size <= getGifMaxSize(context) && isWithinBounds(context, uri)) || (MediaUtil.isImageType(contentType) && size <= getImageMaxSize(context) && isWithinBounds(context, uri)) || (MediaUtil.isAudioType(contentType) && size <= getAudioMaxSize(context)) || - (MediaUtil.isVideoType(contentType) && size <= getVideoMaxSize(context)) || + (MediaUtil.isVideoType(contentType) && size <= getVideoMaxSize()) || size <= getDocumentMaxSize(context); } catch (IOException ioe) { Log.w(TAG, "Failed to determine if media's constraints are satisfied.", ioe); diff --git a/app/src/main/java/org/thoughtcrime/securesms/mms/PushMediaConstraints.java b/app/src/main/java/org/thoughtcrime/securesms/mms/PushMediaConstraints.java index c57874c1bb..28a3ddfcda 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mms/PushMediaConstraints.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mms/PushMediaConstraints.java @@ -53,14 +53,14 @@ public class PushMediaConstraints extends MediaConstraints { } @Override - public long getVideoMaxSize(Context context) { + public long getVideoMaxSize() { return getMaxAttachmentSize(); } @Override public long getUncompressedVideoMaxSize(Context context) { return isVideoTranscodeAvailable() ? RemoteConfig.maxSourceTranscodeVideoSizeBytes() - : getVideoMaxSize(context); + : getVideoMaxSize(); } @Override diff --git a/app/src/main/java/org/thoughtcrime/securesms/profiles/ProfileMediaConstraints.java b/app/src/main/java/org/thoughtcrime/securesms/profiles/ProfileMediaConstraints.java index 352b5220b7..1bdac31163 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/profiles/ProfileMediaConstraints.java +++ b/app/src/main/java/org/thoughtcrime/securesms/profiles/ProfileMediaConstraints.java @@ -32,7 +32,7 @@ public class ProfileMediaConstraints extends MediaConstraints { } @Override - public long getVideoMaxSize(Context context) { + public long getVideoMaxSize() { return 0; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java b/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java index 47048dde9e..92bf90b530 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java +++ b/app/src/main/java/org/thoughtcrime/securesms/sms/MessageSender.java @@ -52,10 +52,10 @@ import org.thoughtcrime.securesms.jobs.AttachmentCompressionJob; import org.thoughtcrime.securesms.jobs.AttachmentCopyJob; import org.thoughtcrime.securesms.jobs.AttachmentMarkUploadedJob; import org.thoughtcrime.securesms.jobs.AttachmentUploadJob; +import org.thoughtcrime.securesms.jobs.IndividualSendJob; import org.thoughtcrime.securesms.jobs.ProfileKeySendJob; import org.thoughtcrime.securesms.jobs.PushDistributionListSendJob; import org.thoughtcrime.securesms.jobs.PushGroupSendJob; -import org.thoughtcrime.securesms.jobs.IndividualSendJob; import org.thoughtcrime.securesms.jobs.ReactionSendJob; import org.thoughtcrime.securesms.jobs.RemoteDeleteSendJob; import org.thoughtcrime.securesms.keyvalue.SignalStore; @@ -251,12 +251,11 @@ public class MessageSender { } } - public static long sendPushWithPreUploadedMedia(final Context context, - final OutgoingMessage message, - final Collection preUploadResults, - final long threadId, - final MessageTable.InsertListener insertListener) - { + public static boolean sendPushWithPreUploadedMedia(final Context context, + final OutgoingMessage message, + final Collection preUploadResults, + final long threadId, + final MessageTable.InsertListener insertListener) { Log.i(TAG, "Sending media message with pre-uploads to " + message.getThreadRecipient().getId() + ", thread: " + threadId + ", pre-uploads: " + preUploadResults); Preconditions.checkArgument(message.getAttachments().isEmpty(), "If the media is pre-uploaded, there should be no attachments on the message."); @@ -267,24 +266,30 @@ public class MessageSender { Recipient recipient = message.getThreadRecipient(); long allocatedThreadId = threadTable.getOrCreateValidThreadId(message.getThreadRecipient(), threadId); - long messageId = mmsDatabase.insertMessageOutbox(applyUniversalExpireTimerIfNecessary(context, recipient, message, allocatedThreadId), - allocatedThreadId, - false, - insertListener); List attachmentIds = Stream.of(preUploadResults).map(PreUploadResult::getAttachmentId).toList(); List jobIds = Stream.of(preUploadResults).map(PreUploadResult::getJobIds).flatMap(Stream::of).toList(); + if (!attachmentDatabase.hasAttachments(attachmentIds)) { + Log.w(TAG, "Attachments not found in database for " + message.getThreadRecipient().getId() + ", thread: " + threadId + ", pre-uploads: " + preUploadResults); + return false; + } + + long messageId = mmsDatabase.insertMessageOutbox(applyUniversalExpireTimerIfNecessary(context, recipient, message, allocatedThreadId), + allocatedThreadId, + false, + insertListener); + attachmentDatabase.updateMessageId(attachmentIds, messageId, message.getStoryType().isStory()); sendMessageInternal(context, recipient, SendType.SIGNAL, messageId, jobIds, false); onMessageSent(); threadTable.update(allocatedThreadId, true, true); - return allocatedThreadId; + return true; } catch (MmsException e) { Log.w(TAG, e); - return threadId; + return false; } }