Load bitmaps for MediaMetadataCompat
and handle the metadata updates.
* Add `Listener` in `MediaSession` with method `onNotificationRefreshRequired(MediaSession)`. * Add `MediaSessionService` as the listener of the `MediaSession` when `MediaSession` is added to `MediaSessionService` * Load bitmap when update metadata in `MediaSessionLegacyStub` and call `onNotificationRefreshRequired` when bitmap asynchronously arrives. PiperOrigin-RevId: 485376145
This commit is contained in:
parent
a65ff85a98
commit
77fedd8d7d
@ -859,6 +859,11 @@ public class MediaSession {
|
||||
impl.setSessionPositionUpdateDelayMsOnHandler(updateDelayMs);
|
||||
}
|
||||
|
||||
/** Sets the {@linkplain Listener listener}. */
|
||||
/* package */ void setListener(@Nullable Listener listener) {
|
||||
impl.setMediaSessionListener(listener);
|
||||
}
|
||||
|
||||
private Uri getUri() {
|
||||
return impl.getUri();
|
||||
}
|
||||
@ -1240,6 +1245,17 @@ public class MediaSession {
|
||||
default void onRenderedFirstFrame(int seq) throws RemoteException {}
|
||||
}
|
||||
|
||||
/** Listener for media session events */
|
||||
/* package */ interface Listener {
|
||||
|
||||
/**
|
||||
* Called when the notification requires to be refreshed.
|
||||
*
|
||||
* @param session The media session for which the notification requires to be refreshed.
|
||||
*/
|
||||
void onNotificationRefreshRequired(MediaSession session);
|
||||
}
|
||||
|
||||
/**
|
||||
* A base class for {@link MediaSession.Builder} and {@link
|
||||
* MediaLibraryService.MediaLibrarySession.Builder}. Any changes to this class should be also
|
||||
|
@ -119,6 +119,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
||||
private final BitmapLoader bitmapLoader;
|
||||
|
||||
@Nullable private PlayerListener playerListener;
|
||||
@Nullable private MediaSession.Listener mediaSessionListener;
|
||||
|
||||
private PlayerInfo playerInfo;
|
||||
private PlayerWrapper playerWrapper;
|
||||
@ -573,6 +574,16 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
||||
}
|
||||
}
|
||||
|
||||
/* package */ void setMediaSessionListener(@Nullable MediaSession.Listener listener) {
|
||||
this.mediaSessionListener = listener;
|
||||
}
|
||||
|
||||
/* package */ void onNotificationRefreshRequired() {
|
||||
if (this.mediaSessionListener != null) {
|
||||
this.mediaSessionListener.onNotificationRefreshRequired(instance);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchRemoteControllerTaskToLegacyStub(RemoteControllerTask task) {
|
||||
try {
|
||||
task.run(sessionLegacyStub.getControllerLegacyCbForBroadcast(), /* seq= */ 0);
|
||||
|
@ -44,6 +44,7 @@ import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
@ -114,8 +115,10 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
||||
private final MediaPlayPauseKeyHandler mediaPlayPauseKeyHandler;
|
||||
private final MediaSessionCompat sessionCompat;
|
||||
@Nullable private VolumeProviderCompat volumeProviderCompat;
|
||||
private final Handler mainHandler;
|
||||
|
||||
private volatile long connectionTimeoutMs;
|
||||
@Nullable private FutureCallback<Bitmap> pendingBitmapLoadCallback;
|
||||
|
||||
public MediaSessionLegacyStub(
|
||||
MediaSessionImpl session,
|
||||
@ -156,6 +159,7 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
||||
@Initialized
|
||||
MediaSessionLegacyStub thisRef = this;
|
||||
sessionCompat.setCallback(thisRef, handler);
|
||||
mainHandler = new Handler(Looper.getMainLooper());
|
||||
}
|
||||
|
||||
/** Starts to receive commands. */
|
||||
@ -1110,11 +1114,52 @@ import org.checkerframework.checker.initialization.qual.Initialized;
|
||||
currentMediaItemForMetadataUpdate = currentMediaItem;
|
||||
durationMsForMetadataUpdate = durationMs;
|
||||
|
||||
if (currentMediaItem == null) {
|
||||
setMetadata(sessionCompat, /* metadataCompat= */ null);
|
||||
return;
|
||||
}
|
||||
|
||||
@Nullable Bitmap artworkBitmap = null;
|
||||
ListenableFuture<Bitmap> bitmapFuture =
|
||||
sessionImpl.getBitmapLoader().loadBitmapFromMetadata(currentMediaItem.mediaMetadata);
|
||||
if (bitmapFuture != null) {
|
||||
pendingBitmapLoadCallback = null;
|
||||
if (bitmapFuture.isDone()) {
|
||||
try {
|
||||
artworkBitmap = Futures.getDone(bitmapFuture);
|
||||
} catch (ExecutionException e) {
|
||||
Log.w(TAG, "Failed to load bitmap", e);
|
||||
}
|
||||
} else {
|
||||
pendingBitmapLoadCallback =
|
||||
new FutureCallback<Bitmap>() {
|
||||
@Override
|
||||
public void onSuccess(Bitmap result) {
|
||||
if (this != pendingBitmapLoadCallback) {
|
||||
return;
|
||||
}
|
||||
setMetadata(
|
||||
sessionCompat,
|
||||
MediaUtils.convertToMediaMetadataCompat(
|
||||
currentMediaItem, durationMs, result));
|
||||
sessionImpl.onNotificationRefreshRequired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
if (this != pendingBitmapLoadCallback) {
|
||||
return;
|
||||
}
|
||||
Log.d(TAG, "Failed to load bitmap", t);
|
||||
}
|
||||
};
|
||||
Futures.addCallback(
|
||||
bitmapFuture, pendingBitmapLoadCallback, /* executor= */ mainHandler::post);
|
||||
}
|
||||
}
|
||||
setMetadata(
|
||||
sessionCompat,
|
||||
currentMediaItem != null
|
||||
? MediaUtils.convertToMediaMetadataCompat(currentMediaItem, durationMs)
|
||||
: null);
|
||||
MediaUtils.convertToMediaMetadataCompat(currentMediaItem, durationMs, artworkBitmap));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,6 +239,7 @@ public abstract class MediaSessionService extends Service {
|
||||
// TODO(b/191644474): Check whether the session is registered to multiple services.
|
||||
MediaNotificationManager notificationManager = getMediaNotificationManager();
|
||||
postOrRun(mainHandler, () -> notificationManager.addSession(session));
|
||||
session.setListener(this::onUpdateNotification);
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,6 +259,7 @@ public abstract class MediaSessionService extends Service {
|
||||
}
|
||||
MediaNotificationManager notificationManager = getMediaNotificationManager();
|
||||
postOrRun(mainHandler, () -> notificationManager.removeSession(session));
|
||||
session.setListener(null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -525,7 +525,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
|
||||
/** Converts a {@link MediaItem} to a {@link MediaMetadataCompat}. */
|
||||
public static MediaMetadataCompat convertToMediaMetadataCompat(
|
||||
MediaItem mediaItem, long durationMs) {
|
||||
MediaItem mediaItem, long durationMs, @Nullable Bitmap artworkBitmap) {
|
||||
MediaMetadataCompat.Builder builder =
|
||||
new MediaMetadataCompat.Builder()
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, mediaItem.mediaId);
|
||||
@ -574,11 +574,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
||||
MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, metadata.artworkUri.toString());
|
||||
}
|
||||
|
||||
if (metadata.artworkData != null) {
|
||||
Bitmap artwork =
|
||||
BitmapFactory.decodeByteArray(metadata.artworkData, 0, metadata.artworkData.length);
|
||||
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, artwork);
|
||||
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, artwork);
|
||||
if (artworkBitmap != null) {
|
||||
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, artworkBitmap);
|
||||
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, artworkBitmap);
|
||||
}
|
||||
|
||||
if (metadata.folderType != null && metadata.folderType != MediaMetadata.FOLDER_TYPE_NONE) {
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
@ -16,9 +16,13 @@
|
||||
package androidx.media3.test.session.common;
|
||||
|
||||
import static android.content.Context.KEYGUARD_SERVICE;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.KeyguardManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.WindowManager;
|
||||
@ -28,6 +32,9 @@ import androidx.media3.common.Player;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.common.util.Util;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Locale;
|
||||
|
||||
/** Provides utility methods for testing purpose. */
|
||||
@ -40,6 +47,9 @@ public class TestUtils {
|
||||
public static final long VOLUME_CHANGE_TIMEOUT_MS = 5_000;
|
||||
public static final long LONG_TIMEOUT_MS = 20_000;
|
||||
|
||||
private static final int MAX_BITMAP_WIDTH = 500;
|
||||
private static final int MAX_BITMAP_HEIGHT = 500;
|
||||
|
||||
/**
|
||||
* Compares contents of two throwables for both message and class.
|
||||
*
|
||||
@ -143,5 +153,32 @@ public class TestUtils {
|
||||
return list.build();
|
||||
}
|
||||
|
||||
/** Returns the bytes of a scaled asset file. */
|
||||
public static byte[] getByteArrayForScaledBitmap(Context context, String fileName)
|
||||
throws IOException {
|
||||
Bitmap bitmap = getBitmap(context, fileName);
|
||||
int width = min(bitmap.getWidth(), MAX_BITMAP_WIDTH);
|
||||
int height = min(bitmap.getHeight(), MAX_BITMAP_HEIGHT);
|
||||
return convertToByteArray(Bitmap.createScaledBitmap(bitmap, width, height, true));
|
||||
}
|
||||
|
||||
/** Returns an {@link InputStream} for reading from an asset file. */
|
||||
public static InputStream getInputStream(Context context, String fileName) throws IOException {
|
||||
return context.getResources().getAssets().open(fileName);
|
||||
}
|
||||
|
||||
/** Returns a {@link Bitmap} read from an asset file. */
|
||||
public static Bitmap getBitmap(Context context, String fileName) throws IOException {
|
||||
return BitmapFactory.decodeStream(getInputStream(context, fileName));
|
||||
}
|
||||
|
||||
/** Converts the given {@link Bitmap} to an array of bytes. */
|
||||
public static byte[] convertToByteArray(Bitmap bitmap) throws IOException {
|
||||
try (ByteArrayOutputStream stream = new ByteArrayOutputStream()) {
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, /* ignored */ 0, stream);
|
||||
return stream.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
private TestUtils() {}
|
||||
}
|
||||
|
@ -32,12 +32,16 @@ android {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
sourceSets.main.assets.srcDir '../test_data/src/test/assets/'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(modulePrefix + 'lib-session')
|
||||
implementation project(modulePrefix + 'test-session-common')
|
||||
implementation 'androidx.media:media:' + androidxMediaVersion
|
||||
implementation 'androidx.test:core:' + androidxTestCoreVersion
|
||||
implementation project(path: ':test-data')
|
||||
androidTestImplementation project(modulePrefix + 'lib-exoplayer')
|
||||
androidTestImplementation 'androidx.test.ext:junit:' + androidxTestJUnitVersion
|
||||
androidTestImplementation 'androidx.test.ext:truth:' + androidxTestTruthVersion
|
||||
|
@ -39,10 +39,12 @@ import static androidx.media3.test.session.common.CommonConstants.SUPPORT_APP_PA
|
||||
import static androidx.media3.test.session.common.TestUtils.TIMEOUT_MS;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.media.AudioManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
@ -113,11 +115,13 @@ public class MediaControllerWithMediaSessionCompatTest {
|
||||
|
||||
private Context context;
|
||||
private RemoteMediaSessionCompat session;
|
||||
private BitmapLoader bitmapLoader;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
context = ApplicationProvider.getApplicationContext();
|
||||
session = new RemoteMediaSessionCompat(DEFAULT_TEST_NAME, context);
|
||||
bitmapLoader = new CacheBitmapLoader(new SimpleBitmapLoader());
|
||||
}
|
||||
|
||||
@After
|
||||
@ -697,12 +701,14 @@ public class MediaControllerWithMediaSessionCompatTest {
|
||||
List<QueueItem> testQueue = MediaUtils.convertToQueueItemList(testList);
|
||||
MediaItem testRemoveMediaItem = MediaTestUtils.createMediaItem("removed");
|
||||
MediaMetadataCompat testMetadataCompat =
|
||||
MediaUtils.convertToMediaMetadataCompat(testRemoveMediaItem, /* durationMs= */ 100L);
|
||||
MediaUtils.convertToMediaMetadataCompat(
|
||||
testRemoveMediaItem, /* durationMs= */ 100L, /* artworkBitmap= */ null);
|
||||
session.setQueue(testQueue);
|
||||
session.setMetadata(testMetadataCompat);
|
||||
MediaController controller = controllerTestRule.createController(session.getSessionToken());
|
||||
|
||||
int mediaItemCount = threadTestRule.getHandler().postAndSync(controller::getMediaItemCount);
|
||||
|
||||
assertThat(mediaItemCount).isEqualTo(testList.size() + 1);
|
||||
}
|
||||
|
||||
@ -713,7 +719,8 @@ public class MediaControllerWithMediaSessionCompatTest {
|
||||
List<QueueItem> testQueue = MediaUtils.convertToQueueItemList(testList);
|
||||
MediaItem testRemoveMediaItem = MediaTestUtils.createMediaItem("removed");
|
||||
MediaMetadataCompat testMetadataCompat =
|
||||
MediaUtils.convertToMediaMetadataCompat(testRemoveMediaItem, /* durationMs= */ 100L);
|
||||
MediaUtils.convertToMediaMetadataCompat(
|
||||
testRemoveMediaItem, /* durationMs= */ 100L, /* artworkBitmap= */ null);
|
||||
session.setQueue(testQueue);
|
||||
session.setMetadata(testMetadataCompat);
|
||||
MediaController controller = controllerTestRule.createController(session.getSessionToken());
|
||||
@ -732,9 +739,11 @@ public class MediaControllerWithMediaSessionCompatTest {
|
||||
new PlaybackStateCompat.Builder()
|
||||
.setActiveQueueItemId(testQueue.get(0).getQueueId())
|
||||
.build());
|
||||
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
|
||||
int mediaItemCount = threadTestRule.getHandler().postAndSync(controller::getMediaItemCount);
|
||||
|
||||
assertThat(mediaItemCount).isEqualTo(testList.size());
|
||||
}
|
||||
|
||||
@ -745,13 +754,15 @@ public class MediaControllerWithMediaSessionCompatTest {
|
||||
List<QueueItem> testQueue = MediaUtils.convertToQueueItemList(testList);
|
||||
MediaItem testRemoveMediaItem = MediaTestUtils.createMediaItem("removed");
|
||||
MediaMetadataCompat testMetadataCompat =
|
||||
MediaUtils.convertToMediaMetadataCompat(testRemoveMediaItem, /* durationMs= */ 100L);
|
||||
MediaUtils.convertToMediaMetadataCompat(
|
||||
testRemoveMediaItem, /* durationMs= */ 100L, /* artworkBitmap= */ null);
|
||||
session.setQueue(testQueue);
|
||||
session.setMetadata(testMetadataCompat);
|
||||
MediaController controller = controllerTestRule.createController(session.getSessionToken());
|
||||
|
||||
int mediaItemIndex =
|
||||
threadTestRule.getHandler().postAndSync(controller::getCurrentMediaItemIndex);
|
||||
|
||||
assertThat(mediaItemIndex).isEqualTo(testList.size());
|
||||
}
|
||||
|
||||
@ -761,12 +772,46 @@ public class MediaControllerWithMediaSessionCompatTest {
|
||||
MediaItem testMediaItem = MediaTestUtils.createMediaItem("test");
|
||||
MediaMetadata testMediaMetadata = testMediaItem.mediaMetadata;
|
||||
MediaMetadataCompat testMediaMetadataCompat =
|
||||
MediaUtils.convertToMediaMetadataCompat(testMediaItem, /* durationMs= */ 100L);
|
||||
MediaUtils.convertToMediaMetadataCompat(
|
||||
testMediaItem, /* durationMs= */ 100L, /* artworkBitmap= */ null);
|
||||
session.setMetadata(testMediaMetadataCompat);
|
||||
MediaController controller = controllerTestRule.createController(session.getSessionToken());
|
||||
|
||||
MediaMetadata mediaMetadata =
|
||||
threadTestRule.getHandler().postAndSync(controller::getMediaMetadata);
|
||||
|
||||
assertThat(mediaMetadata).isEqualTo(testMediaMetadata);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMediaMetadata_withMediaMetadataCompatAndArtworkData_returnsConvertedMediaMetadata()
|
||||
throws Exception {
|
||||
MediaItem testMediaItem = MediaTestUtils.createMediaItemWithArtworkData("test");
|
||||
MediaMetadata testMediaMetadata = testMediaItem.mediaMetadata;
|
||||
@Nullable Bitmap artworkBitmap = getBitmapFromMetadata(testMediaMetadata);
|
||||
MediaMetadataCompat testMediaMetadataCompat =
|
||||
MediaUtils.convertToMediaMetadataCompat(
|
||||
testMediaItem, /* durationMs= */ 100L, artworkBitmap);
|
||||
session.setMetadata(testMediaMetadataCompat);
|
||||
MediaController controller = controllerTestRule.createController(session.getSessionToken());
|
||||
|
||||
MediaMetadata mediaMetadata =
|
||||
threadTestRule.getHandler().postAndSync(controller::getMediaMetadata);
|
||||
|
||||
assertThat(mediaMetadata.artworkData).isNotNull();
|
||||
if (Util.SDK_INT < 21) {
|
||||
// Bitmap conversion and back gives not exactly the same byte array below API 21
|
||||
mediaMetadata =
|
||||
mediaMetadata
|
||||
.buildUpon()
|
||||
.setArtworkData(/* artworkData= */ null, /* artworkDataType= */ null)
|
||||
.build();
|
||||
testMediaMetadata =
|
||||
testMediaMetadata
|
||||
.buildUpon()
|
||||
.setArtworkData(/* artworkData= */ null, /* artworkDataType= */ null)
|
||||
.build();
|
||||
}
|
||||
assertThat(mediaMetadata).isEqualTo(testMediaMetadata);
|
||||
}
|
||||
|
||||
@ -1085,7 +1130,8 @@ public class MediaControllerWithMediaSessionCompatTest {
|
||||
public void setPlaybackState_fromStateBufferingToPlaying_notifiesReadyState() throws Exception {
|
||||
List<MediaItem> testPlaylist = MediaTestUtils.createMediaItems(/* size= */ 1);
|
||||
MediaMetadataCompat metadata =
|
||||
MediaUtils.convertToMediaMetadataCompat(testPlaylist.get(0), /* durationMs= */ 50_000);
|
||||
MediaUtils.convertToMediaMetadataCompat(
|
||||
testPlaylist.get(0), /* durationMs= */ 50_000, /* artworkBitmap= */ null);
|
||||
long testBufferedPosition = 5_000;
|
||||
session.setMetadata(metadata);
|
||||
session.setPlaybackState(
|
||||
@ -1129,7 +1175,8 @@ public class MediaControllerWithMediaSessionCompatTest {
|
||||
throws Exception {
|
||||
List<MediaItem> testPlaylist = MediaTestUtils.createMediaItems(1);
|
||||
MediaMetadataCompat metadata =
|
||||
MediaUtils.convertToMediaMetadataCompat(testPlaylist.get(0), /* durationMs= */ 1_000);
|
||||
MediaUtils.convertToMediaMetadataCompat(
|
||||
testPlaylist.get(0), /* durationMs= */ 1_000, /* artworkBitmap= */ null);
|
||||
long testBufferingPosition = 0;
|
||||
session.setMetadata(metadata);
|
||||
session.setPlaybackState(
|
||||
@ -1689,4 +1736,14 @@ public class MediaControllerWithMediaSessionCompatTest {
|
||||
threadTestRule.getHandler().postAndSync(controller::getTotalBufferedDuration);
|
||||
assertThat(totalBufferedDurationMs).isEqualTo(testTotalBufferedDurationMs);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Bitmap getBitmapFromMetadata(MediaMetadata metadata) throws Exception {
|
||||
@Nullable Bitmap bitmap = null;
|
||||
@Nullable ListenableFuture<Bitmap> bitmapFuture = bitmapLoader.loadBitmapFromMetadata(metadata);
|
||||
if (bitmapFuture != null) {
|
||||
bitmap = bitmapFuture.get(10, SECONDS);
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,10 @@ package androidx.media3.session;
|
||||
import static android.support.v4.media.MediaMetadataCompat.METADATA_KEY_DURATION;
|
||||
import static android.support.v4.media.session.MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
import android.service.media.MediaBrowserService;
|
||||
@ -31,6 +33,7 @@ import android.support.v4.media.session.MediaControllerCompat;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
import android.support.v4.media.session.PlaybackStateCompat;
|
||||
import android.text.TextUtils;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media.AudioAttributesCompat;
|
||||
import androidx.media3.common.AudioAttributes;
|
||||
import androidx.media3.common.C;
|
||||
@ -46,6 +49,7 @@ import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.SdkSuppress;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@ -59,10 +63,12 @@ import org.junit.runner.RunWith;
|
||||
public final class MediaUtilsTest {
|
||||
|
||||
private Context context;
|
||||
private BitmapLoader bitmapLoader;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
context = ApplicationProvider.getApplicationContext();
|
||||
bitmapLoader = new CacheBitmapLoader(new SimpleBitmapLoader());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -199,14 +205,24 @@ public final class MediaUtilsTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void convertToMediaMetadata_roundTrip_returnsEqualMediaItem() {
|
||||
MediaItem testMediaItem = MediaTestUtils.createMediaItem("testZZZ");
|
||||
public void convertToMediaMetadata_roundTrip_returnsEqualMediaItem() throws Exception {
|
||||
MediaItem testMediaItem = MediaTestUtils.createMediaItemWithArtworkData("testZZZ");
|
||||
MediaMetadata testMediaMetadata = testMediaItem.mediaMetadata;
|
||||
@Nullable Bitmap testArtworkBitmap = null;
|
||||
@Nullable
|
||||
ListenableFuture<Bitmap> bitmapFuture = bitmapLoader.loadBitmapFromMetadata(testMediaMetadata);
|
||||
if (bitmapFuture != null) {
|
||||
testArtworkBitmap = bitmapFuture.get(10, SECONDS);
|
||||
}
|
||||
MediaMetadataCompat testMediaMetadataCompat =
|
||||
MediaUtils.convertToMediaMetadataCompat(testMediaItem, /* durationMs= */ 100L);
|
||||
MediaUtils.convertToMediaMetadataCompat(
|
||||
testMediaItem, /* durationMs= */ 100L, testArtworkBitmap);
|
||||
|
||||
MediaMetadata mediaMetadata =
|
||||
MediaUtils.convertToMediaMetadata(testMediaMetadataCompat, RatingCompat.RATING_NONE);
|
||||
|
||||
assertThat(mediaMetadata).isEqualTo(testMediaMetadata);
|
||||
assertThat(mediaMetadata.artworkData).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -23,6 +23,7 @@ import static androidx.media3.test.session.common.CommonConstants.METADATA_TITLE
|
||||
import static androidx.media3.test.session.common.CommonConstants.SUPPORT_APP_PACKAGE_NAME;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.media.MediaBrowserCompat;
|
||||
@ -38,6 +39,8 @@ import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.session.MediaLibraryService.LibraryParams;
|
||||
import androidx.media3.session.MediaSession.ControllerInfo;
|
||||
import androidx.media3.test.session.common.TestUtils;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ -47,6 +50,8 @@ public final class MediaTestUtils {
|
||||
|
||||
private static final String TAG = "MediaTestUtils";
|
||||
|
||||
private static final String TEST_IMAGE_PATH = "media/png/non-motion-photo-shortened.png";
|
||||
|
||||
/** Create a media item with the mediaId for testing purpose. */
|
||||
public static MediaItem createMediaItem(String mediaId) {
|
||||
MediaMetadata mediaMetadata =
|
||||
@ -57,6 +62,23 @@ public final class MediaTestUtils {
|
||||
return new MediaItem.Builder().setMediaId(mediaId).setMediaMetadata(mediaMetadata).build();
|
||||
}
|
||||
|
||||
public static MediaItem createMediaItemWithArtworkData(String mediaId) {
|
||||
MediaMetadata.Builder mediaMetadataBuilder =
|
||||
new MediaMetadata.Builder()
|
||||
.setFolderType(MediaMetadata.FOLDER_TYPE_NONE)
|
||||
.setIsPlayable(true);
|
||||
try {
|
||||
byte[] artworkData =
|
||||
TestUtils.getByteArrayForScaledBitmap(
|
||||
ApplicationProvider.getApplicationContext(), TEST_IMAGE_PATH);
|
||||
mediaMetadataBuilder.setArtworkData(artworkData, MediaMetadata.PICTURE_TYPE_FRONT_COVER);
|
||||
} catch (IOException e) {
|
||||
fail(e.getMessage());
|
||||
}
|
||||
MediaMetadata mediaMetadata = mediaMetadataBuilder.build();
|
||||
return new MediaItem.Builder().setMediaId(mediaId).setMediaMetadata(mediaMetadata).build();
|
||||
}
|
||||
|
||||
public static ArrayList<MediaItem> createMediaItems(int size) {
|
||||
ArrayList<MediaItem> list = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
@ -65,6 +87,14 @@ public final class MediaTestUtils {
|
||||
return list;
|
||||
}
|
||||
|
||||
public static ArrayList<MediaItem> createMediaItemsWithArtworkData(int size) {
|
||||
ArrayList<MediaItem> list = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
list.add(createMediaItemWithArtworkData("mediaItem_" + (i + 1)));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<MediaItem> createMediaItems(String... mediaIds) {
|
||||
List<MediaItem> list = new ArrayList<>();
|
||||
for (int i = 0; i < mediaIds.length; i++) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user