mirror of
https://github.com/androidx/media.git
synced 2025-05-05 06:30:24 +08:00
Trigger media item transition event in CastPlayer
#minor-release PiperOrigin-RevId: 361803897
This commit is contained in:
parent
ff8db9a4fe
commit
b74bfa1e9a
@ -63,6 +63,8 @@
|
||||
* Fix `onPositionDiscontinuity` event so that it is not triggered with
|
||||
reason `DISCONTINUITY_REASON_PERIOD_TRANSITION` after a seek to another
|
||||
media item and so that it is not triggered after a timeline change.
|
||||
* Trigger `onMediaItemTransition` event for all reasons except
|
||||
`MEDIA_ITEM_TRANSITION_REASON_REPEAT`.
|
||||
|
||||
### 2.13.2 (2021-02-25)
|
||||
|
||||
|
@ -440,6 +440,13 @@ public final class CastPlayer extends BasePlayer {
|
||||
if (getCurrentWindowIndex() != windowIndex) {
|
||||
remoteMediaClient.queueJumpToItem((int) currentTimeline.getPeriod(windowIndex, period).uid,
|
||||
positionMs, null).setResultCallback(seekResultCallback);
|
||||
// TODO(internal b/182261884): queue `onMediaItemTransition` event when the media item is
|
||||
// repeated.
|
||||
MediaItem mediaItem = currentTimeline.getWindow(windowIndex, window).mediaItem;
|
||||
listeners.queueEvent(
|
||||
Player.EVENT_MEDIA_ITEM_TRANSITION,
|
||||
listener ->
|
||||
listener.onMediaItemTransition(mediaItem, MEDIA_ITEM_TRANSITION_REASON_SEEK));
|
||||
} else {
|
||||
remoteMediaClient.seek(positionMs).setResultCallback(seekResultCallback);
|
||||
}
|
||||
@ -637,6 +644,11 @@ public final class CastPlayer extends BasePlayer {
|
||||
listeners.queueEvent(
|
||||
Player.EVENT_POSITION_DISCONTINUITY,
|
||||
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_REASON_PERIOD_TRANSITION));
|
||||
listeners.queueEvent(
|
||||
Player.EVENT_MEDIA_ITEM_TRANSITION,
|
||||
listener ->
|
||||
listener.onMediaItemTransition(
|
||||
getCurrentMediaItem(), MEDIA_ITEM_TRANSITION_REASON_AUTO));
|
||||
}
|
||||
if (updateTracksAndSelectionsAndNotifyIfChanged()) {
|
||||
listeners.queueEvent(
|
||||
@ -681,6 +693,8 @@ public final class CastPlayer extends BasePlayer {
|
||||
|
||||
@SuppressWarnings("deprecation") // Calling deprecated listener method.
|
||||
private void updateTimelineAndNotifyIfChanged() {
|
||||
Timeline previousTimeline = currentTimeline;
|
||||
int previousWindowIndex = currentWindowIndex;
|
||||
if (updateTimeline()) {
|
||||
// TODO: Differentiate TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED and
|
||||
// TIMELINE_CHANGE_REASON_SOURCE_UPDATE [see internal: b/65152553].
|
||||
@ -692,7 +706,26 @@ public final class CastPlayer extends BasePlayer {
|
||||
timeline, /* manifest= */ null, Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE);
|
||||
listener.onTimelineChanged(timeline, Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE);
|
||||
});
|
||||
|
||||
updateAvailableCommandsAndNotifyIfChanged();
|
||||
|
||||
boolean mediaItemTransitioned;
|
||||
if (currentTimeline.isEmpty() && previousTimeline.isEmpty()) {
|
||||
mediaItemTransitioned = false;
|
||||
} else if (currentTimeline.isEmpty() != previousTimeline.isEmpty()) {
|
||||
mediaItemTransitioned = true;
|
||||
} else {
|
||||
Object previousWindowUid = previousTimeline.getWindow(previousWindowIndex, window).uid;
|
||||
Object currentWindowUid = currentTimeline.getWindow(currentWindowIndex, window).uid;
|
||||
mediaItemTransitioned = !currentWindowUid.equals(previousWindowUid);
|
||||
}
|
||||
if (mediaItemTransitioned) {
|
||||
listeners.queueEvent(
|
||||
Player.EVENT_MEDIA_ITEM_TRANSITION,
|
||||
listener ->
|
||||
listener.onMediaItemTransition(
|
||||
getCurrentMediaItem(), MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -80,8 +80,8 @@ public class CastPlayerTest {
|
||||
setResultCallbackArgumentCaptor;
|
||||
|
||||
@Captor private ArgumentCaptor<RemoteMediaClient.Callback> callbackArgumentCaptor;
|
||||
|
||||
@Captor private ArgumentCaptor<MediaQueueItem[]> queueItemsArgumentCaptor;
|
||||
@Captor private ArgumentCaptor<MediaItem> mediaItemCaptor;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Before
|
||||
@ -457,9 +457,107 @@ public class CastPlayerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addMediaItems_notifiesMediaItemTransition() {
|
||||
MediaItem mediaItem = createMediaItem(/* mediaQueueItemId= */ 1);
|
||||
List<MediaItem> mediaItems = ImmutableList.of(mediaItem);
|
||||
int[] mediaQueueItemIds = new int[] {1};
|
||||
|
||||
addMediaItemsAndUpdateTimeline(mediaItems, mediaQueueItemIds);
|
||||
|
||||
verify(mockListener)
|
||||
.onMediaItemTransition(
|
||||
mediaItemCaptor.capture(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
|
||||
assertThat(mediaItemCaptor.getValue().playbackProperties.tag)
|
||||
.isEqualTo(mediaItem.playbackProperties.tag);
|
||||
verify(mockListener).onMediaItemTransition(any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearMediaItems_notifiesMediaItemTransition() {
|
||||
int[] mediaQueueItemIds = new int[] {1, 2};
|
||||
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
|
||||
|
||||
addMediaItemsAndUpdateTimeline(mediaItems, mediaQueueItemIds);
|
||||
verify(mockListener).onMediaItemTransition(any(), anyInt());
|
||||
|
||||
clearMediaItemsAndUpdateTimeline();
|
||||
verify(mockListener)
|
||||
.onMediaItemTransition(
|
||||
/* mediaItem= */ null, Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED);
|
||||
verify(mockListener, times(2)).onMediaItemTransition(any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeCurrentMediaItem_notifiesMediaItemTransition() {
|
||||
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
|
||||
MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2);
|
||||
List<MediaItem> mediaItems = ImmutableList.of(mediaItem1, mediaItem2);
|
||||
int[] mediaQueueItemIds = new int[] {1, 2};
|
||||
|
||||
addMediaItemsAndUpdateTimeline(mediaItems, mediaQueueItemIds);
|
||||
verify(mockListener).onMediaItemTransition(any(), anyInt());
|
||||
|
||||
removeMediaItemsAndUpdateTimeline(
|
||||
mediaItems, mediaQueueItemIds, /* fromIndex= */ 0, /* toIndex= */ 1);
|
||||
verify(mockListener, times(2))
|
||||
.onMediaItemTransition(
|
||||
mediaItemCaptor.capture(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_PLAYLIST_CHANGED));
|
||||
assertThat(mediaItemCaptor.getValue().playbackProperties.tag)
|
||||
.isEqualTo(mediaItem2.playbackProperties.tag);
|
||||
verify(mockListener, times(2)).onMediaItemTransition(any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removeNonCurrentMediaItem_doesNotNotifyMediaItemTransition() {
|
||||
int[] mediaQueueItemIds = new int[] {1, 2};
|
||||
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
|
||||
|
||||
addMediaItemsAndUpdateTimeline(mediaItems, mediaQueueItemIds);
|
||||
verify(mockListener).onMediaItemTransition(any(), anyInt());
|
||||
|
||||
removeMediaItemsAndUpdateTimeline(
|
||||
mediaItems, mediaQueueItemIds, /* fromIndex= */ 1, /* toIndex= */ 2);
|
||||
verify(mockListener).onMediaItemTransition(any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void seekTo_otherWindow_notifiesMediaItemTransition() {
|
||||
when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null)))
|
||||
.thenReturn(mockPendingResult);
|
||||
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
|
||||
MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2);
|
||||
List<MediaItem> mediaItems = ImmutableList.of(mediaItem1, mediaItem2);
|
||||
int[] mediaQueueItemIds = new int[] {1, 2};
|
||||
|
||||
addMediaItemsAndUpdateTimeline(mediaItems, mediaQueueItemIds);
|
||||
verify(mockListener).onMediaItemTransition(any(), anyInt());
|
||||
|
||||
castPlayer.seekTo(/* windowIndex= */ 1, /* positionMs= */ 0);
|
||||
verify(mockListener)
|
||||
.onMediaItemTransition(
|
||||
mediaItemCaptor.capture(), eq(Player.MEDIA_ITEM_TRANSITION_REASON_SEEK));
|
||||
assertThat(mediaItemCaptor.getValue().playbackProperties.tag)
|
||||
.isEqualTo(mediaItem2.playbackProperties.tag);
|
||||
verify(mockListener, times(2)).onMediaItemTransition(any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer.
|
||||
public void seekTo_sameWindow_doesNotNotifyMediaItemTransition() {
|
||||
when(mockRemoteMediaClient.seek(anyLong())).thenReturn(mockPendingResult);
|
||||
int[] mediaQueueItemIds = new int[] {1, 2};
|
||||
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
|
||||
|
||||
addMediaItemsAndUpdateTimeline(mediaItems, mediaQueueItemIds);
|
||||
verify(mockListener).onMediaItemTransition(any(), anyInt());
|
||||
|
||||
castPlayer.seekTo(/* windowIndex= */ 0, /* positionMs= */ 0);
|
||||
verify(mockListener).onMediaItemTransition(any(), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void seekTo_otherWindow_notifiesAvailableCommandsChanged() {
|
||||
when(mockRemoteMediaClient.play()).thenReturn(mockPendingResult);
|
||||
when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null)))
|
||||
.thenReturn(mockPendingResult);
|
||||
Player.Commands commandsWithHasNext =
|
||||
@ -488,7 +586,6 @@ public class CastPlayerTest {
|
||||
|
||||
@Test
|
||||
public void addMediaItems_whenLastPlaying_notifiesAvailableCommandsChanged() {
|
||||
when(mockRemoteMediaClient.play()).thenReturn(mockPendingResult);
|
||||
Player.Commands commandsWithHasNext =
|
||||
new Player.Commands.Builder().add(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM).build();
|
||||
int[] mediaQueueItemIds = new int[] {1};
|
||||
@ -519,7 +616,6 @@ public class CastPlayerTest {
|
||||
|
||||
@Test
|
||||
public void removeMediaItems_followingCurrent_notifiesAvailableCommandsChanged() {
|
||||
when(mockRemoteMediaClient.play()).thenReturn(mockPendingResult);
|
||||
Player.Commands commandsWithHasNext =
|
||||
new Player.Commands.Builder().add(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM).build();
|
||||
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
|
||||
@ -550,7 +646,6 @@ public class CastPlayerTest {
|
||||
|
||||
@Test
|
||||
public void setRepeatMode_all_notifiesAvailableCommandsChanged() {
|
||||
when(mockRemoteMediaClient.play()).thenReturn(mockPendingResult);
|
||||
when(mockRemoteMediaClient.queueSetRepeatMode(anyInt(), eq(null)))
|
||||
.thenReturn(mockPendingResult);
|
||||
Player.Commands commandsWithHasNext =
|
||||
@ -568,7 +663,6 @@ public class CastPlayerTest {
|
||||
|
||||
@Test
|
||||
public void setRepeatMode_one_doesNotNotifyAvailableCommandsChanged() {
|
||||
when(mockRemoteMediaClient.play()).thenReturn(mockPendingResult);
|
||||
when(mockRemoteMediaClient.queueSetRepeatMode(anyInt(), eq(null)))
|
||||
.thenReturn(mockPendingResult);
|
||||
int[] mediaQueueItemIds = new int[] {1};
|
||||
@ -658,6 +752,11 @@ public class CastPlayerTest {
|
||||
updateTimeLine(mediaItems, mediaQueueItemIds);
|
||||
}
|
||||
|
||||
private void clearMediaItemsAndUpdateTimeline() {
|
||||
castPlayer.clearMediaItems();
|
||||
updateTimeLine(ImmutableList.of(), new int[0]);
|
||||
}
|
||||
|
||||
private void updateTimeLine(List<MediaItem> mediaItems, int[] mediaQueueItemIds) {
|
||||
List<MediaQueueItem> queueItems = new ArrayList<>();
|
||||
DefaultMediaItemConverter converter = new DefaultMediaItemConverter();
|
||||
|
Loading…
x
Reference in New Issue
Block a user