Commit 6c9f9f9d by kimvde Committed by Oliver Woodman

Add available command to seek in current item

PiperOrigin-RevId: 362972550
parent 46aab922
...@@ -21,6 +21,7 @@ import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS; ...@@ -21,6 +21,7 @@ import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS;
import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS_METADATA; import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS_METADATA;
import static com.google.android.exoplayer2.Player.COMMAND_PLAY_PAUSE; import static com.google.android.exoplayer2.Player.COMMAND_PLAY_PAUSE;
import static com.google.android.exoplayer2.Player.COMMAND_PREPARE_STOP_RELEASE; import static com.google.android.exoplayer2.Player.COMMAND_PREPARE_STOP_RELEASE;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM; import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM; import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SET_REPEAT_MODE; import static com.google.android.exoplayer2.Player.COMMAND_SET_REPEAT_MODE;
...@@ -31,6 +32,7 @@ import static org.mockito.ArgumentMatchers.any; ...@@ -31,6 +32,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
...@@ -55,9 +57,9 @@ import com.google.android.gms.cast.framework.media.MediaQueue; ...@@ -55,9 +57,9 @@ import com.google.android.gms.cast.framework.media.MediaQueue;
import com.google.android.gms.cast.framework.media.RemoteMediaClient; import com.google.android.gms.cast.framework.media.RemoteMediaClient;
import com.google.android.gms.common.api.PendingResult; import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback; import com.google.android.gms.common.api.ResultCallback;
import com.google.android.gms.common.api.Status;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.junit.Before; import org.junit.Before;
...@@ -66,32 +68,26 @@ import org.junit.runner.RunWith; ...@@ -66,32 +68,26 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.mockito.Captor; import org.mockito.Captor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
/** Tests for {@link CastPlayer}. */ /** Tests for {@link CastPlayer}. */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class CastPlayerTest { public class CastPlayerTest {
private CastPlayer castPlayer; private CastPlayer castPlayer;
private RemoteMediaClient.Callback remoteMediaClientCallback; private RemoteMediaClient.Callback remoteMediaClientCallback;
@Mock private RemoteMediaClient mockRemoteMediaClient; @Mock private RemoteMediaClient mockRemoteMediaClient;
@Mock private MediaStatus mockMediaStatus; @Mock private MediaStatus mockMediaStatus;
@Mock private MediaInfo mockMediaInfo;
@Mock private MediaQueue mockMediaQueue; @Mock private MediaQueue mockMediaQueue;
@Mock private MediaQueueItem mockMediaQueueItem;
@Mock private CastContext mockCastContext; @Mock private CastContext mockCastContext;
@Mock private SessionManager mockSessionManager; @Mock private SessionManager mockSessionManager;
@Mock private CastSession mockCastSession; @Mock private CastSession mockCastSession;
@Mock private Player.EventListener mockListener; @Mock private Player.EventListener mockListener;
@Mock private PendingResult<RemoteMediaClient.MediaChannelResult> mockPendingResult; @Mock private PendingResult<RemoteMediaClient.MediaChannelResult> mockPendingResult;
@Mock private RemoteMediaClient.MediaChannelResult mediaChannelResultMock;
@Captor @Captor
private ArgumentCaptor<ResultCallback<RemoteMediaClient.MediaChannelResult>> private ArgumentCaptor<ResultCallback<RemoteMediaClient.MediaChannelResult>>
setResultCallbackArgumentCaptor; setResultCallbackArgumentCaptor;
@Captor private ArgumentCaptor<RemoteMediaClient.Callback> callbackArgumentCaptor; @Captor private ArgumentCaptor<RemoteMediaClient.Callback> callbackArgumentCaptor;
@Captor private ArgumentCaptor<MediaQueueItem[]> queueItemsArgumentCaptor; @Captor private ArgumentCaptor<MediaQueueItem[]> queueItemsArgumentCaptor;
@Captor private ArgumentCaptor<MediaItem> mediaItemCaptor; @Captor private ArgumentCaptor<MediaItem> mediaItemCaptor;
...@@ -106,8 +102,6 @@ public class CastPlayerTest { ...@@ -106,8 +102,6 @@ public class CastPlayerTest {
when(mockRemoteMediaClient.getMediaStatus()).thenReturn(mockMediaStatus); when(mockRemoteMediaClient.getMediaStatus()).thenReturn(mockMediaStatus);
when(mockRemoteMediaClient.getMediaQueue()).thenReturn(mockMediaQueue); when(mockRemoteMediaClient.getMediaQueue()).thenReturn(mockMediaQueue);
when(mockMediaQueue.getItemIds()).thenReturn(new int[0]); when(mockMediaQueue.getItemIds()).thenReturn(new int[0]);
when(mockRemoteMediaClient.getCurrentItem()).thenReturn(mockMediaQueueItem);
when(mediaChannelResultMock.getStatus()).thenReturn(Status.RESULT_SUCCESS);
// Make the remote media client present the same default values as ExoPlayer: // Make the remote media client present the same default values as ExoPlayer:
when(mockRemoteMediaClient.isPaused()).thenReturn(true); when(mockRemoteMediaClient.isPaused()).thenReturn(true);
when(mockMediaStatus.getQueueRepeatMode()).thenReturn(MediaStatus.REPEAT_MODE_REPEAT_OFF); when(mockMediaStatus.getQueueRepeatMode()).thenReturn(MediaStatus.REPEAT_MODE_REPEAT_OFF);
...@@ -138,7 +132,7 @@ public class CastPlayerTest { ...@@ -138,7 +132,7 @@ public class CastPlayerTest {
when(mockRemoteMediaClient.isPaused()).thenReturn(false); when(mockRemoteMediaClient.isPaused()).thenReturn(false);
setResultCallbackArgumentCaptor setResultCallbackArgumentCaptor
.getValue() .getValue()
.onResult(Mockito.mock(RemoteMediaClient.MediaChannelResult.class)); .onResult(mock(RemoteMediaClient.MediaChannelResult.class));
verifyNoMoreInteractions(mockListener); verifyNoMoreInteractions(mockListener);
} }
...@@ -158,7 +152,7 @@ public class CastPlayerTest { ...@@ -158,7 +152,7 @@ public class CastPlayerTest {
// Upon result, the remote media client is still paused. The state should reflect that. // Upon result, the remote media client is still paused. The state should reflect that.
setResultCallbackArgumentCaptor setResultCallbackArgumentCaptor
.getValue() .getValue()
.onResult(Mockito.mock(RemoteMediaClient.MediaChannelResult.class)); .onResult(mock(RemoteMediaClient.MediaChannelResult.class));
verify(mockListener).onPlayerStateChanged(false, Player.STATE_IDLE); verify(mockListener).onPlayerStateChanged(false, Player.STATE_IDLE);
verify(mockListener).onPlayWhenReadyChanged(false, Player.PLAY_WHEN_READY_CHANGE_REASON_REMOTE); verify(mockListener).onPlayWhenReadyChanged(false, Player.PLAY_WHEN_READY_CHANGE_REASON_REMOTE);
assertThat(castPlayer.getPlayWhenReady()).isFalse(); assertThat(castPlayer.getPlayWhenReady()).isFalse();
...@@ -212,7 +206,7 @@ public class CastPlayerTest { ...@@ -212,7 +206,7 @@ public class CastPlayerTest {
when(mockMediaStatus.getQueueRepeatMode()).thenReturn(MediaStatus.REPEAT_MODE_REPEAT_SINGLE); when(mockMediaStatus.getQueueRepeatMode()).thenReturn(MediaStatus.REPEAT_MODE_REPEAT_SINGLE);
setResultCallbackArgumentCaptor setResultCallbackArgumentCaptor
.getValue() .getValue()
.onResult(Mockito.mock(RemoteMediaClient.MediaChannelResult.class)); .onResult(mock(RemoteMediaClient.MediaChannelResult.class));
verifyNoMoreInteractions(mockListener); verifyNoMoreInteractions(mockListener);
} }
...@@ -233,7 +227,7 @@ public class CastPlayerTest { ...@@ -233,7 +227,7 @@ public class CastPlayerTest {
// Upon result, the repeat mode is ALL. The state should reflect that. // Upon result, the repeat mode is ALL. The state should reflect that.
setResultCallbackArgumentCaptor setResultCallbackArgumentCaptor
.getValue() .getValue()
.onResult(Mockito.mock(RemoteMediaClient.MediaChannelResult.class)); .onResult(mock(RemoteMediaClient.MediaChannelResult.class));
verify(mockListener).onRepeatModeChanged(Player.REPEAT_MODE_ALL); verify(mockListener).onRepeatModeChanged(Player.REPEAT_MODE_ALL);
assertThat(castPlayer.getRepeatMode()).isEqualTo(Player.REPEAT_MODE_ALL); assertThat(castPlayer.getRepeatMode()).isEqualTo(Player.REPEAT_MODE_ALL);
} }
...@@ -599,6 +593,7 @@ public class CastPlayerTest { ...@@ -599,6 +593,7 @@ public class CastPlayerTest {
assertThat(castPlayer.isCommandAvailable(COMMAND_PLAY_PAUSE)).isTrue(); assertThat(castPlayer.isCommandAvailable(COMMAND_PLAY_PAUSE)).isTrue();
assertThat(castPlayer.isCommandAvailable(COMMAND_PREPARE_STOP_RELEASE)).isTrue(); assertThat(castPlayer.isCommandAvailable(COMMAND_PREPARE_STOP_RELEASE)).isTrue();
assertThat(castPlayer.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)).isTrue();
assertThat(castPlayer.isCommandAvailable(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)).isTrue(); assertThat(castPlayer.isCommandAvailable(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)).isTrue();
assertThat(castPlayer.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)).isFalse(); assertThat(castPlayer.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)).isFalse();
assertThat(castPlayer.isCommandAvailable(COMMAND_SET_SPEED_AND_PITCH)).isFalse(); assertThat(castPlayer.isCommandAvailable(COMMAND_SET_SPEED_AND_PITCH)).isFalse();
...@@ -611,31 +606,50 @@ public class CastPlayerTest { ...@@ -611,31 +606,50 @@ public class CastPlayerTest {
} }
@Test @Test
public void isCommandAvailable_duringUnseekableItem_isFalseForSeekInCurrent() {
MediaItem mediaItem = createMediaItem(/* mediaQueueItemId= */ 1);
List<MediaItem> mediaItems = ImmutableList.of(mediaItem);
int[] mediaQueueItemIds = new int[] {1};
int[] streamTypes = new int[] {MediaInfo.STREAM_TYPE_LIVE};
long[] durationsMs = new long[] {C.TIME_UNSET};
castPlayer.addMediaItem(mediaItem);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1, streamTypes, durationsMs);
assertThat(castPlayer.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)).isFalse();
}
@Test
public void seekTo_nextWindow_notifiesAvailableCommandsChanged() { public void seekTo_nextWindow_notifiesAvailableCommandsChanged() {
when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null))) when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null)))
.thenReturn(mockPendingResult); .thenReturn(mockPendingResult);
Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); Player.Commands commandsWithSeekInCurrentAndToNext =
Player.Commands commandsWithSeekToPrevious = createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
createCommands(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); Player.Commands commandsWithSeekInCurrentAndToPrevious =
Player.Commands commandsWithSeekToNextAndPrevious = createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); Player.Commands commandsWithSeekAnywhere =
createCommands(
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM,
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
int[] mediaQueueItemIds = new int[] {1, 2, 3, 4}; int[] mediaQueueItemIds = new int[] {1, 2, 3, 4};
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds); List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
castPlayer.addMediaItems(mediaItems); castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1); updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrentAndToNext);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
castPlayer.seekTo(/* windowIndex= */ 1, /* positionMs= */ 0); castPlayer.seekTo(/* windowIndex= */ 1, /* positionMs= */ 0);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNextAndPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekAnywhere);
verify(mockListener, times(2)).onAvailableCommandsChanged(any()); verify(mockListener, times(2)).onAvailableCommandsChanged(any());
castPlayer.seekTo(/* windowIndex= */ 2, /* positionMs= */ 0); castPlayer.seekTo(/* windowIndex= */ 2, /* positionMs= */ 0);
verify(mockListener, times(2)).onAvailableCommandsChanged(any()); verify(mockListener, times(2)).onAvailableCommandsChanged(any());
castPlayer.seekTo(/* windowIndex= */ 3, /* positionMs= */ 0); castPlayer.seekTo(/* windowIndex= */ 3, /* positionMs= */ 0);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrentAndToPrevious);
verify(mockListener, times(3)).onAvailableCommandsChanged(any()); verify(mockListener, times(3)).onAvailableCommandsChanged(any());
} }
...@@ -643,28 +657,33 @@ public class CastPlayerTest { ...@@ -643,28 +657,33 @@ public class CastPlayerTest {
public void seekTo_previousWindow_notifiesAvailableCommandsChanged() { public void seekTo_previousWindow_notifiesAvailableCommandsChanged() {
when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null))) when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null)))
.thenReturn(mockPendingResult); .thenReturn(mockPendingResult);
Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); Player.Commands commandsWithSeekInCurrentAndToNext =
Player.Commands commandsWithSeekToPrevious = createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
createCommands(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); Player.Commands commandsWithSeekInCurrentAndToPrevious =
Player.Commands commandsWithSeekToNextAndPrevious = createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); Player.Commands commandsWithSeekAnywhere =
createCommands(
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM,
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
int[] mediaQueueItemIds = new int[] {1, 2, 3, 4}; int[] mediaQueueItemIds = new int[] {1, 2, 3, 4};
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds); List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
castPlayer.addMediaItems(mediaItems); castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 4); updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 4);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrentAndToPrevious);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
castPlayer.seekTo(/* windowIndex= */ 2, /* positionMs= */ 0); castPlayer.seekTo(/* windowIndex= */ 2, /* positionMs= */ 0);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNextAndPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekAnywhere);
verify(mockListener, times(2)).onAvailableCommandsChanged(any()); verify(mockListener, times(2)).onAvailableCommandsChanged(any());
castPlayer.seekTo(/* windowIndex= */ 1, /* positionMs= */ 0); castPlayer.seekTo(/* windowIndex= */ 1, /* positionMs= */ 0);
verify(mockListener, times(2)).onAvailableCommandsChanged(any()); verify(mockListener, times(2)).onAvailableCommandsChanged(any());
castPlayer.seekTo(/* windowIndex= */ 0, /* positionMs= */ 0); castPlayer.seekTo(/* windowIndex= */ 0, /* positionMs= */ 0);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrentAndToNext);
verify(mockListener, times(3)).onAvailableCommandsChanged(any()); verify(mockListener, times(3)).onAvailableCommandsChanged(any());
} }
...@@ -672,19 +691,25 @@ public class CastPlayerTest { ...@@ -672,19 +691,25 @@ public class CastPlayerTest {
@SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer. @SuppressWarnings("deprecation") // Mocks deprecated method used by the CastPlayer.
public void seekTo_sameWindow_doesNotNotifyAvailableCommandsChanged() { public void seekTo_sameWindow_doesNotNotifyAvailableCommandsChanged() {
when(mockRemoteMediaClient.seek(anyLong())).thenReturn(mockPendingResult); when(mockRemoteMediaClient.seek(anyLong())).thenReturn(mockPendingResult);
Player.Commands commandsWithSeekInCurrent = createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM);
int[] mediaQueueItemIds = new int[] {1}; int[] mediaQueueItemIds = new int[] {1};
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds); List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
castPlayer.addMediaItems(mediaItems); castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1); updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrent);
castPlayer.seekTo(/* windowIndex= */ 0, /* positionMs= */ 200); castPlayer.seekTo(/* windowIndex= */ 0, /* positionMs= */ 200);
castPlayer.seekTo(/* windowIndex= */ 0, /* positionMs= */ 100); castPlayer.seekTo(/* windowIndex= */ 0, /* positionMs= */ 100);
verify(mockListener, never()).onAvailableCommandsChanged(any()); // Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any());
} }
@Test @Test
public void addMediaItem_atTheEnd_notifiesAvailableCommandsChanged() { public void addMediaItem_atTheEnd_notifiesAvailableCommandsChanged() {
Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); Player.Commands commandsWithSeekInCurrent = createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM);
Player.Commands commandsWithSeekInCurrentAndToNext =
createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1); MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2); MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2);
MediaItem mediaItem3 = createMediaItem(/* mediaQueueItemId= */ 3); MediaItem mediaItem3 = createMediaItem(/* mediaQueueItemId= */ 3);
...@@ -694,28 +719,31 @@ public class CastPlayerTest { ...@@ -694,28 +719,31 @@ public class CastPlayerTest {
ImmutableList.of(mediaItem1), ImmutableList.of(mediaItem1),
/* mediaQueueItemIds= */ new int[] {1}, /* mediaQueueItemIds= */ new int[] {1},
/* currentItemId= */ 1); /* currentItemId= */ 1);
verify(mockListener, never()).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrent);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any());
castPlayer.addMediaItem(mediaItem2); castPlayer.addMediaItem(mediaItem2);
updateTimeLine( updateTimeLine(
ImmutableList.of(mediaItem1, mediaItem2), ImmutableList.of(mediaItem1, mediaItem2),
/* mediaQueueItemIds= */ new int[] {1, 2}, /* mediaQueueItemIds= */ new int[] {1, 2},
/* currentItemId= */ 1); /* currentItemId= */ 1);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrentAndToNext);
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener, times(2)).onAvailableCommandsChanged(any());
castPlayer.addMediaItem(mediaItem3); castPlayer.addMediaItem(mediaItem3);
updateTimeLine( updateTimeLine(
ImmutableList.of(mediaItem1, mediaItem2, mediaItem3), ImmutableList.of(mediaItem1, mediaItem2, mediaItem3),
/* mediaQueueItemIds= */ new int[] {1, 2, 3}, /* mediaQueueItemIds= */ new int[] {1, 2, 3},
/* currentItemId= */ 1); /* currentItemId= */ 1);
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener, times(2)).onAvailableCommandsChanged(any());
} }
@Test @Test
public void addMediaItem_atTheStart_notifiesAvailableCommandsChanged() { public void addMediaItem_atTheStart_notifiesAvailableCommandsChanged() {
Player.Commands commandsWithSeekToPrevious = Player.Commands commandsWithSeekInCurrent = createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM);
createCommands(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); Player.Commands commandsWithSeekInCurrentAndToPrevious =
createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1); MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2); MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2);
MediaItem mediaItem3 = createMediaItem(/* mediaQueueItemId= */ 3); MediaItem mediaItem3 = createMediaItem(/* mediaQueueItemId= */ 3);
...@@ -725,28 +753,32 @@ public class CastPlayerTest { ...@@ -725,28 +753,32 @@ public class CastPlayerTest {
ImmutableList.of(mediaItem1), ImmutableList.of(mediaItem1),
/* mediaQueueItemIds= */ new int[] {1}, /* mediaQueueItemIds= */ new int[] {1},
/* currentItemId= */ 1); /* currentItemId= */ 1);
verify(mockListener, never()).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrent);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any());
castPlayer.addMediaItem(/* index= */ 0, mediaItem2); castPlayer.addMediaItem(/* index= */ 0, mediaItem2);
updateTimeLine( updateTimeLine(
ImmutableList.of(mediaItem2, mediaItem1), ImmutableList.of(mediaItem2, mediaItem1),
/* mediaQueueItemIds= */ new int[] {2, 1}, /* mediaQueueItemIds= */ new int[] {2, 1},
/* currentItemId= */ 1); /* currentItemId= */ 1);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrentAndToPrevious);
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener, times(2)).onAvailableCommandsChanged(any());
castPlayer.addMediaItem(/* index= */ 0, mediaItem3); castPlayer.addMediaItem(/* index= */ 0, mediaItem3);
updateTimeLine( updateTimeLine(
ImmutableList.of(mediaItem3, mediaItem2, mediaItem1), ImmutableList.of(mediaItem3, mediaItem2, mediaItem1),
/* mediaQueueItemIds= */ new int[] {3, 2, 1}, /* mediaQueueItemIds= */ new int[] {3, 2, 1},
/* currentItemId= */ 1); /* currentItemId= */ 1);
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener, times(2)).onAvailableCommandsChanged(any());
} }
@Test @Test
public void removeMediaItem_atTheEnd_notifiesAvailableCommandsChanged() { public void removeMediaItem_atTheEnd_notifiesAvailableCommandsChanged() {
Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
Player.Commands commandsWithoutSeek = createCommands(); Player.Commands commandsWithoutSeek = createCommands();
Player.Commands commandsWithSeekInCurrent = createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM);
Player.Commands commandsWithSeekInCurrentAndToNext =
createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1); MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2); MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2);
MediaItem mediaItem3 = createMediaItem(/* mediaQueueItemId= */ 3); MediaItem mediaItem3 = createMediaItem(/* mediaQueueItemId= */ 3);
...@@ -756,7 +788,8 @@ public class CastPlayerTest { ...@@ -756,7 +788,8 @@ public class CastPlayerTest {
ImmutableList.of(mediaItem1, mediaItem2, mediaItem3), ImmutableList.of(mediaItem1, mediaItem2, mediaItem3),
/* mediaQueueItemIds= */ new int[] {1, 2, 3}, /* mediaQueueItemIds= */ new int[] {1, 2, 3},
/* currentItemId= */ 1); /* currentItemId= */ 1);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrentAndToNext);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
castPlayer.removeMediaItem(/* index= */ 2); castPlayer.removeMediaItem(/* index= */ 2);
...@@ -771,7 +804,7 @@ public class CastPlayerTest { ...@@ -771,7 +804,7 @@ public class CastPlayerTest {
ImmutableList.of(mediaItem1), ImmutableList.of(mediaItem1),
/* mediaQueueItemIds= */ new int[] {1}, /* mediaQueueItemIds= */ new int[] {1},
/* currentItemId= */ 1); /* currentItemId= */ 1);
verify(mockListener).onAvailableCommandsChanged(commandsWithoutSeek); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrent);
verify(mockListener, times(2)).onAvailableCommandsChanged(any()); verify(mockListener, times(2)).onAvailableCommandsChanged(any());
castPlayer.removeMediaItem(/* index= */ 0); castPlayer.removeMediaItem(/* index= */ 0);
...@@ -779,16 +812,18 @@ public class CastPlayerTest { ...@@ -779,16 +812,18 @@ public class CastPlayerTest {
ImmutableList.of(), ImmutableList.of(),
/* mediaQueueItemIds= */ new int[0], /* mediaQueueItemIds= */ new int[0],
/* currentItemId= */ C.INDEX_UNSET); /* currentItemId= */ C.INDEX_UNSET);
verify(mockListener, times(2)).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(commandsWithoutSeek);
verify(mockListener, times(3)).onAvailableCommandsChanged(any());
} }
@Test @Test
public void removeMediaItem_atTheStart_notifiesAvailableCommandsChanged() { public void removeMediaItem_atTheStart_notifiesAvailableCommandsChanged() {
when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null))) when(mockRemoteMediaClient.queueJumpToItem(anyInt(), anyLong(), eq(null)))
.thenReturn(mockPendingResult); .thenReturn(mockPendingResult);
Player.Commands commandsWithSeekToPrevious =
createCommands(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
Player.Commands commandsWithoutSeek = createCommands(); Player.Commands commandsWithoutSeek = createCommands();
Player.Commands commandsWithSeekInCurrent = createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM);
Player.Commands commandsWithSeekInCurrentAndToPrevious =
createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1); MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2); MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2);
MediaItem mediaItem3 = createMediaItem(/* mediaQueueItemId= */ 3); MediaItem mediaItem3 = createMediaItem(/* mediaQueueItemId= */ 3);
...@@ -798,7 +833,8 @@ public class CastPlayerTest { ...@@ -798,7 +833,8 @@ public class CastPlayerTest {
ImmutableList.of(mediaItem1, mediaItem2, mediaItem3), ImmutableList.of(mediaItem1, mediaItem2, mediaItem3),
/* mediaQueueItemIds= */ new int[] {1, 2, 3}, /* mediaQueueItemIds= */ new int[] {1, 2, 3},
/* currentItemId= */ 3); /* currentItemId= */ 3);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrentAndToPrevious);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
castPlayer.removeMediaItem(/* index= */ 0); castPlayer.removeMediaItem(/* index= */ 0);
...@@ -813,7 +849,7 @@ public class CastPlayerTest { ...@@ -813,7 +849,7 @@ public class CastPlayerTest {
ImmutableList.of(mediaItem3), ImmutableList.of(mediaItem3),
/* mediaQueueItemIds= */ new int[] {3}, /* mediaQueueItemIds= */ new int[] {3},
/* currentItemId= */ 3); /* currentItemId= */ 3);
verify(mockListener).onAvailableCommandsChanged(commandsWithoutSeek); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrent);
verify(mockListener, times(2)).onAvailableCommandsChanged(any()); verify(mockListener, times(2)).onAvailableCommandsChanged(any());
castPlayer.removeMediaItem(/* index= */ 0); castPlayer.removeMediaItem(/* index= */ 0);
...@@ -821,13 +857,15 @@ public class CastPlayerTest { ...@@ -821,13 +857,15 @@ public class CastPlayerTest {
ImmutableList.of(), ImmutableList.of(),
/* mediaQueueItemIds= */ new int[0], /* mediaQueueItemIds= */ new int[0],
/* currentItemId= */ C.INDEX_UNSET); /* currentItemId= */ C.INDEX_UNSET);
verify(mockListener, times(2)).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(commandsWithoutSeek);
verify(mockListener, times(3)).onAvailableCommandsChanged(any());
} }
@Test @Test
public void removeMediaItem_current_notifiesAvailableCommandsChanged() { public void removeMediaItem_current_notifiesAvailableCommandsChanged() {
Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); Player.Commands commandsWithSeekInCurrent = createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM);
Player.Commands commandsWithoutSeek = createCommands(); Player.Commands commandsWithSeekInCurrentAndToNext =
createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1); MediaItem mediaItem1 = createMediaItem(/* mediaQueueItemId= */ 1);
MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2); MediaItem mediaItem2 = createMediaItem(/* mediaQueueItemId= */ 2);
...@@ -836,7 +874,8 @@ public class CastPlayerTest { ...@@ -836,7 +874,8 @@ public class CastPlayerTest {
ImmutableList.of(mediaItem1, mediaItem2), ImmutableList.of(mediaItem1, mediaItem2),
/* mediaQueueItemIds= */ new int[] {1, 2}, /* mediaQueueItemIds= */ new int[] {1, 2},
/* currentItemId= */ 1); /* currentItemId= */ 1);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrentAndToNext);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
castPlayer.removeMediaItem(/* index= */ 0); castPlayer.removeMediaItem(/* index= */ 0);
...@@ -844,7 +883,7 @@ public class CastPlayerTest { ...@@ -844,7 +883,7 @@ public class CastPlayerTest {
ImmutableList.of(mediaItem2), ImmutableList.of(mediaItem2),
/* mediaQueueItemIds= */ new int[] {2}, /* mediaQueueItemIds= */ new int[] {2},
/* currentItemId= */ 2); /* currentItemId= */ 2);
verify(mockListener).onAvailableCommandsChanged(commandsWithoutSeek); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrent);
verify(mockListener, times(2)).onAvailableCommandsChanged(any()); verify(mockListener, times(2)).onAvailableCommandsChanged(any());
} }
...@@ -852,31 +891,42 @@ public class CastPlayerTest { ...@@ -852,31 +891,42 @@ public class CastPlayerTest {
public void setRepeatMode_all_notifiesAvailableCommandsChanged() { public void setRepeatMode_all_notifiesAvailableCommandsChanged() {
when(mockRemoteMediaClient.queueSetRepeatMode(anyInt(), eq(null))) when(mockRemoteMediaClient.queueSetRepeatMode(anyInt(), eq(null)))
.thenReturn(mockPendingResult); .thenReturn(mockPendingResult);
Player.Commands commandsWithSeekToNextAndPrevious = Player.Commands commandsWithSeekInCurrent = createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM);
createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); Player.Commands commandsWithSeekAnywhere =
createCommands(
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM,
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
int[] mediaQueueItemIds = new int[] {1}; int[] mediaQueueItemIds = new int[] {1};
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds); List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
castPlayer.addMediaItems(mediaItems); castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1); updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
verify(mockListener, never()).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrent);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any());
castPlayer.setRepeatMode(Player.REPEAT_MODE_ALL); castPlayer.setRepeatMode(Player.REPEAT_MODE_ALL);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNextAndPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekAnywhere);
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener, times(2)).onAvailableCommandsChanged(any());
} }
@Test @Test
public void setRepeatMode_one_doesNotNotifyAvailableCommandsChanged() { public void setRepeatMode_one_doesNotNotifyAvailableCommandsChanged() {
when(mockRemoteMediaClient.queueSetRepeatMode(anyInt(), eq(null))) when(mockRemoteMediaClient.queueSetRepeatMode(anyInt(), eq(null)))
.thenReturn(mockPendingResult); .thenReturn(mockPendingResult);
Player.Commands commandsWithSeekInCurrent = createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM);
int[] mediaQueueItemIds = new int[] {1}; int[] mediaQueueItemIds = new int[] {1};
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds); List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
castPlayer.addMediaItems(mediaItems); castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1); updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */ 1);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrent);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any());
castPlayer.setRepeatMode(Player.REPEAT_MODE_ONE); castPlayer.setRepeatMode(Player.REPEAT_MODE_ONE);
verify(mockListener, never()).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
} }
private int[] createMediaQueueItemIds(int numberOfIds) { private int[] createMediaQueueItemIds(int numberOfIds) {
...@@ -911,21 +961,46 @@ public class CastPlayerTest { ...@@ -911,21 +961,46 @@ public class CastPlayerTest {
private void updateTimeLine( private void updateTimeLine(
List<MediaItem> mediaItems, int[] mediaQueueItemIds, int currentItemId) { List<MediaItem> mediaItems, int[] mediaQueueItemIds, int currentItemId) {
List<MediaQueueItem> queueItems = new ArrayList<>(); int[] streamTypes = new int[mediaItems.size()];
DefaultMediaItemConverter converter = new DefaultMediaItemConverter(); Arrays.fill(streamTypes, MediaInfo.STREAM_TYPE_BUFFERED);
for (MediaItem mediaItem : mediaItems) { long[] durationsMs = new long[mediaItems.size()];
queueItems.add(converter.toMediaQueueItem(mediaItem)); updateTimeLine(mediaItems, mediaQueueItemIds, currentItemId, streamTypes, durationsMs);
} }
private void updateTimeLine(
List<MediaItem> mediaItems,
int[] mediaQueueItemIds,
int currentItemId,
int[] streamTypes,
long[] durationsMs) {
// Set up mocks to allow the player to update the timeline. // Set up mocks to allow the player to update the timeline.
when(mockMediaQueue.getItemIds()).thenReturn(mediaQueueItemIds); List<MediaQueueItem> queueItems = new ArrayList<>();
if (currentItemId != C.INDEX_UNSET) { for (int i = 0; i < mediaQueueItemIds.length; i++) {
when(mockMediaQueueItem.getItemId()).thenReturn(currentItemId); MediaItem mediaItem = mediaItems.get(i);
when(mockMediaStatus.getCurrentItemId()).thenReturn(currentItemId); int mediaQueueItemId = mediaQueueItemIds[i];
int streamType = streamTypes[i];
long durationMs = durationsMs[i];
MediaInfo.Builder mediaInfoBuilder =
new MediaInfo.Builder(mediaItem.playbackProperties.uri.toString())
.setStreamType(streamType)
.setContentType(mediaItem.playbackProperties.mimeType);
if (durationMs != C.TIME_UNSET) {
mediaInfoBuilder.setStreamDuration(durationMs);
}
MediaInfo mediaInfo = mediaInfoBuilder.build();
MediaQueueItem mediaQueueItem = mock(MediaQueueItem.class);
when(mediaQueueItem.getItemId()).thenReturn(mediaQueueItemId);
when(mediaQueueItem.getMedia()).thenReturn(mediaInfo);
queueItems.add(mediaQueueItem);
if (mediaQueueItemId == currentItemId) {
when(mockRemoteMediaClient.getCurrentItem()).thenReturn(mediaQueueItem);
when(mockMediaStatus.getMediaInfo()).thenReturn(mediaInfo);
}
} }
when(mockMediaStatus.getMediaInfo()).thenReturn(mockMediaInfo); when(mockMediaQueue.getItemIds()).thenReturn(mediaQueueItemIds);
when(mockMediaInfo.getStreamType()).thenReturn(MediaInfo.STREAM_TYPE_NONE);
when(mockMediaStatus.getQueueItems()).thenReturn(queueItems); when(mockMediaStatus.getQueueItems()).thenReturn(queueItems);
when(mockMediaStatus.getCurrentItemId())
.thenReturn(currentItemId == C.INDEX_UNSET ? 0 : currentItemId);
// Call listener to update the timeline of the player. // Call listener to update the timeline of the player.
remoteMediaClientCallback.onQueueStatusUpdated(); remoteMediaClientCallback.onQueueStatusUpdated();
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
*/ */
package com.google.android.exoplayer2.ext.mediasession; package com.google.android.exoplayer2.ext.mediasession;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
import static java.lang.Math.min; import static java.lang.Math.min;
import android.os.Bundle; import android.os.Bundle;
...@@ -99,12 +102,12 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu ...@@ -99,12 +102,12 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu
timeline.getWindow(player.getCurrentWindowIndex(), window); timeline.getWindow(player.getCurrentWindowIndex(), window);
enableSkipTo = timeline.getWindowCount() > 1; enableSkipTo = timeline.getWindowCount() > 1;
enablePrevious = enablePrevious =
window.isSeekable player.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)
|| !window.isLive() || !window.isLive()
|| player.isCommandAvailable(Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); || player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
enableNext = enableNext =
(window.isLive() && window.isDynamic) (window.isLive() && window.isDynamic)
|| player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); || player.isCommandAvailable(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
} }
long actions = 0; long actions = 0;
......
...@@ -323,6 +323,7 @@ public abstract class BasePlayer implements Player { ...@@ -323,6 +323,7 @@ public abstract class BasePlayer implements Player {
protected Commands getAvailableCommands(@Command int[] permanentAvailableCommands) { protected Commands getAvailableCommands(@Command int[] permanentAvailableCommands) {
return new Commands.Builder() return new Commands.Builder()
.addAll(permanentAvailableCommands) .addAll(permanentAvailableCommands)
.addIf(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, isCurrentWindowSeekable() && !isPlayingAd())
.addIf(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, hasNext() && !isPlayingAd()) .addIf(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, hasNext() && !isPlayingAd())
.addIf(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, hasPrevious() && !isPlayingAd()) .addIf(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM, hasPrevious() && !isPlayingAd())
.build(); .build();
......
...@@ -1029,43 +1029,54 @@ public interface Player { ...@@ -1029,43 +1029,54 @@ public interface Player {
/** /**
* Commands that can be executed on a {@code Player}. One of {@link #COMMAND_PLAY_PAUSE}, {@link * Commands that can be executed on a {@code Player}. One of {@link #COMMAND_PLAY_PAUSE}, {@link
* #COMMAND_PREPARE_STOP_RELEASE}, {@link #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM}, {@link * #COMMAND_PREPARE_STOP_RELEASE}, {@link #COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM}, {@link
* #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM}, {@link #COMMAND_SET_SPEED_AND_PITCH}, {@link * #COMMAND_SEEK_TO_NEXT_MEDIA_ITEM}, {@link #COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM}, {@link
* #COMMAND_SET_SHUFFLE_MODE}, {@link #COMMAND_SET_REPEAT_MODE}, {@link * #COMMAND_SET_SPEED_AND_PITCH}, {@link #COMMAND_SET_SHUFFLE_MODE}, {@link
* #COMMAND_GET_CURRENT_MEDIA_ITEM}, {@link #COMMAND_GET_MEDIA_ITEMS}, {@link * #COMMAND_SET_REPEAT_MODE}, {@link #COMMAND_GET_CURRENT_MEDIA_ITEM}, {@link
* #COMMAND_GET_MEDIA_ITEMS_METADATA} or {@link #COMMAND_CHANGE_MEDIA_ITEMS}. * #COMMAND_GET_MEDIA_ITEMS}, {@link #COMMAND_GET_MEDIA_ITEMS_METADATA} or {@link
* #COMMAND_CHANGE_MEDIA_ITEMS}.
*/ */
@Documented @Documented
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({ @IntDef({
COMMAND_PLAY_PAUSE, COMMAND_PLAY_PAUSE,
COMMAND_PREPARE_STOP_RELEASE, COMMAND_PREPARE_STOP_RELEASE,
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM,
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM,
COMMAND_SET_SPEED_AND_PITCH,
COMMAND_SET_SHUFFLE_MODE,
COMMAND_SET_REPEAT_MODE,
COMMAND_GET_CURRENT_MEDIA_ITEM,
COMMAND_GET_MEDIA_ITEMS,
COMMAND_GET_MEDIA_ITEMS_METADATA,
COMMAND_CHANGE_MEDIA_ITEMS
}) })
@interface Command {} @interface Command {}
/** Command to start, pause or resume playback. */ /** Command to start, pause or resume playback. */
int COMMAND_PLAY_PAUSE = 1; int COMMAND_PLAY_PAUSE = 1;
/** Command to prepare the player, stop playback or release the player. */ /** Command to prepare the player, stop playback or release the player. */
int COMMAND_PREPARE_STOP_RELEASE = 2; int COMMAND_PREPARE_STOP_RELEASE = 2;
/** Command to seek into the current {@link MediaItem}. */
int COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM = 3;
/** Command to seek to the next {@link MediaItem} in the playlist. */ /** Command to seek to the next {@link MediaItem} in the playlist. */
int COMMAND_SEEK_TO_NEXT_MEDIA_ITEM = 3; int COMMAND_SEEK_TO_NEXT_MEDIA_ITEM = 4;
/** Command to seek to the previous {@link MediaItem} in the playlist. */ /** Command to seek to the previous {@link MediaItem} in the playlist. */
int COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM = 4; int COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM = 5;
/** Command to set the playback speed and pitch. */ /** Command to set the playback speed and pitch. */
int COMMAND_SET_SPEED_AND_PITCH = 5; int COMMAND_SET_SPEED_AND_PITCH = 6;
/** Command to enable shuffling. */ /** Command to enable shuffling. */
int COMMAND_SET_SHUFFLE_MODE = 6; int COMMAND_SET_SHUFFLE_MODE = 7;
/** Command to set the repeat mode. */ /** Command to set the repeat mode. */
int COMMAND_SET_REPEAT_MODE = 7; int COMMAND_SET_REPEAT_MODE = 8;
/** Command to get the current {@link MediaItem}. */ /** Command to get the current {@link MediaItem}. */
int COMMAND_GET_CURRENT_MEDIA_ITEM = 8; int COMMAND_GET_CURRENT_MEDIA_ITEM = 9;
/** Command to get the {@link MediaItem MediaItems} in the playlist. */ /** Command to get the {@link MediaItem MediaItems} in the playlist. */
int COMMAND_GET_MEDIA_ITEMS = 9; int COMMAND_GET_MEDIA_ITEMS = 10;
/** Command to get the {@link MediaItem MediaItems} metadata. */ /** Command to get the {@link MediaItem MediaItems} metadata. */
int COMMAND_GET_MEDIA_ITEMS_METADATA = 10; int COMMAND_GET_MEDIA_ITEMS_METADATA = 11;
/** Command to change the {@link MediaItem MediaItems} in the playlist. */ /** Command to change the {@link MediaItem MediaItems} in the playlist. */
int COMMAND_CHANGE_MEDIA_ITEMS = 11; int COMMAND_CHANGE_MEDIA_ITEMS = 12;
/** Returns the component of this player for audio output, or null if audio is not supported. */ /** Returns the component of this player for audio output, or null if audio is not supported. */
@Nullable @Nullable
......
...@@ -21,6 +21,7 @@ import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS; ...@@ -21,6 +21,7 @@ import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS;
import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS_METADATA; import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS_METADATA;
import static com.google.android.exoplayer2.Player.COMMAND_PLAY_PAUSE; import static com.google.android.exoplayer2.Player.COMMAND_PLAY_PAUSE;
import static com.google.android.exoplayer2.Player.COMMAND_PREPARE_STOP_RELEASE; import static com.google.android.exoplayer2.Player.COMMAND_PREPARE_STOP_RELEASE;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM; import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM; import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SET_REPEAT_MODE; import static com.google.android.exoplayer2.Player.COMMAND_SET_REPEAT_MODE;
...@@ -8087,6 +8088,7 @@ public final class ExoPlayerTest { ...@@ -8087,6 +8088,7 @@ public final class ExoPlayerTest {
assertThat(player.isCommandAvailable(COMMAND_PLAY_PAUSE)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_PLAY_PAUSE)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_PREPARE_STOP_RELEASE)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_PREPARE_STOP_RELEASE)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)).isFalse();
assertThat(player.isCommandAvailable(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)).isFalse(); assertThat(player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)).isFalse();
assertThat(player.isCommandAvailable(COMMAND_SET_SPEED_AND_PITCH)).isTrue(); assertThat(player.isCommandAvailable(COMMAND_SET_SPEED_AND_PITCH)).isTrue();
...@@ -8099,7 +8101,7 @@ public final class ExoPlayerTest { ...@@ -8099,7 +8101,7 @@ public final class ExoPlayerTest {
} }
@Test @Test
public void isCommandAvailable_whenPlayingAd_isFalseForSeekCommands() throws Exception { public void isCommandAvailable_duringAd_isFalseForSeekCommands() throws Exception {
AdPlaybackState adPlaybackState = AdPlaybackState adPlaybackState =
new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0) new AdPlaybackState(/* adsId= */ new Object(), /* adGroupTimesUs...= */ 0)
.withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1) .withAdCount(/* adGroupIndex= */ 0, /* adCount= */ 1)
...@@ -8123,11 +8125,29 @@ public final class ExoPlayerTest { ...@@ -8123,11 +8125,29 @@ public final class ExoPlayerTest {
player.prepare(); player.prepare();
runUntilPlaybackState(player, Player.STATE_READY); runUntilPlaybackState(player, Player.STATE_READY);
assertThat(player.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)).isFalse();
assertThat(player.isCommandAvailable(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)).isFalse(); assertThat(player.isCommandAvailable(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM)).isFalse();
assertThat(player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)).isFalse(); assertThat(player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM)).isFalse();
} }
@Test @Test
public void isCommandAvailable_duringUnseekableItem_isFalseForSeekInCurrent() throws Exception {
Timeline timelineWithUnseekableWindow =
new FakeTimeline(
new TimelineWindowDefinition(
/* isSeekable= */ false,
/* isDynamic= */ false,
/* durationUs= */ C.msToUs(10_000)));
ExoPlayer player = new TestExoPlayerBuilder(context).build();
player.addMediaSource(new FakeMediaSource(timelineWithUnseekableWindow));
player.prepare();
runUntilPlaybackState(player, Player.STATE_READY);
assertThat(player.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM)).isFalse();
}
@Test
public void seekTo_nextWindow_notifiesAvailableCommandsChanged() { public void seekTo_nextWindow_notifiesAvailableCommandsChanged() {
Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
Player.Commands commandsWithSeekToPrevious = Player.Commands commandsWithSeekToPrevious =
...@@ -8145,6 +8165,7 @@ public final class ExoPlayerTest { ...@@ -8145,6 +8165,7 @@ public final class ExoPlayerTest {
new FakeMediaSource(), new FakeMediaSource(),
new FakeMediaSource())); new FakeMediaSource()));
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
player.seekTo(/* windowIndex= */ 1, /* positionMs= */ 0); player.seekTo(/* windowIndex= */ 1, /* positionMs= */ 0);
...@@ -8178,6 +8199,7 @@ public final class ExoPlayerTest { ...@@ -8178,6 +8199,7 @@ public final class ExoPlayerTest {
new FakeMediaSource(), new FakeMediaSource(),
new FakeMediaSource())); new FakeMediaSource()));
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
player.seekTo(/* windowIndex= */ 2, /* positionMs= */ 0); player.seekTo(/* windowIndex= */ 2, /* positionMs= */ 0);
...@@ -8207,10 +8229,15 @@ public final class ExoPlayerTest { ...@@ -8207,10 +8229,15 @@ public final class ExoPlayerTest {
@Test @Test
public void automaticWindowTransition_notifiesAvailableCommandsChanged() throws Exception { public void automaticWindowTransition_notifiesAvailableCommandsChanged() throws Exception {
Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); Player.Commands commandsWithSeekToNext = createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
Player.Commands commandsWithSeekToPrevious = Player.Commands commandsWithSeekInCurrentAndToNext =
createCommands(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
Player.Commands commandsWithSeekToNextAndPrevious = Player.Commands commandsWithSeekInCurrentAndToPrevious =
createCommands(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM, COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); createCommands(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM, COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
Player.Commands commandsWithSeekAnywhere =
createCommands(
COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM,
COMMAND_SEEK_TO_NEXT_MEDIA_ITEM,
COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
Player.EventListener mockListener = mock(Player.EventListener.class); Player.EventListener mockListener = mock(Player.EventListener.class);
ExoPlayer player = new TestExoPlayerBuilder(context).build(); ExoPlayer player = new TestExoPlayerBuilder(context).build();
player.addListener(mockListener); player.addListener(mockListener);
...@@ -8222,22 +8249,27 @@ public final class ExoPlayerTest { ...@@ -8222,22 +8249,27 @@ public final class ExoPlayerTest {
new FakeMediaSource(), new FakeMediaSource(),
new FakeMediaSource())); new FakeMediaSource()));
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
player.prepare(); player.prepare();
runUntilPlaybackState(player, Player.STATE_READY);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrentAndToNext);
verify(mockListener, times(2)).onAvailableCommandsChanged(any());
playUntilStartOfWindow(player, /* windowIndex= */ 1); playUntilStartOfWindow(player, /* windowIndex= */ 1);
runUntilPendingCommandsAreFullyHandled(player); runUntilPendingCommandsAreFullyHandled(player);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNextAndPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekAnywhere);
verify(mockListener, times(2)).onAvailableCommandsChanged(any()); verify(mockListener, times(3)).onAvailableCommandsChanged(any());
playUntilStartOfWindow(player, /* windowIndex= */ 2); playUntilStartOfWindow(player, /* windowIndex= */ 2);
runUntilPendingCommandsAreFullyHandled(player); runUntilPendingCommandsAreFullyHandled(player);
verify(mockListener, times(2)).onAvailableCommandsChanged(any()); verify(mockListener, times(3)).onAvailableCommandsChanged(any());
player.play(); player.play();
runUntilPlaybackState(player, Player.STATE_ENDED); runUntilPlaybackState(player, Player.STATE_ENDED);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekInCurrentAndToPrevious);
verify(mockListener, times(3)).onAvailableCommandsChanged(any()); verify(mockListener, times(4)).onAvailableCommandsChanged(any());
} }
@Test @Test
...@@ -8252,6 +8284,7 @@ public final class ExoPlayerTest { ...@@ -8252,6 +8284,7 @@ public final class ExoPlayerTest {
player.addMediaSource(new FakeMediaSource()); player.addMediaSource(new FakeMediaSource());
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
player.addMediaSource(new FakeMediaSource()); player.addMediaSource(new FakeMediaSource());
...@@ -8271,6 +8304,7 @@ public final class ExoPlayerTest { ...@@ -8271,6 +8304,7 @@ public final class ExoPlayerTest {
player.addMediaSource(/* index= */ 0, new FakeMediaSource()); player.addMediaSource(/* index= */ 0, new FakeMediaSource());
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
player.addMediaSource(/* index= */ 0, new FakeMediaSource()); player.addMediaSource(/* index= */ 0, new FakeMediaSource());
...@@ -8288,6 +8322,7 @@ public final class ExoPlayerTest { ...@@ -8288,6 +8322,7 @@ public final class ExoPlayerTest {
player.addMediaSources( player.addMediaSources(
ImmutableList.of(new FakeMediaSource(), new FakeMediaSource(), new FakeMediaSource())); ImmutableList.of(new FakeMediaSource(), new FakeMediaSource(), new FakeMediaSource()));
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
player.removeMediaItem(/* index= */ 2); player.removeMediaItem(/* index= */ 2);
...@@ -8314,6 +8349,7 @@ public final class ExoPlayerTest { ...@@ -8314,6 +8349,7 @@ public final class ExoPlayerTest {
player.addMediaSources( player.addMediaSources(
ImmutableList.of(new FakeMediaSource(), new FakeMediaSource(), new FakeMediaSource())); ImmutableList.of(new FakeMediaSource(), new FakeMediaSource(), new FakeMediaSource()));
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
player.removeMediaItem(/* index= */ 0); player.removeMediaItem(/* index= */ 0);
...@@ -8337,6 +8373,7 @@ public final class ExoPlayerTest { ...@@ -8337,6 +8373,7 @@ public final class ExoPlayerTest {
player.addMediaSources(ImmutableList.of(new FakeMediaSource(), new FakeMediaSource())); player.addMediaSources(ImmutableList.of(new FakeMediaSource(), new FakeMediaSource()));
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
player.removeMediaItem(/* index= */ 0); player.removeMediaItem(/* index= */ 0);
...@@ -8357,6 +8394,7 @@ public final class ExoPlayerTest { ...@@ -8357,6 +8394,7 @@ public final class ExoPlayerTest {
player.setRepeatMode(Player.REPEAT_MODE_ALL); player.setRepeatMode(Player.REPEAT_MODE_ALL);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNextAndPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNextAndPrevious);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any()); verify(mockListener).onAvailableCommandsChanged(any());
} }
...@@ -8388,9 +8426,12 @@ public final class ExoPlayerTest { ...@@ -8388,9 +8426,12 @@ public final class ExoPlayerTest {
player.addMediaSource(mediaSource); player.addMediaSource(mediaSource);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToNext);
// Check that there were no other calls to onAvailableCommandsChanged.
verify(mockListener).onAvailableCommandsChanged(any());
player.setShuffleModeEnabled(true); player.setShuffleModeEnabled(true);
verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious); verify(mockListener).onAvailableCommandsChanged(commandsWithSeekToPrevious);
verify(mockListener, times(2)).onAvailableCommandsChanged(any());
} }
@Test @Test
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
*/ */
package com.google.android.exoplayer2.ui; package com.google.android.exoplayer2.ui;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.EVENT_IS_PLAYING_CHANGED; import static com.google.android.exoplayer2.Player.EVENT_IS_PLAYING_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_STATE_CHANGED; import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_STATE_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_PLAY_WHEN_READY_CHANGED; import static com.google.android.exoplayer2.Player.EVENT_PLAY_WHEN_READY_CHANGED;
...@@ -910,18 +913,18 @@ public class PlayerControlView extends FrameLayout { ...@@ -910,18 +913,18 @@ public class PlayerControlView extends FrameLayout {
if (player != null) { if (player != null) {
Timeline timeline = player.getCurrentTimeline(); Timeline timeline = player.getCurrentTimeline();
if (!timeline.isEmpty() && !player.isPlayingAd()) { if (!timeline.isEmpty() && !player.isPlayingAd()) {
boolean isSeekable = player.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM);
timeline.getWindow(player.getCurrentWindowIndex(), window); timeline.getWindow(player.getCurrentWindowIndex(), window);
boolean isSeekable = window.isSeekable;
enableSeeking = isSeekable; enableSeeking = isSeekable;
enablePrevious = enablePrevious =
isSeekable isSeekable
|| !window.isLive() || !window.isLive()
|| player.isCommandAvailable(Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); || player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
enableRewind = isSeekable && controlDispatcher.isRewindEnabled(); enableRewind = isSeekable && controlDispatcher.isRewindEnabled();
enableFastForward = isSeekable && controlDispatcher.isFastForwardEnabled(); enableFastForward = isSeekable && controlDispatcher.isFastForwardEnabled();
enableNext = enableNext =
(window.isLive() && window.isDynamic) (window.isLive() && window.isDynamic)
|| player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); || player.isCommandAvailable(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
} }
} }
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
*/ */
package com.google.android.exoplayer2.ui; package com.google.android.exoplayer2.ui;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.EVENT_IS_PLAYING_CHANGED; import static com.google.android.exoplayer2.Player.EVENT_IS_PLAYING_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_PARAMETERS_CHANGED; import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_PARAMETERS_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_STATE_CHANGED; import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_STATE_CHANGED;
...@@ -1458,17 +1461,17 @@ public class PlayerNotificationManager { ...@@ -1458,17 +1461,17 @@ public class PlayerNotificationManager {
boolean enableNext = false; boolean enableNext = false;
Timeline timeline = player.getCurrentTimeline(); Timeline timeline = player.getCurrentTimeline();
if (!timeline.isEmpty() && !player.isPlayingAd()) { if (!timeline.isEmpty() && !player.isPlayingAd()) {
boolean isSeekable = player.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM);
timeline.getWindow(player.getCurrentWindowIndex(), window); timeline.getWindow(player.getCurrentWindowIndex(), window);
boolean isSeekable = window.isSeekable;
enablePrevious = enablePrevious =
isSeekable isSeekable
|| !window.isLive() || !window.isLive()
|| player.isCommandAvailable(Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); || player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
enableRewind = isSeekable && controlDispatcher.isRewindEnabled(); enableRewind = isSeekable && controlDispatcher.isRewindEnabled();
enableFastForward = isSeekable && controlDispatcher.isFastForwardEnabled(); enableFastForward = isSeekable && controlDispatcher.isFastForwardEnabled();
enableNext = enableNext =
(window.isLive() && window.isDynamic) (window.isLive() && window.isDynamic)
|| player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); || player.isCommandAvailable(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
} }
List<String> stringActions = new ArrayList<>(); List<String> stringActions = new ArrayList<>();
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
*/ */
package com.google.android.exoplayer2.ui; package com.google.android.exoplayer2.ui;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM;
import static com.google.android.exoplayer2.Player.EVENT_IS_PLAYING_CHANGED; import static com.google.android.exoplayer2.Player.EVENT_IS_PLAYING_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_PARAMETERS_CHANGED; import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_PARAMETERS_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_STATE_CHANGED; import static com.google.android.exoplayer2.Player.EVENT_PLAYBACK_STATE_CHANGED;
...@@ -1145,18 +1148,18 @@ public class StyledPlayerControlView extends FrameLayout { ...@@ -1145,18 +1148,18 @@ public class StyledPlayerControlView extends FrameLayout {
if (player != null) { if (player != null) {
Timeline timeline = player.getCurrentTimeline(); Timeline timeline = player.getCurrentTimeline();
if (!timeline.isEmpty() && !player.isPlayingAd()) { if (!timeline.isEmpty() && !player.isPlayingAd()) {
boolean isSeekable = player.isCommandAvailable(COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM);
timeline.getWindow(player.getCurrentWindowIndex(), window); timeline.getWindow(player.getCurrentWindowIndex(), window);
boolean isSeekable = window.isSeekable;
enableSeeking = isSeekable; enableSeeking = isSeekable;
enablePrevious = enablePrevious =
isSeekable isSeekable
|| !window.isLive() || !window.isLive()
|| player.isCommandAvailable(Player.COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM); || player.isCommandAvailable(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM);
enableRewind = isSeekable && controlDispatcher.isRewindEnabled(); enableRewind = isSeekable && controlDispatcher.isRewindEnabled();
enableFastForward = isSeekable && controlDispatcher.isFastForwardEnabled(); enableFastForward = isSeekable && controlDispatcher.isFastForwardEnabled();
enableNext = enableNext =
(window.isLive() && window.isDynamic) (window.isLive() && window.isDynamic)
|| player.isCommandAvailable(Player.COMMAND_SEEK_TO_NEXT_MEDIA_ITEM); || player.isCommandAvailable(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment