diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSession.java b/libraries/session/src/main/java/androidx/media3/session/MediaSession.java index a2b58d3cfe..2697fd11dd 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSession.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSession.java @@ -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 diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java index 68f8eee074..4cbbb83222 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java @@ -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); diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionLegacyStub.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionLegacyStub.java index 90d4eeb1e8..5e8ae12591 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionLegacyStub.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionLegacyStub.java @@ -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 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 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() { + @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)); } } diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java index 7bb17e342f..0e8d21cca4 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionService.java @@ -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); } /** diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaUtils.java b/libraries/session/src/main/java/androidx/media3/session/MediaUtils.java index 644e625554..f73ca3cfcb 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaUtils.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaUtils.java @@ -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) { diff --git a/libraries/test_data/src/test/assets/media/png/non-motion-photo-shortened.png b/libraries/test_data/src/test/assets/media/png/non-motion-photo-shortened.png new file mode 100644 index 0000000000..b51eaa6511 Binary files /dev/null and b/libraries/test_data/src/test/assets/media/png/non-motion-photo-shortened.png differ diff --git a/libraries/test_session_common/src/main/java/androidx/media3/test/session/common/TestUtils.java b/libraries/test_session_common/src/main/java/androidx/media3/test/session/common/TestUtils.java index 3975e98410..fe90b5bd04 100644 --- a/libraries/test_session_common/src/main/java/androidx/media3/test/session/common/TestUtils.java +++ b/libraries/test_session_common/src/main/java/androidx/media3/test/session/common/TestUtils.java @@ -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() {} } diff --git a/libraries/test_session_current/build.gradle b/libraries/test_session_current/build.gradle index 429b89881a..93c1c99c65 100644 --- a/libraries/test_session_current/build.gradle +++ b/libraries/test_session_current/build.gradle @@ -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 diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerWithMediaSessionCompatTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerWithMediaSessionCompatTest.java index d5109f05af..724c82492b 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerWithMediaSessionCompatTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerWithMediaSessionCompatTest.java @@ -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 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 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 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 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 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 bitmapFuture = bitmapLoader.loadBitmapFromMetadata(metadata); + if (bitmapFuture != null) { + bitmap = bitmapFuture.get(10, SECONDS); + } + return bitmap; + } } diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaUtilsTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaUtilsTest.java index cbde70120c..1d53a84794 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaUtilsTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaUtilsTest.java @@ -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 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 diff --git a/libraries/test_session_current/src/main/java/androidx/media3/session/MediaTestUtils.java b/libraries/test_session_current/src/main/java/androidx/media3/session/MediaTestUtils.java index e6d5d24632..2b1cd045ce 100644 --- a/libraries/test_session_current/src/main/java/androidx/media3/session/MediaTestUtils.java +++ b/libraries/test_session_current/src/main/java/androidx/media3/session/MediaTestUtils.java @@ -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 createMediaItems(int size) { ArrayList list = new ArrayList<>(); for (int i = 0; i < size; i++) { @@ -65,6 +87,14 @@ public final class MediaTestUtils { return list; } + public static ArrayList createMediaItemsWithArtworkData(int size) { + ArrayList list = new ArrayList<>(); + for (int i = 0; i < size; i++) { + list.add(createMediaItemWithArtworkData("mediaItem_" + (i + 1))); + } + return list; + } + public static List createMediaItems(String... mediaIds) { List list = new ArrayList<>(); for (int i = 0; i < mediaIds.length; i++) {