From 683b5243bdc836caa099a4d2175f506e2e1e7b43 Mon Sep 17 00:00:00 2001 From: Harris Date: Wed, 7 Jul 2021 14:56:53 +1000 Subject: [PATCH 1/2] fix: notify update for attachment's thread ID on setting audio extras --- .../attachments/DatabaseAttachmentProvider.kt | 17 +++++++++++------ .../securesms/database/AttachmentDatabase.java | 17 +++++++++++++++-- .../libsession/database/MessageDataProvider.kt | 2 +- .../messaging/jobs/AttachmentDownloadJob.kt | 9 +++++---- .../messaging/jobs/AttachmentUploadJob.kt | 12 ++++-------- 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt index 18b5ff78f5..47e4136656 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt @@ -9,12 +9,12 @@ import org.session.libsession.messaging.sending_receiving.attachments.* import org.session.libsession.utilities.Address import org.session.libsession.utilities.UploadResult import org.session.libsession.utilities.Util -import org.session.libsignal.utilities.guava.Optional import org.session.libsignal.messages.SignalServiceAttachment import org.session.libsignal.messages.SignalServiceAttachmentPointer import org.session.libsignal.messages.SignalServiceAttachmentStream import org.session.libsignal.utilities.Base64 import org.session.libsignal.utilities.Log +import org.session.libsignal.utilities.guava.Optional import org.thoughtcrime.securesms.database.AttachmentDatabase import org.thoughtcrime.securesms.database.Database import org.thoughtcrime.securesms.database.DatabaseFactory @@ -97,11 +97,16 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper) attachmentDatabase.insertAttachmentsForPlaceholder(messageId, attachmentId, stream) } - override fun updateAudioAttachmentDuration(attachmentId: AttachmentId, durationMs: Long) { - DatabaseFactory.getAttachmentDatabase(context).setAttachmentAudioExtras(DatabaseAttachmentAudioExtras( - attachmentId = attachmentId, - visualSamples = byteArrayOf(), - durationMs = durationMs + override fun updateAudioAttachmentDuration( + attachmentId: AttachmentId, + durationMs: Long, + threadId: Long + ) { + val attachmentDb = DatabaseFactory.getAttachmentDatabase(context) + attachmentDb.setAttachmentAudioExtras(DatabaseAttachmentAudioExtras( + attachmentId = attachmentId, + visualSamples = byteArrayOf(), + durationMs = durationMs )) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java index 4b20ee202e..2f85f27d52 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java @@ -44,8 +44,8 @@ import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAt import org.session.libsession.messaging.sending_receiving.attachments.DatabaseAttachmentAudioExtras; import org.session.libsession.utilities.MediaTypes; import org.session.libsession.utilities.Util; -import org.session.libsignal.utilities.JsonUtil; import org.session.libsignal.utilities.ExternalStorageUtil; +import org.session.libsignal.utilities.JsonUtil; import org.session.libsignal.utilities.Log; import org.thoughtcrime.securesms.crypto.AttachmentSecret; import org.thoughtcrime.securesms.crypto.ClassicDecryptingPartInputStream; @@ -820,7 +820,7 @@ public class AttachmentDatabase extends Database { * @return true if the update operation was successful. */ @Synchronized - public boolean setAttachmentAudioExtras(@NonNull DatabaseAttachmentAudioExtras extras) { + public boolean setAttachmentAudioExtras(@NonNull DatabaseAttachmentAudioExtras extras, long threadId) { ContentValues values = new ContentValues(); values.put(AUDIO_VISUAL_SAMPLES, extras.getVisualSamples()); values.put(AUDIO_DURATION, extras.getDurationMs()); @@ -830,9 +830,22 @@ public class AttachmentDatabase extends Database { PART_ID_WHERE + " AND " + PART_AUDIO_ONLY_WHERE, extras.getAttachmentId().toStrings()); + if (threadId >= 0) { + notifyConversationListeners(threadId); + } + return alteredRows > 0; } + /** + * Updates audio extra columns for the "audio/*" mime type attachments only. + * @return true if the update operation was successful. + */ + @Synchronized + public boolean setAttachmentAudioExtras(@NonNull DatabaseAttachmentAudioExtras extras) { + return setAttachmentAudioExtras(extras, -1); // -1 for no update + } + @VisibleForTesting class ThumbnailFetchCallable implements Callable { diff --git a/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt b/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt index 37d6d44e4a..39ca4854ce 100644 --- a/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt +++ b/libsession/src/main/java/org/session/libsession/database/MessageDataProvider.kt @@ -20,7 +20,7 @@ interface MessageDataProvider { fun getSignalAttachmentPointer(attachmentId: Long): SignalServiceAttachmentPointer? fun setAttachmentState(attachmentState: AttachmentState, attachmentId: Long, messageID: Long) fun insertAttachment(messageId: Long, attachmentId: AttachmentId, stream : InputStream) - fun updateAudioAttachmentDuration(attachmentId: AttachmentId, durationMs: Long) + fun updateAudioAttachmentDuration(attachmentId: AttachmentId, durationMs: Long, threadId: Long) fun isOutgoingMessage(timestamp: Long): Boolean fun handleSuccessfulAttachmentUpload(attachmentId: Long, attachmentStream: SignalServiceAttachmentStream, attachmentKey: ByteArray, uploadResult: UploadResult) fun handleFailedAttachmentUpload(attachmentId: Long) diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt index 605052f85c..d0a09dc771 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt @@ -1,8 +1,5 @@ package org.session.libsession.messaging.jobs -import android.content.ContentResolver -import android.media.MediaDataSource -import android.media.MediaExtractor import okhttp3.HttpUrl import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.open_groups.OpenGroupAPIV2 @@ -78,7 +75,11 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long) try { InputStreamMediaDataSource(getInputStream(tempFile, attachment)).use { mediaDataSource -> val durationMs = (DecodedAudio.create(mediaDataSource).totalDuration / 1000.0).toLong() - messageDataProvider.updateAudioAttachmentDuration(attachment.attachmentId, durationMs) + messageDataProvider.updateAudioAttachmentDuration( + attachment.attachmentId, + durationMs, + threadID + ) } } catch (e: Exception) { Log.e("Loki", "Couldn't process audio attachment", e) diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt index 332d674115..02475c39cb 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentUploadJob.kt @@ -14,15 +14,11 @@ import org.session.libsession.messaging.utilities.Data import org.session.libsession.utilities.DecodedAudio import org.session.libsession.utilities.InputStreamMediaDataSource import org.session.libsession.utilities.UploadResult -import org.session.libsignal.streams.AttachmentCipherOutputStream import org.session.libsignal.messages.SignalServiceAttachmentStream -import org.session.libsignal.streams.PaddingInputStream -import org.session.libsignal.utilities.PushAttachmentData -import org.session.libsignal.streams.AttachmentCipherOutputStreamFactory -import org.session.libsignal.streams.DigestingRequestBody -import org.session.libsignal.utilities.Util -import org.session.libsignal.streams.PlaintextOutputStreamFactory +import org.session.libsignal.streams.* import org.session.libsignal.utilities.Log +import org.session.libsignal.utilities.PushAttachmentData +import org.session.libsignal.utilities.Util class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val message: Message, val messageSendJobID: String) : Job { override var delegate: JobDelegate? = null @@ -119,7 +115,7 @@ class AttachmentUploadJob(val attachmentID: Long, val threadID: String, val mess InputStreamMediaDataSource(inputStream).use { mediaDataSource -> val durationMs = (DecodedAudio.create(mediaDataSource).totalDuration / 1000.0).toLong() messageDataProvider.getDatabaseAttachment(attachmentID)?.attachmentId?.let { attachmentId -> - messageDataProvider.updateAudioAttachmentDuration(attachmentId, durationMs) + messageDataProvider.updateAudioAttachmentDuration(attachmentId, durationMs, threadID.toLong()) } } } catch (e: Exception) { From ce490f5f90297f0a5d00bb252c90e77dba804edd Mon Sep 17 00:00:00 2001 From: Harris Date: Wed, 7 Jul 2021 15:18:12 +1000 Subject: [PATCH 2/2] fix: avoid crash in voice message view for pending downloads, display the icon on player stop when player starting from another view. Use thread id in setAttachmentAudioExtras --- .../attachments/DatabaseAttachmentProvider.kt | 2 +- .../v2/messages/VoiceMessageView.kt | 30 ++++++++++++++----- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt index 47e4136656..12a76739cf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/attachments/DatabaseAttachmentProvider.kt @@ -107,7 +107,7 @@ class DatabaseAttachmentProvider(context: Context, helper: SQLCipherOpenHelper) attachmentId = attachmentId, visualSamples = byteArrayOf(), durationMs = durationMs - )) + ), threadId) } override fun isOutgoingMessage(timestamp: Long): Boolean { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt index 894a078b30..72023d56c7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/VoiceMessageView.kt @@ -4,7 +4,8 @@ import android.content.Context import android.graphics.Canvas import android.util.AttributeSet import android.util.Log -import android.view.* +import android.view.LayoutInflater +import android.view.View import android.widget.LinearLayout import android.widget.RelativeLayout import androidx.core.view.isVisible @@ -23,6 +24,10 @@ import kotlin.math.roundToLong class VoiceMessageView : LinearLayout, AudioSlidePlayer.Listener { private val cornerMask by lazy { CornerMask(this) } private var isPlaying = false + set(value) { + field = value + renderIcon() + } private var progress = 0.0 private var duration = 0L private var player: AudioSlidePlayer? = null @@ -44,8 +49,6 @@ class VoiceMessageView : LinearLayout, AudioSlidePlayer.Listener { // region Updating fun bind(message: MmsMessageRecord, isStartOfMessageCluster: Boolean, isEndOfMessageCluster: Boolean) { val audio = message.slideDeck.audioSlide!! - val player = AudioSlidePlayer.createFor(context, audio, this) - this.player = player voiceMessageViewLoader.isVisible = audio.isPendingDownload val cornerRadii = MessageBubbleUtilities.calculateRadii(context, isStartOfMessageCluster, isEndOfMessageCluster, message.isOutgoing) cornerMask.setTopLeftRadius(cornerRadii[0]) @@ -54,7 +57,13 @@ class VoiceMessageView : LinearLayout, AudioSlidePlayer.Listener { cornerMask.setBottomLeftRadius(cornerRadii[3]) // only process audio if downloaded - if (audio.isPendingDownload || audio.isInProgress) return + if (audio.isPendingDownload || audio.isInProgress) { + this.player = null + return + } + + val player = AudioSlidePlayer.createFor(context, audio, this) + this.player = player (audio.asAttachment() as? DatabaseAttachment)?.let { attachment -> DatabaseFactory.getAttachmentDatabase(context).getAttachmentAudioExtras(attachment.attachmentId)?.let { audioExtras -> @@ -90,20 +99,27 @@ class VoiceMessageView : LinearLayout, AudioSlidePlayer.Listener { progressView.layoutParams = layoutParams } - override fun onPlayerStop(player: AudioSlidePlayer) { } + override fun onPlayerStop(player: AudioSlidePlayer) { + Log.d("Loki", "Player stopped") + isPlaying = false + } override fun dispatchDraw(canvas: Canvas) { super.dispatchDraw(canvas) cornerMask.mask(canvas) } + + private fun renderIcon() { + val iconID = if (isPlaying) R.drawable.exo_icon_pause else R.drawable.exo_icon_play + voiceMessagePlaybackImageView.setImageResource(iconID) + } + // endregion // region Interaction fun togglePlayback() { val player = this.player ?: return isPlaying = !isPlaying - val iconID = if (isPlaying) R.drawable.exo_icon_pause else R.drawable.exo_icon_play - voiceMessagePlaybackImageView.setImageResource(iconID) if (isPlaying) { player.play(progress) } else {