diff --git a/libraries/session/src/main/java/androidx/media3/session/DefaultMediaNotificationProvider.java b/libraries/session/src/main/java/androidx/media3/session/DefaultMediaNotificationProvider.java index c3acb2a83d..6b2368df7d 100644 --- a/libraries/session/src/main/java/androidx/media3/session/DefaultMediaNotificationProvider.java +++ b/libraries/session/src/main/java/androidx/media3/session/DefaultMediaNotificationProvider.java @@ -319,33 +319,35 @@ public class DefaultMediaNotificationProvider implements MediaNotification.Provi mediaStyle.setShowActionsInCompactView(compactViewIndices); // Set metadata info in the notification. - MediaMetadata metadata = player.getMediaMetadata(); - builder - .setContentTitle(getNotificationContentTitle(metadata)) - .setContentText(getNotificationContentText(metadata)); - @Nullable - ListenableFuture bitmapFuture = - mediaSession.getBitmapLoader().loadBitmapFromMetadata(metadata); - if (bitmapFuture != null) { - if (pendingOnBitmapLoadedFutureCallback != null) { - pendingOnBitmapLoadedFutureCallback.discardIfPending(); - } - if (bitmapFuture.isDone()) { - try { - builder.setLargeIcon(Futures.getDone(bitmapFuture)); - } catch (ExecutionException e) { - Log.w(TAG, getBitmapLoadErrorMessage(e)); + if (player.isCommandAvailable(Player.COMMAND_GET_MEDIA_ITEMS_METADATA)) { + MediaMetadata metadata = player.getMediaMetadata(); + builder + .setContentTitle(getNotificationContentTitle(metadata)) + .setContentText(getNotificationContentText(metadata)); + @Nullable + ListenableFuture bitmapFuture = + mediaSession.getBitmapLoader().loadBitmapFromMetadata(metadata); + if (bitmapFuture != null) { + if (pendingOnBitmapLoadedFutureCallback != null) { + pendingOnBitmapLoadedFutureCallback.discardIfPending(); + } + if (bitmapFuture.isDone()) { + try { + builder.setLargeIcon(Futures.getDone(bitmapFuture)); + } catch (ExecutionException e) { + Log.w(TAG, getBitmapLoadErrorMessage(e)); + } + } else { + pendingOnBitmapLoadedFutureCallback = + new OnBitmapLoadedFutureCallback( + notificationId, builder, onNotificationChangedCallback); + Futures.addCallback( + bitmapFuture, + pendingOnBitmapLoadedFutureCallback, + // This callback must be executed on the next looper iteration, after this method has + // returned a media notification. + mainHandler::post); } - } else { - pendingOnBitmapLoadedFutureCallback = - new OnBitmapLoadedFutureCallback( - notificationId, builder, onNotificationChangedCallback); - Futures.addCallback( - bitmapFuture, - pendingOnBitmapLoadedFutureCallback, - // This callback must be executed on the next looper iteration, after this method has - // returned a media notification. - mainHandler::post); } } diff --git a/libraries/session/src/test/java/androidx/media3/session/DefaultMediaNotificationProviderTest.java b/libraries/session/src/test/java/androidx/media3/session/DefaultMediaNotificationProviderTest.java index fe7616bce3..e696979c6c 100644 --- a/libraries/session/src/test/java/androidx/media3/session/DefaultMediaNotificationProviderTest.java +++ b/libraries/session/src/test/java/androidx/media3/session/DefaultMediaNotificationProviderTest.java @@ -20,6 +20,7 @@ import static androidx.media3.session.DefaultMediaNotificationProvider.DEFAULT_C import static androidx.media3.session.DefaultMediaNotificationProvider.DEFAULT_NOTIFICATION_ID; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -628,6 +629,33 @@ public class DefaultMediaNotificationProviderTest { assertThat(isMediaMetadataArtistEqualToNotificationContentText).isTrue(); } + @Test + public void + setMediaMetadata_withoutAvailableCommandToGetMetadata_doesNotUseMetadataForNotification() { + Context context = ApplicationProvider.getApplicationContext(); + DefaultMediaNotificationProvider defaultMediaNotificationProvider = + new DefaultMediaNotificationProvider.Builder(context).build(); + DefaultActionFactory defaultActionFactory = + new DefaultActionFactory(Robolectric.setupService(TestService.class)); + MediaSession mockMediaSession = + createMockMediaSessionForNotification( + new MediaMetadata.Builder().setArtist("artist").setTitle("title").build(), + /* getMetadataCommandAvailable= */ false); + BitmapLoader mockBitmapLoader = mock(BitmapLoader.class); + when(mockBitmapLoader.loadBitmapFromMetadata(any())).thenReturn(null); + when(mockMediaSession.getBitmapLoader()).thenReturn(mockBitmapLoader); + + MediaNotification notification = + defaultMediaNotificationProvider.createNotification( + mockMediaSession, + ImmutableList.of(), + defaultActionFactory, + mock(MediaNotification.Provider.Callback.class)); + + assertThat(NotificationCompat.getContentText(notification.notification)).isNull(); + assertThat(NotificationCompat.getContentTitle(notification.notification)).isNull(); + } + /** * {@link DefaultMediaNotificationProvider} is designed to be extendable. Public constructor * should not be removed. @@ -720,9 +748,22 @@ public class DefaultMediaNotificationProviderTest { } private static MediaSession createMockMediaSessionForNotification(MediaMetadata mediaMetadata) { + return createMockMediaSessionForNotification( + mediaMetadata, /* getMetadataCommandAvailable= */ true); + } + + private static MediaSession createMockMediaSessionForNotification( + MediaMetadata mediaMetadata, boolean getMetadataCommandAvailable) { Player mockPlayer = mock(Player.class); - when(mockPlayer.getAvailableCommands()).thenReturn(Commands.EMPTY); - when(mockPlayer.getMediaMetadata()).thenReturn(mediaMetadata); + when(mockPlayer.isCommandAvailable(anyInt())).thenReturn(false); + if (getMetadataCommandAvailable) { + when(mockPlayer.getAvailableCommands()) + .thenReturn(new Commands.Builder().add(Player.COMMAND_GET_MEDIA_ITEMS_METADATA).build()); + when(mockPlayer.isCommandAvailable(Player.COMMAND_GET_MEDIA_ITEMS_METADATA)).thenReturn(true); + when(mockPlayer.getMediaMetadata()).thenReturn(mediaMetadata); + } else { + when(mockPlayer.getAvailableCommands()).thenReturn(Commands.EMPTY); + } MediaSession mockMediaSession = mock(MediaSession.class); when(mockMediaSession.getPlayer()).thenReturn(mockPlayer); MediaSessionImpl mockMediaSessionImpl = mock(MediaSessionImpl.class);