Add BitmapLoader injection in MediaController
Also clean up the strict mode violations of using `BitmapFactory.convertToByteArray` on the main thread. PiperOrigin-RevId: 496422355
This commit is contained in:
parent
0744a52b8d
commit
d848d3358a
@ -32,6 +32,7 @@ import androidx.annotation.Nullable;
|
|||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
import androidx.media3.common.util.Consumer;
|
import androidx.media3.common.util.Consumer;
|
||||||
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.session.MediaLibraryService.LibraryParams;
|
import androidx.media3.session.MediaLibraryService.LibraryParams;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
@ -57,6 +58,7 @@ public final class MediaBrowser extends MediaController {
|
|||||||
private Bundle connectionHints;
|
private Bundle connectionHints;
|
||||||
private Listener listener;
|
private Listener listener;
|
||||||
private Looper applicationLooper;
|
private Looper applicationLooper;
|
||||||
|
private @MonotonicNonNull BitmapLoader bitmapLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a builder for {@link MediaBrowser}.
|
* Creates a builder for {@link MediaBrowser}.
|
||||||
@ -121,6 +123,21 @@ public final class MediaBrowser extends MediaController {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a {@link BitmapLoader} for the {@link MediaBrowser} to decode bitmaps from compressed
|
||||||
|
* binary data. If not set, a {@link CacheBitmapLoader} that wraps a {@link SimpleBitmapLoader}
|
||||||
|
* will be used.
|
||||||
|
*
|
||||||
|
* @param bitmapLoader The bitmap loader.
|
||||||
|
* @return The builder to allow chaining.
|
||||||
|
*/
|
||||||
|
@UnstableApi
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public Builder setBitmapLoader(BitmapLoader bitmapLoader) {
|
||||||
|
this.bitmapLoader = checkNotNull(bitmapLoader);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a {@link MediaBrowser} asynchronously.
|
* Builds a {@link MediaBrowser} asynchronously.
|
||||||
*
|
*
|
||||||
@ -149,8 +166,12 @@ public final class MediaBrowser extends MediaController {
|
|||||||
*/
|
*/
|
||||||
public ListenableFuture<MediaBrowser> buildAsync() {
|
public ListenableFuture<MediaBrowser> buildAsync() {
|
||||||
MediaControllerHolder<MediaBrowser> holder = new MediaControllerHolder<>(applicationLooper);
|
MediaControllerHolder<MediaBrowser> holder = new MediaControllerHolder<>(applicationLooper);
|
||||||
|
if (token.isLegacySession() && bitmapLoader == null) {
|
||||||
|
bitmapLoader = new CacheBitmapLoader(new SimpleBitmapLoader());
|
||||||
|
}
|
||||||
MediaBrowser browser =
|
MediaBrowser browser =
|
||||||
new MediaBrowser(context, token, connectionHints, listener, applicationLooper, holder);
|
new MediaBrowser(
|
||||||
|
context, token, connectionHints, listener, applicationLooper, holder, bitmapLoader);
|
||||||
postOrRun(new Handler(applicationLooper), () -> holder.setController(browser));
|
postOrRun(new Handler(applicationLooper), () -> holder.setController(browser));
|
||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
@ -215,8 +236,16 @@ public final class MediaBrowser extends MediaController {
|
|||||||
Bundle connectionHints,
|
Bundle connectionHints,
|
||||||
Listener listener,
|
Listener listener,
|
||||||
Looper applicationLooper,
|
Looper applicationLooper,
|
||||||
ConnectionCallback connectionCallback) {
|
ConnectionCallback connectionCallback,
|
||||||
super(context, token, connectionHints, listener, applicationLooper, connectionCallback);
|
@Nullable BitmapLoader bitmapLoader) {
|
||||||
|
super(
|
||||||
|
context,
|
||||||
|
token,
|
||||||
|
connectionHints,
|
||||||
|
listener,
|
||||||
|
applicationLooper,
|
||||||
|
connectionCallback,
|
||||||
|
bitmapLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -226,10 +255,13 @@ public final class MediaBrowser extends MediaController {
|
|||||||
Context context,
|
Context context,
|
||||||
SessionToken token,
|
SessionToken token,
|
||||||
Bundle connectionHints,
|
Bundle connectionHints,
|
||||||
Looper applicationLooper) {
|
Looper applicationLooper,
|
||||||
|
@Nullable BitmapLoader bitmapLoader) {
|
||||||
MediaBrowserImpl impl;
|
MediaBrowserImpl impl;
|
||||||
if (token.isLegacySession()) {
|
if (token.isLegacySession()) {
|
||||||
impl = new MediaBrowserImplLegacy(context, this, token, applicationLooper);
|
impl =
|
||||||
|
new MediaBrowserImplLegacy(
|
||||||
|
context, this, token, applicationLooper, checkNotNull(bitmapLoader));
|
||||||
} else {
|
} else {
|
||||||
impl = new MediaBrowserImplBase(context, this, token, connectionHints, applicationLooper);
|
impl = new MediaBrowserImplBase(context, this, token, connectionHints, applicationLooper);
|
||||||
}
|
}
|
||||||
|
@ -57,8 +57,9 @@ import org.checkerframework.checker.initialization.qual.UnderInitialization;
|
|||||||
Context context,
|
Context context,
|
||||||
@UnderInitialization MediaBrowser instance,
|
@UnderInitialization MediaBrowser instance,
|
||||||
SessionToken token,
|
SessionToken token,
|
||||||
Looper applicationLooper) {
|
Looper applicationLooper,
|
||||||
super(context, instance, token, applicationLooper);
|
BitmapLoader bitmapLoader) {
|
||||||
|
super(context, instance, token, applicationLooper, bitmapLoader);
|
||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,6 +67,7 @@ import java.util.concurrent.Executor;
|
|||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
import org.checkerframework.checker.initialization.qual.NotOnlyInitialized;
|
import org.checkerframework.checker.initialization.qual.NotOnlyInitialized;
|
||||||
import org.checkerframework.checker.initialization.qual.UnderInitialization;
|
import org.checkerframework.checker.initialization.qual.UnderInitialization;
|
||||||
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A controller that interacts with a {@link MediaSession}, a {@link MediaSessionService} hosting a
|
* A controller that interacts with a {@link MediaSession}, a {@link MediaSessionService} hosting a
|
||||||
@ -183,6 +184,7 @@ public class MediaController implements Player {
|
|||||||
private Bundle connectionHints;
|
private Bundle connectionHints;
|
||||||
private Listener listener;
|
private Listener listener;
|
||||||
private Looper applicationLooper;
|
private Looper applicationLooper;
|
||||||
|
private @MonotonicNonNull BitmapLoader bitmapLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a builder for {@link MediaController}.
|
* Creates a builder for {@link MediaController}.
|
||||||
@ -261,6 +263,21 @@ public class MediaController implements Player {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a {@link BitmapLoader} for the {@link MediaController} to decode bitmaps from compressed
|
||||||
|
* binary data. If not set, a {@link CacheBitmapLoader} that wraps a {@link SimpleBitmapLoader}
|
||||||
|
* will be used.
|
||||||
|
*
|
||||||
|
* @param bitmapLoader The bitmap loader.
|
||||||
|
* @return The builder to allow chaining.
|
||||||
|
*/
|
||||||
|
@UnstableApi
|
||||||
|
@CanIgnoreReturnValue
|
||||||
|
public Builder setBitmapLoader(BitmapLoader bitmapLoader) {
|
||||||
|
this.bitmapLoader = checkNotNull(bitmapLoader);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds a {@link MediaController} asynchronously.
|
* Builds a {@link MediaController} asynchronously.
|
||||||
*
|
*
|
||||||
@ -290,8 +307,12 @@ public class MediaController implements Player {
|
|||||||
public ListenableFuture<MediaController> buildAsync() {
|
public ListenableFuture<MediaController> buildAsync() {
|
||||||
MediaControllerHolder<MediaController> holder =
|
MediaControllerHolder<MediaController> holder =
|
||||||
new MediaControllerHolder<>(applicationLooper);
|
new MediaControllerHolder<>(applicationLooper);
|
||||||
|
if (token.isLegacySession() && bitmapLoader == null) {
|
||||||
|
bitmapLoader = new CacheBitmapLoader(new SimpleBitmapLoader());
|
||||||
|
}
|
||||||
MediaController controller =
|
MediaController controller =
|
||||||
new MediaController(context, token, connectionHints, listener, applicationLooper, holder);
|
new MediaController(
|
||||||
|
context, token, connectionHints, listener, applicationLooper, holder, bitmapLoader);
|
||||||
postOrRun(new Handler(applicationLooper), () -> holder.setController(controller));
|
postOrRun(new Handler(applicationLooper), () -> holder.setController(controller));
|
||||||
return holder;
|
return holder;
|
||||||
}
|
}
|
||||||
@ -404,7 +425,8 @@ public class MediaController implements Player {
|
|||||||
Bundle connectionHints,
|
Bundle connectionHints,
|
||||||
Listener listener,
|
Listener listener,
|
||||||
Looper applicationLooper,
|
Looper applicationLooper,
|
||||||
ConnectionCallback connectionCallback) {
|
ConnectionCallback connectionCallback,
|
||||||
|
@Nullable BitmapLoader bitmapLoader) {
|
||||||
checkNotNull(context, "context must not be null");
|
checkNotNull(context, "context must not be null");
|
||||||
checkNotNull(token, "token must not be null");
|
checkNotNull(token, "token must not be null");
|
||||||
|
|
||||||
@ -417,7 +439,7 @@ public class MediaController implements Player {
|
|||||||
applicationHandler = new Handler(applicationLooper);
|
applicationHandler = new Handler(applicationLooper);
|
||||||
this.connectionCallback = connectionCallback;
|
this.connectionCallback = connectionCallback;
|
||||||
|
|
||||||
impl = createImpl(context, token, connectionHints, applicationLooper);
|
impl = createImpl(context, token, connectionHints, applicationLooper, bitmapLoader);
|
||||||
impl.connect();
|
impl.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,9 +449,11 @@ public class MediaController implements Player {
|
|||||||
Context context,
|
Context context,
|
||||||
SessionToken token,
|
SessionToken token,
|
||||||
Bundle connectionHints,
|
Bundle connectionHints,
|
||||||
Looper applicationLooper) {
|
Looper applicationLooper,
|
||||||
|
@Nullable BitmapLoader bitmapLoader) {
|
||||||
if (token.isLegacySession()) {
|
if (token.isLegacySession()) {
|
||||||
return new MediaControllerImplLegacy(context, this, token, applicationLooper);
|
return new MediaControllerImplLegacy(
|
||||||
|
context, this, token, applicationLooper, checkNotNull(bitmapLoader));
|
||||||
} else {
|
} else {
|
||||||
return new MediaControllerImplBase(context, this, token, connectionHints, applicationLooper);
|
return new MediaControllerImplBase(context, this, token, connectionHints, applicationLooper);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import static java.lang.Math.min;
|
|||||||
|
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
@ -76,7 +77,10 @@ import com.google.common.util.concurrent.SettableFuture;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import org.checkerframework.checker.initialization.qual.UnderInitialization;
|
import org.checkerframework.checker.initialization.qual.UnderInitialization;
|
||||||
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||||
|
|
||||||
@ -93,6 +97,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
private final SessionToken token;
|
private final SessionToken token;
|
||||||
private final ListenerSet<Listener> listeners;
|
private final ListenerSet<Listener> listeners;
|
||||||
private final ControllerCompatCallback controllerCompatCallback;
|
private final ControllerCompatCallback controllerCompatCallback;
|
||||||
|
private final BitmapLoader bitmapLoader;
|
||||||
|
|
||||||
@Nullable private MediaControllerCompat controllerCompat;
|
@Nullable private MediaControllerCompat controllerCompat;
|
||||||
@Nullable private MediaBrowserCompat browserCompat;
|
@Nullable private MediaBrowserCompat browserCompat;
|
||||||
@ -106,7 +111,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
Context context,
|
Context context,
|
||||||
@UnderInitialization MediaController instance,
|
@UnderInitialization MediaController instance,
|
||||||
SessionToken token,
|
SessionToken token,
|
||||||
Looper applicationLooper) {
|
Looper applicationLooper,
|
||||||
|
BitmapLoader bitmapLoader) {
|
||||||
// Initialize default values.
|
// Initialize default values.
|
||||||
legacyPlayerInfo = new LegacyPlayerInfo();
|
legacyPlayerInfo = new LegacyPlayerInfo();
|
||||||
pendingLegacyPlayerInfo = new LegacyPlayerInfo();
|
pendingLegacyPlayerInfo = new LegacyPlayerInfo();
|
||||||
@ -122,6 +128,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
this.instance = instance;
|
this.instance = instance;
|
||||||
controllerCompatCallback = new ControllerCompatCallback(applicationLooper);
|
controllerCompatCallback = new ControllerCompatCallback(applicationLooper);
|
||||||
this.token = token;
|
this.token = token;
|
||||||
|
this.bitmapLoader = bitmapLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ MediaController getInstance() {
|
/* package */ MediaController getInstance() {
|
||||||
@ -716,11 +723,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
/* mediaItemTransitionReason= */ null);
|
/* mediaItemTransitionReason= */ null);
|
||||||
|
|
||||||
if (isPrepared()) {
|
if (isPrepared()) {
|
||||||
for (int i = 0; i < mediaItems.size(); i++) {
|
addQueueItems(mediaItems, index);
|
||||||
MediaItem mediaItem = mediaItems.get(i);
|
|
||||||
controllerCompat.addQueueItem(
|
|
||||||
MediaUtils.convertToMediaDescriptionCompat(mediaItem), index + i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1340,15 +1343,61 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
}
|
}
|
||||||
// Add all other items to the playlist if supported.
|
// Add all other items to the playlist if supported.
|
||||||
if (getAvailableCommands().contains(Player.COMMAND_CHANGE_MEDIA_ITEMS)) {
|
if (getAvailableCommands().contains(Player.COMMAND_CHANGE_MEDIA_ITEMS)) {
|
||||||
|
List<MediaItem> adjustedMediaItems = new ArrayList<>();
|
||||||
for (int i = 0; i < queueTimeline.getWindowCount(); i++) {
|
for (int i = 0; i < queueTimeline.getWindowCount(); i++) {
|
||||||
if (i == currentIndex || queueTimeline.getQueueId(i) != QueueItem.UNKNOWN_ID) {
|
if (i == currentIndex || queueTimeline.getQueueId(i) != QueueItem.UNKNOWN_ID) {
|
||||||
// Skip the current item (added above) and all items already known to the session.
|
// Skip the current item (added above) and all items already known to the session.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
MediaItem mediaItem = queueTimeline.getWindow(/* windowIndex= */ i, window).mediaItem;
|
adjustedMediaItems.add(queueTimeline.getWindow(/* windowIndex= */ i, window).mediaItem);
|
||||||
controllerCompat.addQueueItem(
|
|
||||||
MediaUtils.convertToMediaDescriptionCompat(mediaItem), /* index= */ i);
|
|
||||||
}
|
}
|
||||||
|
addQueueItems(adjustedMediaItems, /* startIndex= */ 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addQueueItems(List<MediaItem> mediaItems, int startIndex) {
|
||||||
|
List<@NullableType ListenableFuture<Bitmap>> bitmapFutures = new ArrayList<>();
|
||||||
|
final AtomicInteger resultCount = new AtomicInteger(0);
|
||||||
|
Runnable handleBitmapFuturesTask =
|
||||||
|
() -> {
|
||||||
|
int completedBitmapFutureCount = resultCount.incrementAndGet();
|
||||||
|
if (completedBitmapFutureCount == mediaItems.size()) {
|
||||||
|
handleBitmapFuturesAllCompletedAndAddQueueItems(
|
||||||
|
bitmapFutures, mediaItems, /* startIndex= */ startIndex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int i = 0; i < mediaItems.size(); i++) {
|
||||||
|
MediaItem mediaItem = mediaItems.get(i);
|
||||||
|
MediaMetadata metadata = mediaItem.mediaMetadata;
|
||||||
|
if (metadata.artworkData == null) {
|
||||||
|
bitmapFutures.add(null);
|
||||||
|
handleBitmapFuturesTask.run();
|
||||||
|
} else {
|
||||||
|
ListenableFuture<Bitmap> bitmapFuture = bitmapLoader.decodeBitmap(metadata.artworkData);
|
||||||
|
bitmapFutures.add(bitmapFuture);
|
||||||
|
bitmapFuture.addListener(handleBitmapFuturesTask, getInstance().applicationHandler::post);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleBitmapFuturesAllCompletedAndAddQueueItems(
|
||||||
|
List<@NullableType ListenableFuture<Bitmap>> bitmapFutures,
|
||||||
|
List<MediaItem> mediaItems,
|
||||||
|
int startIndex) {
|
||||||
|
for (int i = 0; i < bitmapFutures.size(); i++) {
|
||||||
|
@Nullable ListenableFuture<Bitmap> future = bitmapFutures.get(i);
|
||||||
|
@Nullable Bitmap bitmap = null;
|
||||||
|
if (future != null) {
|
||||||
|
try {
|
||||||
|
bitmap = Futures.getDone(future);
|
||||||
|
} catch (CancellationException | ExecutionException e) {
|
||||||
|
Log.d(TAG, "Failed to get bitmap");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
controllerCompat.addQueueItem(
|
||||||
|
MediaUtils.convertToMediaDescriptionCompat(mediaItems.get(i), bitmap),
|
||||||
|
/* index= */ startIndex + i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,6 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.media.AudioManager;
|
import android.media.AudioManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@ -311,23 +310,6 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a {@link MediaItem} to a {@link MediaDescriptionCompat}.
|
|
||||||
*
|
|
||||||
* @deprecated Use {@link #convertToMediaDescriptionCompat(MediaItem, Bitmap)} instead.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static MediaDescriptionCompat convertToMediaDescriptionCompat(MediaItem item) {
|
|
||||||
MediaMetadata metadata = item.mediaMetadata;
|
|
||||||
@Nullable Bitmap artworkBitmap = null;
|
|
||||||
if (metadata.artworkData != null) {
|
|
||||||
artworkBitmap =
|
|
||||||
BitmapFactory.decodeByteArray(metadata.artworkData, 0, metadata.artworkData.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
return convertToMediaDescriptionCompat(item, artworkBitmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Converts a {@link MediaItem} to a {@link MediaDescriptionCompat} */
|
/** Converts a {@link MediaItem} to a {@link MediaDescriptionCompat} */
|
||||||
public static MediaDescriptionCompat convertToMediaDescriptionCompat(
|
public static MediaDescriptionCompat convertToMediaDescriptionCompat(
|
||||||
MediaItem item, @Nullable Bitmap artworkBitmap) {
|
MediaItem item, @Nullable Bitmap artworkBitmap) {
|
||||||
|
@ -37,6 +37,7 @@ import android.support.v4.media.session.PlaybackStateCompat.RepeatMode;
|
|||||||
import android.support.v4.media.session.PlaybackStateCompat.ShuffleMode;
|
import android.support.v4.media.session.PlaybackStateCompat.ShuffleMode;
|
||||||
import androidx.media.AudioManagerCompat;
|
import androidx.media.AudioManagerCompat;
|
||||||
import androidx.media.VolumeProviderCompat;
|
import androidx.media.VolumeProviderCompat;
|
||||||
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.MediaItem;
|
import androidx.media3.common.MediaItem;
|
||||||
import androidx.media3.common.PlaybackParameters;
|
import androidx.media3.common.PlaybackParameters;
|
||||||
import androidx.media3.common.Player;
|
import androidx.media3.common.Player;
|
||||||
@ -52,6 +53,7 @@ import androidx.test.core.app.ApplicationProvider;
|
|||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import androidx.test.filters.SdkSuppress;
|
import androidx.test.filters.SdkSuppress;
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
@ -327,7 +329,7 @@ public class MediaSessionCompatCallbackWithMediaControllerTest {
|
|||||||
@Test
|
@Test
|
||||||
public void addMediaItems() throws Exception {
|
public void addMediaItems() throws Exception {
|
||||||
int size = 2;
|
int size = 2;
|
||||||
List<MediaItem> testList = MediaTestUtils.createMediaItems(size);
|
List<MediaItem> testList = MediaTestUtils.createMediaItemsWithArtworkData(size);
|
||||||
List<QueueItem> testQueue = MediaTestUtils.convertToQueueItemsWithoutBitmap(testList);
|
List<QueueItem> testQueue = MediaTestUtils.convertToQueueItemsWithoutBitmap(testList);
|
||||||
|
|
||||||
session.setQueue(testQueue);
|
session.setQueue(testQueue);
|
||||||
@ -345,6 +347,7 @@ public class MediaSessionCompatCallbackWithMediaControllerTest {
|
|||||||
assertThat(sessionCallback.queueIndices.get(i)).isEqualTo(testIndex + i);
|
assertThat(sessionCallback.queueIndices.get(i)).isEqualTo(testIndex + i);
|
||||||
assertThat(sessionCallback.queueDescriptionListForAdd.get(i).getMediaId())
|
assertThat(sessionCallback.queueDescriptionListForAdd.get(i).getMediaId())
|
||||||
.isEqualTo(testList.get(i).mediaId);
|
.isEqualTo(testList.get(i).mediaId);
|
||||||
|
assertThat(sessionCallback.queueDescriptionListForAdd.get(i).getIconBitmap()).isNotNull();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,6 +394,75 @@ public class MediaSessionCompatCallbackWithMediaControllerTest {
|
|||||||
assertThat(sessionCallback.onSkipToNextCalled).isTrue();
|
assertThat(sessionCallback.onSkipToNextCalled).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setMediaItems_nonEmptyList_startFromFirstMediaItem() throws Exception {
|
||||||
|
int size = 3;
|
||||||
|
List<MediaItem> testList = MediaTestUtils.createMediaItemsWithArtworkData(size);
|
||||||
|
|
||||||
|
session.setFlags(FLAG_HANDLES_QUEUE_COMMANDS);
|
||||||
|
setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
|
||||||
|
RemoteMediaController controller = createControllerAndWaitConnection();
|
||||||
|
sessionCallback.reset(size);
|
||||||
|
|
||||||
|
controller.setMediaItems(testList);
|
||||||
|
|
||||||
|
assertThat(sessionCallback.await(TIMEOUT_MS)).isTrue();
|
||||||
|
assertThat(sessionCallback.onPlayFromMediaIdCalled).isTrue();
|
||||||
|
assertThat(sessionCallback.mediaId).isEqualTo(testList.get(0).mediaId);
|
||||||
|
for (int i = 0; i < size - 1; i++) {
|
||||||
|
assertThat(sessionCallback.queueIndices.get(i)).isEqualTo(i);
|
||||||
|
assertThat(sessionCallback.queueDescriptionListForAdd.get(i).getMediaId())
|
||||||
|
.isEqualTo(testList.get(i + 1).mediaId);
|
||||||
|
assertThat(sessionCallback.queueDescriptionListForAdd.get(i).getIconBitmap()).isNotNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setMediaItems_nonEmptyList_startFromNonFirstMediaItem() throws Exception {
|
||||||
|
int size = 5;
|
||||||
|
List<MediaItem> testList = MediaTestUtils.createMediaItemsWithArtworkData(size);
|
||||||
|
|
||||||
|
session.setFlags(FLAG_HANDLES_QUEUE_COMMANDS);
|
||||||
|
setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
|
||||||
|
RemoteMediaController controller = createControllerAndWaitConnection();
|
||||||
|
sessionCallback.reset(size);
|
||||||
|
int testStartIndex = 2;
|
||||||
|
|
||||||
|
controller.setMediaItems(testList, testStartIndex, /* startPositionMs= */ C.TIME_UNSET);
|
||||||
|
|
||||||
|
assertThat(sessionCallback.await(TIMEOUT_MS)).isTrue();
|
||||||
|
assertThat(sessionCallback.onPlayFromMediaIdCalled).isTrue();
|
||||||
|
assertThat(sessionCallback.mediaId).isEqualTo(testList.get(testStartIndex).mediaId);
|
||||||
|
for (int i = 0; i < size - 1; i++) {
|
||||||
|
assertThat(sessionCallback.queueIndices.get(i)).isEqualTo(i);
|
||||||
|
int adjustedIndex = (i < testStartIndex) ? i : i + 1;
|
||||||
|
assertThat(sessionCallback.queueDescriptionListForAdd.get(i).getMediaId())
|
||||||
|
.isEqualTo(testList.get(adjustedIndex).mediaId);
|
||||||
|
assertThat(sessionCallback.queueDescriptionListForAdd.get(i).getIconBitmap()).isNotNull();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void setMediaItems_emptyList() throws Exception {
|
||||||
|
int size = 3;
|
||||||
|
List<MediaItem> testList = MediaTestUtils.createMediaItems(size);
|
||||||
|
List<QueueItem> testQueue = MediaTestUtils.convertToQueueItemsWithoutBitmap(testList);
|
||||||
|
|
||||||
|
session.setQueue(testQueue);
|
||||||
|
session.setFlags(FLAG_HANDLES_QUEUE_COMMANDS);
|
||||||
|
setPlaybackState(PlaybackStateCompat.STATE_PLAYING);
|
||||||
|
RemoteMediaController controller = createControllerAndWaitConnection();
|
||||||
|
sessionCallback.reset(size);
|
||||||
|
|
||||||
|
controller.setMediaItems(ImmutableList.of());
|
||||||
|
|
||||||
|
assertThat(sessionCallback.await(TIMEOUT_MS)).isTrue();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
assertThat(sessionCallback.queueDescriptionListForRemove.get(i).getMediaId())
|
||||||
|
.isEqualTo(testList.get(i).mediaId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void setShuffleMode() throws Exception {
|
public void setShuffleMode() throws Exception {
|
||||||
session.setShuffleMode(PlaybackStateCompat.SHUFFLE_MODE_NONE);
|
session.setShuffleMode(PlaybackStateCompat.SHUFFLE_MODE_NONE);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user