diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java index d8f4074c68..563af3bc37 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java @@ -293,18 +293,16 @@ public final class PlaybackStatsListener } private void maybeAddSessions(Player player, Events events) { - if (player.getCurrentTimeline().isEmpty() && player.getPlaybackState() == Player.STATE_IDLE) { - // Player is completely idle. Don't add new sessions. - return; - } + boolean isCompletelyIdle = + player.getCurrentTimeline().isEmpty() && player.getPlaybackState() == Player.STATE_IDLE; for (int i = 0; i < events.size(); i++) { @EventFlags int event = events.get(i); EventTime eventTime = events.getEventTime(event); if (event == EVENT_TIMELINE_CHANGED) { sessionManager.updateSessionsWithTimelineChange(eventTime); - } else if (event == EVENT_POSITION_DISCONTINUITY) { + } else if (!isCompletelyIdle && event == EVENT_POSITION_DISCONTINUITY) { sessionManager.updateSessionsWithDiscontinuity(eventTime, discontinuityReason); - } else { + } else if (!isCompletelyIdle) { sessionManager.updateSessions(eventTime); } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/analytics/PlaybackStatsListenerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/analytics/PlaybackStatsListenerTest.java index c736444a43..e99f6a6d65 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/analytics/PlaybackStatsListenerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/analytics/PlaybackStatsListenerTest.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.analytics; +import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.runUntilPendingCommandsAreFullyHandled; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -42,6 +43,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; +import org.robolectric.shadows.ShadowLooper; /** Unit test for {@link PlaybackStatsListener}. */ @RunWith(AndroidJUnit4.class) @@ -151,6 +153,35 @@ public final class PlaybackStatsListenerTest { verify(callback).onPlaybackStatsReady(any(), any()); } + @Test + public void playlistClear_callsAllPendingCallbacks() throws Exception { + PlaybackStatsListener.Callback callback = mock(PlaybackStatsListener.Callback.class); + PlaybackStatsListener playbackStatsListener = + new PlaybackStatsListener(/* keepHistory= */ true, callback); + player.addAnalyticsListener(playbackStatsListener); + + MediaSource mediaSource = new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1)); + player.setMediaSources(ImmutableList.of(mediaSource, mediaSource)); + player.prepare(); + TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_READY); + // Play close to the end of the first item to ensure the second session is already created, but + // the first one isn't finished yet. + TestPlayerRunHelper.playUntilPosition( + player, /* windowIndex= */ 0, /* positionMs= */ player.getDuration()); + runUntilPendingCommandsAreFullyHandled(player); + player.clearMediaItems(); + ShadowLooper.idleMainLooper(); + + ArgumentCaptor eventTimeCaptor = + ArgumentCaptor.forClass(AnalyticsListener.EventTime.class); + verify(callback, times(2)).onPlaybackStatsReady(eventTimeCaptor.capture(), any()); + assertThat( + eventTimeCaptor.getAllValues().stream() + .map(eventTime -> eventTime.windowIndex) + .collect(Collectors.toList())) + .containsExactly(0, 1); + } + @Test public void playerRelease_callsAllPendingCallbacks() throws Exception { PlaybackStatsListener.Callback callback = mock(PlaybackStatsListener.Callback.class);