diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNoteMediaDescriptionCompatFactory.java b/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNoteMediaDescriptionCompatFactory.java index e2ce0260a..67903ab3c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNoteMediaDescriptionCompatFactory.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNoteMediaDescriptionCompatFactory.java @@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.database.model.MmsMessageRecord; import org.thoughtcrime.securesms.keyvalue.SignalStore; +import org.thoughtcrime.securesms.mms.AudioSlide; import org.thoughtcrime.securesms.preferences.widgets.NotificationPrivacyPreference; import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.DateUtils; @@ -70,8 +71,8 @@ class VoiceNoteMediaDescriptionCompatFactory { * @return A MediaDescriptionCompat with all the details the service expects. */ @WorkerThread - static MediaDescriptionCompat buildMediaDescription(@NonNull Context context, - @NonNull MessageRecord messageRecord) + @Nullable static MediaDescriptionCompat buildMediaDescription(@NonNull Context context, + @NonNull MessageRecord messageRecord) { int startingPosition = DatabaseFactory.getMmsSmsDatabase(context) .getMessagePositionInConversation(messageRecord.getThreadId(), @@ -79,9 +80,20 @@ class VoiceNoteMediaDescriptionCompatFactory { Recipient threadRecipient = Objects.requireNonNull(DatabaseFactory.getThreadDatabase(context) .getRecipientForThreadId(messageRecord.getThreadId())); - Recipient sender = messageRecord.isOutgoing() ? Recipient.self() : messageRecord.getIndividualRecipient(); - Recipient avatarRecipient = threadRecipient.isGroup() ? threadRecipient : sender; - Uri uri = Objects.requireNonNull(((MmsMessageRecord) messageRecord).getSlideDeck().getAudioSlide().getUri()); + Recipient sender = messageRecord.isOutgoing() ? Recipient.self() : messageRecord.getIndividualRecipient(); + Recipient avatarRecipient = threadRecipient.isGroup() ? threadRecipient : sender; + AudioSlide audioSlide = ((MmsMessageRecord) messageRecord).getSlideDeck().getAudioSlide(); + + if (audioSlide == null) { + Log.w(TAG, "Message does not have an audio slide. Can't play this voice note."); + return null; + } + + Uri uri = audioSlide.getUri(); + if (uri == null) { + Log.w(TAG, "Audio slide does not have a URI. Can't play this voice note."); + return null; + } return buildMediaDescription(context, threadRecipient, diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNotePlaybackPreparer.java b/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNotePlaybackPreparer.java index dc3efe442..bc97372d6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNotePlaybackPreparer.java +++ b/app/src/main/java/org/thoughtcrime/securesms/components/voice/VoiceNotePlaybackPreparer.java @@ -6,6 +6,7 @@ import android.os.Bundle; import android.os.ResultReceiver; import android.support.v4.media.MediaDescriptionCompat; import android.support.v4.media.session.PlaybackStateCompat; +import android.widget.Toast; import androidx.annotation.MainThread; import androidx.annotation.NonNull; @@ -19,7 +20,9 @@ import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; import com.google.android.exoplayer2.source.ConcatenatingMediaSource; +import org.signal.core.util.ThreadUtil; import org.signal.core.util.logging.Log; +import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.database.DatabaseFactory; import org.thoughtcrime.securesms.database.NoSuchMessageException; import org.thoughtcrime.securesms.database.model.MessageRecord; @@ -35,6 +38,7 @@ import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.Executors; +import java.util.stream.Collectors; /** * ExoPlayer Preparer for Voice Notes. This only supports ACTION_PLAY_FROM_URI @@ -140,6 +144,10 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP player.prepare(dataSource); canLoadMore = !singlePlayback; + } else if (Objects.equals(latestUri, uri)) { + Log.w(TAG, "Requested playback but no voice notes could be found."); + ThreadUtil.postToMain(() -> Toast.makeText(context, R.string.VoiceNotePlaybackPreparer__failed_to_play_voice_message, Toast.LENGTH_SHORT) + .show()); } }); } @@ -262,7 +270,12 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP return Collections.emptyList(); } - return Collections.singletonList(VoiceNoteMediaDescriptionCompatFactory.buildMediaDescription(context ,messageRecord)); + MediaDescriptionCompat mediaDescriptionCompat = VoiceNoteMediaDescriptionCompatFactory.buildMediaDescription(context ,messageRecord); + if (mediaDescriptionCompat == null) { + return Collections.emptyList(); + } else { + return Collections.singletonList(mediaDescriptionCompat); + } } catch (NoSuchMessageException e) { Log.w(TAG, "Could not find message.", e); return Collections.emptyList(); @@ -278,9 +291,10 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP try { List recordsAfter = DatabaseFactory.getMmsSmsDatabase(context).getMessagesAfterVoiceNoteInclusive(messageId, LIMIT); - return Stream.of(buildFilteredMessageRecordList(recordsAfter)) - .map(record -> VoiceNoteMediaDescriptionCompatFactory.buildMediaDescription(context, record)) - .toList(); + return buildFilteredMessageRecordList(recordsAfter).stream() + .map(record -> VoiceNoteMediaDescriptionCompatFactory.buildMediaDescription(context, record)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); } catch (NoSuchMessageException e) { Log.w(TAG, "Could not find message.", e); return Collections.emptyList(); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index db7d1a609..bda7cef3d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3169,6 +3169,7 @@ The link is not currently active + Failed to play voice message Voice message · %1$s