diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 6d3ea9ac62..63d2cacbdd 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -35,6 +35,9 @@ * Muxers: * IMA extension: * Session: + * Keep notification visible when playback enters an error or stopped + state. The notification is only removed if the playlist is cleared or + the player is released. * UI: * Downloads: * OkHttp Extension: diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java b/libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java index 14f2406a97..fc4ccdce6d 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaNotificationManager.java @@ -251,9 +251,7 @@ import java.util.concurrent.TimeoutException; private boolean shouldShowNotification(MediaSession session) { MediaController controller = getConnectedControllerForSession(session); - return controller != null - && !controller.getCurrentTimeline().isEmpty() - && controller.getPlaybackState() != Player.STATE_IDLE; + return controller != null && !controller.getCurrentTimeline().isEmpty(); } @Nullable diff --git a/libraries/session/src/test/java/androidx/media3/session/MediaSessionServiceTest.java b/libraries/session/src/test/java/androidx/media3/session/MediaSessionServiceTest.java index aeb6908a00..97daf26a99 100644 --- a/libraries/session/src/test/java/androidx/media3/session/MediaSessionServiceTest.java +++ b/libraries/session/src/test/java/androidx/media3/session/MediaSessionServiceTest.java @@ -67,6 +67,55 @@ public class MediaSessionServiceTest { (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); } + @Test + public void service_sessionIdleNoMedia_createsNoNotification() { + ExoPlayer player = new TestExoPlayerBuilder(context).build(); + MediaSession session = new MediaSession.Builder(context, player).build(); + ServiceController serviceController = Robolectric.buildService(TestService.class); + TestService service = serviceController.create().get(); + service.setMediaNotificationProvider( + new DefaultMediaNotificationProvider( + service, + /* notificationIdProvider= */ unused -> 2000, + DefaultMediaNotificationProvider.DEFAULT_CHANNEL_ID, + DefaultMediaNotificationProvider.DEFAULT_CHANNEL_NAME_RESOURCE_ID)); + service.addSession(session); + + // Give the service a chance to create a notification. + ShadowLooper.idleMainLooper(); + + assertThat(getStatusBarNotification(2000)).isNull(); + + session.release(); + player.release(); + serviceController.destroy(); + } + + @Test + public void service_sessionIdleWithMedia_createsNotification() { + ExoPlayer player = new TestExoPlayerBuilder(context).build(); + MediaSession session = new MediaSession.Builder(context, player).build(); + ServiceController serviceController = Robolectric.buildService(TestService.class); + TestService service = serviceController.create().get(); + service.setMediaNotificationProvider( + new DefaultMediaNotificationProvider( + service, + /* notificationIdProvider= */ unused -> 2000, + DefaultMediaNotificationProvider.DEFAULT_CHANNEL_ID, + DefaultMediaNotificationProvider.DEFAULT_CHANNEL_NAME_RESOURCE_ID)); + service.addSession(session); + + // Add media and give the service a chance to create a notification. + player.setMediaItem(MediaItem.fromUri("asset:///media/mp4/sample.mp4")); + ShadowLooper.idleMainLooper(); + + assertThat(getStatusBarNotification(2000)).isNotNull(); + + session.release(); + player.release(); + serviceController.destroy(); + } + @Test public void service_multipleSessionsOnMainThread_createsNotificationForEachSession() { ExoPlayer player1 = new TestExoPlayerBuilder(context).build();