mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-25 17:37:57 +00:00
Return sane value if player is out of sync with data adapter.
This commit is contained in:
@@ -222,7 +222,8 @@ public class VoiceNoteMediaController implements DefaultLifecycleObserver {
|
|||||||
MediaMetadataCompat mediaMetadataCompat = mediaController.getMetadata();
|
MediaMetadataCompat mediaMetadataCompat = mediaController.getMetadata();
|
||||||
if (isPlayerActive(mediaController.getPlaybackState()) &&
|
if (isPlayerActive(mediaController.getPlaybackState()) &&
|
||||||
mediaMetadataCompat != null &&
|
mediaMetadataCompat != null &&
|
||||||
mediaMetadataCompat.getDescription() != null)
|
mediaMetadataCompat.getDescription() != null &&
|
||||||
|
mediaMetadataCompat.getDescription().getMediaUri() != null)
|
||||||
{
|
{
|
||||||
|
|
||||||
Uri mediaUri = Objects.requireNonNull(mediaMetadataCompat.getDescription().getMediaUri());
|
Uri mediaUri = Objects.requireNonNull(mediaMetadataCompat.getDescription().getMediaUri());
|
||||||
|
@@ -79,7 +79,7 @@ class VoiceNoteNotificationManager {
|
|||||||
@Override
|
@Override
|
||||||
public String getCurrentContentTitle(Player player) {
|
public String getCurrentContentTitle(Player player) {
|
||||||
if (hasMetadata()) {
|
if (hasMetadata()) {
|
||||||
return Objects.requireNonNull(controller.getMetadata().getDescription().getTitle()).toString();
|
return Objects.toString(controller.getMetadata().getDescription().getTitle(), null);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -89,9 +89,14 @@ class VoiceNoteNotificationManager {
|
|||||||
public @Nullable PendingIntent createCurrentContentIntent(Player player) {
|
public @Nullable PendingIntent createCurrentContentIntent(Player player) {
|
||||||
if (!hasMetadata()) return null;
|
if (!hasMetadata()) return null;
|
||||||
|
|
||||||
RecipientId recipientId = RecipientId.from(Objects.requireNonNull(controller.getMetadata().getString(VoiceNoteMediaDescriptionCompatFactory.EXTRA_THREAD_RECIPIENT_ID)));
|
String serializedRecipientId = controller.getMetadata().getString(VoiceNoteMediaDescriptionCompatFactory.EXTRA_THREAD_RECIPIENT_ID);
|
||||||
int startingPosition = (int) controller.getMetadata().getLong(VoiceNoteMediaDescriptionCompatFactory.EXTRA_MESSAGE_POSITION);
|
if (serializedRecipientId == null) {
|
||||||
long threadId = controller.getMetadata().getLong(VoiceNoteMediaDescriptionCompatFactory.EXTRA_THREAD_ID);
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RecipientId recipientId = RecipientId.from(serializedRecipientId);
|
||||||
|
int startingPosition = (int) controller.getMetadata().getLong(VoiceNoteMediaDescriptionCompatFactory.EXTRA_MESSAGE_POSITION);
|
||||||
|
long threadId = controller.getMetadata().getLong(VoiceNoteMediaDescriptionCompatFactory.EXTRA_THREAD_ID);
|
||||||
|
|
||||||
MaterialColor color;
|
MaterialColor color;
|
||||||
try {
|
try {
|
||||||
@@ -131,7 +136,12 @@ class VoiceNoteNotificationManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
RecipientId currentRecipientId = RecipientId.from(Objects.requireNonNull(controller.getMetadata().getString(VoiceNoteMediaDescriptionCompatFactory.EXTRA_AVATAR_RECIPIENT_ID)));
|
String serializedRecipientId = controller.getMetadata().getString(VoiceNoteMediaDescriptionCompatFactory.EXTRA_AVATAR_RECIPIENT_ID);
|
||||||
|
if (serializedRecipientId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RecipientId currentRecipientId = RecipientId.from(serializedRecipientId);
|
||||||
|
|
||||||
if (Objects.equals(currentRecipientId, cachedRecipientId) && cachedBitmap != null) {
|
if (Objects.equals(currentRecipientId, cachedRecipientId) && cachedBitmap != null) {
|
||||||
return cachedBitmap;
|
return cachedBitmap;
|
||||||
|
@@ -7,6 +7,7 @@ import android.os.ResultReceiver;
|
|||||||
import android.support.v4.media.MediaDescriptionCompat;
|
import android.support.v4.media.MediaDescriptionCompat;
|
||||||
import android.support.v4.media.session.PlaybackStateCompat;
|
import android.support.v4.media.session.PlaybackStateCompat;
|
||||||
|
|
||||||
|
import androidx.annotation.MainThread;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
@@ -106,13 +107,11 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
descriptions -> {
|
descriptions -> {
|
||||||
if (Util.hasItems(descriptions) && Objects.equals(latestUri, uri)) {
|
queueDataAdapter.clear();
|
||||||
synchronized (queueDataAdapter) {
|
dataSource.clear();
|
||||||
queueDataAdapter.clear();
|
|
||||||
dataSource.clear();
|
|
||||||
|
|
||||||
applyDescriptionsToQueue(descriptions);
|
if (Util.hasItems(descriptions) && Objects.equals(latestUri, uri)) {
|
||||||
}
|
applyDescriptionsToQueue(descriptions);
|
||||||
|
|
||||||
int window = Math.max(0, queueDataAdapter.indexOf(uri));
|
int window = Math.max(0, queueDataAdapter.indexOf(uri));
|
||||||
|
|
||||||
@@ -141,61 +140,64 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP
|
|||||||
public void onCommand(Player player, String command, Bundle extras, ResultReceiver cb) {
|
public void onCommand(Player player, String command, Bundle extras, ResultReceiver cb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MainThread
|
||||||
private void applyDescriptionsToQueue(@NonNull List<MediaDescriptionCompat> descriptions) {
|
private void applyDescriptionsToQueue(@NonNull List<MediaDescriptionCompat> descriptions) {
|
||||||
synchronized (queueDataAdapter) {
|
for (MediaDescriptionCompat description : descriptions) {
|
||||||
for (MediaDescriptionCompat description : descriptions) {
|
int holderIndex = queueDataAdapter.indexOf(description.getMediaUri());
|
||||||
int holderIndex = queueDataAdapter.indexOf(description.getMediaUri());
|
MediaDescriptionCompat next = createNextClone(description);
|
||||||
MediaDescriptionCompat next = createNextClone(description);
|
int currentIndex = player.getCurrentWindowIndex();
|
||||||
int currentIndex = player.getCurrentWindowIndex();
|
|
||||||
|
|
||||||
if (holderIndex != -1) {
|
if (holderIndex != -1) {
|
||||||
|
queueDataAdapter.remove(holderIndex);
|
||||||
|
|
||||||
|
if (!queueDataAdapter.isEmpty()) {
|
||||||
queueDataAdapter.remove(holderIndex);
|
queueDataAdapter.remove(holderIndex);
|
||||||
|
|
||||||
if (!queueDataAdapter.isEmpty()) {
|
|
||||||
queueDataAdapter.remove(holderIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
queueDataAdapter.add(holderIndex, createNextClone(description));
|
|
||||||
queueDataAdapter.add(holderIndex, description);
|
|
||||||
|
|
||||||
if (currentIndex != holderIndex) {
|
|
||||||
dataSource.removeMediaSource(holderIndex);
|
|
||||||
dataSource.addMediaSource(holderIndex, mediaSourceFactory.createMediaSource(description));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentIndex != holderIndex + 1) {
|
|
||||||
if (dataSource.getSize() > 1) {
|
|
||||||
dataSource.removeMediaSource(holderIndex + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
dataSource.addMediaSource(holderIndex + 1, mediaSourceFactory.createMediaSource(next));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int insertLocation = queueDataAdapter.indexAfter(description);
|
|
||||||
|
|
||||||
queueDataAdapter.add(insertLocation, next);
|
|
||||||
queueDataAdapter.add(insertLocation, description);
|
|
||||||
|
|
||||||
dataSource.addMediaSource(insertLocation, mediaSourceFactory.createMediaSource(next));
|
|
||||||
dataSource.addMediaSource(insertLocation, mediaSourceFactory.createMediaSource(description));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
int lastIndex = queueDataAdapter.size() - 1;
|
queueDataAdapter.add(holderIndex, createNextClone(description));
|
||||||
MediaDescriptionCompat last = queueDataAdapter.getMediaDescription(lastIndex);
|
queueDataAdapter.add(holderIndex, description);
|
||||||
|
|
||||||
if (Objects.equals(last.getMediaUri(), NEXT_URI)) {
|
if (currentIndex != holderIndex) {
|
||||||
queueDataAdapter.remove(lastIndex);
|
dataSource.removeMediaSource(holderIndex);
|
||||||
dataSource.removeMediaSource(lastIndex);
|
dataSource.addMediaSource(holderIndex, mediaSourceFactory.createMediaSource(description));
|
||||||
|
|
||||||
if (queueDataAdapter.size() > 1) {
|
|
||||||
MediaDescriptionCompat end = createEndClone(last);
|
|
||||||
|
|
||||||
queueDataAdapter.add(lastIndex, end);
|
|
||||||
dataSource.addMediaSource(lastIndex, mediaSourceFactory.createMediaSource(end));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentIndex != holderIndex + 1) {
|
||||||
|
if (dataSource.getSize() > 1) {
|
||||||
|
dataSource.removeMediaSource(holderIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
dataSource.addMediaSource(holderIndex + 1, mediaSourceFactory.createMediaSource(next));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int insertLocation = queueDataAdapter.indexAfter(description);
|
||||||
|
|
||||||
|
queueDataAdapter.add(insertLocation, next);
|
||||||
|
queueDataAdapter.add(insertLocation, description);
|
||||||
|
|
||||||
|
dataSource.addMediaSource(insertLocation, mediaSourceFactory.createMediaSource(next));
|
||||||
|
dataSource.addMediaSource(insertLocation, mediaSourceFactory.createMediaSource(description));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lastIndex = queueDataAdapter.size() - 1;
|
||||||
|
MediaDescriptionCompat last = queueDataAdapter.getMediaDescription(lastIndex);
|
||||||
|
|
||||||
|
if (Objects.equals(last.getMediaUri(), NEXT_URI)) {
|
||||||
|
queueDataAdapter.remove(lastIndex);
|
||||||
|
dataSource.removeMediaSource(lastIndex);
|
||||||
|
|
||||||
|
if (queueDataAdapter.size() > 1) {
|
||||||
|
MediaDescriptionCompat end = createEndClone(last);
|
||||||
|
|
||||||
|
queueDataAdapter.add(lastIndex, end);
|
||||||
|
dataSource.addMediaSource(lastIndex, mediaSourceFactory.createMediaSource(end));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queueDataAdapter.size() != dataSource.getSize()) {
|
||||||
|
throw new IllegalStateException("QueueDataAdapter and DataSource size inconsistency.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull MediaDescriptionCompat createEndClone(@NonNull MediaDescriptionCompat source) {
|
private @NonNull MediaDescriptionCompat createEndClone(@NonNull MediaDescriptionCompat source) {
|
||||||
@@ -223,7 +225,11 @@ final class VoiceNotePlaybackPreparer implements MediaSessionConnector.PlaybackP
|
|||||||
}
|
}
|
||||||
|
|
||||||
MediaDescriptionCompat mediaDescriptionCompat = queueDataAdapter.getMediaDescription(player.getCurrentWindowIndex());
|
MediaDescriptionCompat mediaDescriptionCompat = queueDataAdapter.getMediaDescription(player.getCurrentWindowIndex());
|
||||||
long messageId = mediaDescriptionCompat.getExtras().getLong(VoiceNoteMediaDescriptionCompatFactory.EXTRA_MESSAGE_ID);
|
if (Objects.equals(mediaDescriptionCompat, VoiceNoteQueueDataAdapter.EMPTY)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long messageId = mediaDescriptionCompat.getExtras().getLong(VoiceNoteMediaDescriptionCompatFactory.EXTRA_MESSAGE_ID);
|
||||||
|
|
||||||
SimpleTask.run(EXECUTOR,
|
SimpleTask.run(EXECUTOR,
|
||||||
() -> loadMediaDescriptionsForConsecutivePlayback(messageId),
|
() -> loadMediaDescriptionsForConsecutivePlayback(messageId),
|
||||||
|
@@ -96,7 +96,11 @@ class VoiceNoteProximityManager implements SensorEventListener {
|
|||||||
} else {
|
} else {
|
||||||
MediaDescriptionCompat mediaDescriptionCompat = queueDataAdapter.getMediaDescription(windowIndex);
|
MediaDescriptionCompat mediaDescriptionCompat = queueDataAdapter.getMediaDescription(windowIndex);
|
||||||
|
|
||||||
threadId = mediaDescriptionCompat.getExtras().getLong(VoiceNoteMediaDescriptionCompatFactory.EXTRA_THREAD_ID, -1);
|
if (mediaDescriptionCompat.getExtras() == null) {
|
||||||
|
threadId = -1;
|
||||||
|
} else {
|
||||||
|
threadId = mediaDescriptionCompat.getExtras().getLong(VoiceNoteMediaDescriptionCompatFactory.EXTRA_THREAD_ID, -1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (desiredStreamType == AudioManager.STREAM_VOICE_CALL &&
|
if (desiredStreamType == AudioManager.STREAM_VOICE_CALL &&
|
||||||
|
@@ -3,11 +3,14 @@ package org.thoughtcrime.securesms.components.voice;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.v4.media.MediaDescriptionCompat;
|
import android.support.v4.media.MediaDescriptionCompat;
|
||||||
|
|
||||||
|
import androidx.annotation.MainThread;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueEditor;
|
import com.google.android.exoplayer2.ext.mediasession.TimelineQueueEditor;
|
||||||
|
|
||||||
|
import org.thoughtcrime.securesms.logging.Log;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -15,36 +18,46 @@ import java.util.Objects;
|
|||||||
/**
|
/**
|
||||||
* DataAdapter which maintains the current queue of MediaDescriptionCompat objects.
|
* DataAdapter which maintains the current queue of MediaDescriptionCompat objects.
|
||||||
*/
|
*/
|
||||||
|
@MainThread
|
||||||
final class VoiceNoteQueueDataAdapter implements TimelineQueueEditor.QueueDataAdapter {
|
final class VoiceNoteQueueDataAdapter implements TimelineQueueEditor.QueueDataAdapter {
|
||||||
|
|
||||||
|
private static final String TAG = Log.tag(VoiceNoteQueueDataAdapter.class);
|
||||||
|
|
||||||
|
public static final MediaDescriptionCompat EMPTY = new MediaDescriptionCompat.Builder().build();
|
||||||
|
|
||||||
private final List<MediaDescriptionCompat> descriptions = new LinkedList<>();
|
private final List<MediaDescriptionCompat> descriptions = new LinkedList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized MediaDescriptionCompat getMediaDescription(int position) {
|
public MediaDescriptionCompat getMediaDescription(int position) {
|
||||||
|
if (descriptions.size() <= position) {
|
||||||
|
Log.i(TAG, "getMediaDescription: Returning EMPTY MediaDescriptionCompat for index " + position);
|
||||||
|
return EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
return descriptions.get(position);
|
return descriptions.get(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void add(int position, MediaDescriptionCompat description) {
|
public void add(int position, MediaDescriptionCompat description) {
|
||||||
descriptions.add(position, description);
|
descriptions.add(position, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void remove(int position) {
|
public void remove(int position) {
|
||||||
descriptions.remove(position);
|
descriptions.remove(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void move(int from, int to) {
|
public void move(int from, int to) {
|
||||||
MediaDescriptionCompat description = descriptions.remove(from);
|
MediaDescriptionCompat description = descriptions.remove(from);
|
||||||
descriptions.add(to, description);
|
descriptions.add(to, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized int size() {
|
int size() {
|
||||||
return descriptions.size();
|
return descriptions.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized int indexOf(@NonNull Uri uri) {
|
int indexOf(@NonNull Uri uri) {
|
||||||
for (int i = 0; i < descriptions.size(); i++) {
|
for (int i = 0; i < descriptions.size(); i++) {
|
||||||
if (Objects.equals(uri, descriptions.get(i).getMediaUri())) {
|
if (Objects.equals(uri, descriptions.get(i).getMediaUri())) {
|
||||||
return i;
|
return i;
|
||||||
@@ -54,7 +67,7 @@ final class VoiceNoteQueueDataAdapter implements TimelineQueueEditor.QueueDataAd
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized int indexAfter(@NonNull MediaDescriptionCompat target) {
|
int indexAfter(@NonNull MediaDescriptionCompat target) {
|
||||||
if (isEmpty()) {
|
if (isEmpty()) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -71,11 +84,11 @@ final class VoiceNoteQueueDataAdapter implements TimelineQueueEditor.QueueDataAd
|
|||||||
return descriptions.size();
|
return descriptions.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized boolean isEmpty() {
|
boolean isEmpty() {
|
||||||
return descriptions.isEmpty();
|
return descriptions.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void clear() {
|
void clear() {
|
||||||
descriptions.clear();
|
descriptions.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user