Make sure CastPlayer calls onIsPlaying if required
Before this change we checked whether the playback state and playWhenReady have changed when the state from the cast device arrived. If we detected such a change we called the listener callback `onIsPlayingChanged`. However, in the case when `setPlayWhenReady(boolean)` is called on 'CastPlayer', we mask the change in `playWhenReady`, then send the play/pause request to the cast device and when the state from the cast device arrives we never detect a change because we have already masked `playWhenReady`. This change now moves the check for `isPlaying` to the same place where the state and playWhenReady is updated, so we call the `onIsPlayingChanged` callback in either case, when masking or when a changed state from the server arrives. Issue: google/ExoPlayer#9792 PiperOrigin-RevId: 418483509
This commit is contained in:
parent
b440b0fc03
commit
967acf3049
@ -818,13 +818,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
!getCurrentTimeline().isEmpty()
|
!getCurrentTimeline().isEmpty()
|
||||||
? getCurrentTimeline().getPeriod(oldWindowIndex, period, /* setIds= */ true).uid
|
? getCurrentTimeline().getPeriod(oldWindowIndex, period, /* setIds= */ true).uid
|
||||||
: null;
|
: null;
|
||||||
boolean wasPlaying = playbackState == Player.STATE_READY && playWhenReady.value;
|
|
||||||
updatePlayerStateAndNotifyIfChanged(/* resultCallback= */ null);
|
updatePlayerStateAndNotifyIfChanged(/* resultCallback= */ null);
|
||||||
boolean isPlaying = playbackState == Player.STATE_READY && playWhenReady.value;
|
|
||||||
if (wasPlaying != isPlaying) {
|
|
||||||
listeners.queueEvent(
|
|
||||||
Player.EVENT_IS_PLAYING_CHANGED, listener -> listener.onIsPlayingChanged(isPlaying));
|
|
||||||
}
|
|
||||||
updateRepeatModeAndNotifyIfChanged(/* resultCallback= */ null);
|
updateRepeatModeAndNotifyIfChanged(/* resultCallback= */ null);
|
||||||
updatePlaybackRateAndNotifyIfChanged(/* resultCallback= */ null);
|
updatePlaybackRateAndNotifyIfChanged(/* resultCallback= */ null);
|
||||||
boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged();
|
boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged();
|
||||||
@ -1218,6 +1212,7 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
boolean playWhenReady,
|
boolean playWhenReady,
|
||||||
@Player.PlayWhenReadyChangeReason int playWhenReadyChangeReason,
|
@Player.PlayWhenReadyChangeReason int playWhenReadyChangeReason,
|
||||||
@Player.State int playbackState) {
|
@Player.State int playbackState) {
|
||||||
|
boolean wasPlaying = this.playbackState == Player.STATE_READY && this.playWhenReady.value;
|
||||||
boolean playWhenReadyChanged = this.playWhenReady.value != playWhenReady;
|
boolean playWhenReadyChanged = this.playWhenReady.value != playWhenReady;
|
||||||
boolean playbackStateChanged = this.playbackState != playbackState;
|
boolean playbackStateChanged = this.playbackState != playbackState;
|
||||||
if (playWhenReadyChanged || playbackStateChanged) {
|
if (playWhenReadyChanged || playbackStateChanged) {
|
||||||
@ -1236,6 +1231,11 @@ public final class CastPlayer extends BasePlayer {
|
|||||||
Player.EVENT_PLAY_WHEN_READY_CHANGED,
|
Player.EVENT_PLAY_WHEN_READY_CHANGED,
|
||||||
listener -> listener.onPlayWhenReadyChanged(playWhenReady, playWhenReadyChangeReason));
|
listener -> listener.onPlayWhenReadyChanged(playWhenReady, playWhenReadyChangeReason));
|
||||||
}
|
}
|
||||||
|
boolean isPlaying = playbackState == Player.STATE_READY && playWhenReady;
|
||||||
|
if (wasPlaying != isPlaying) {
|
||||||
|
listeners.queueEvent(
|
||||||
|
Player.EVENT_IS_PLAYING_CHANGED, listener -> listener.onIsPlayingChanged(isPlaying));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@ 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.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.reset;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
@ -138,13 +139,18 @@ public class CastPlayerTest {
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@Test
|
@Test
|
||||||
public void setPlayWhenReady_masksRemoteState() {
|
public void setPlayWhenReady_masksRemoteState() {
|
||||||
|
when(mockRemoteMediaClient.getPlayerState()).thenReturn(MediaStatus.PLAYER_STATE_PLAYING);
|
||||||
|
// Trigger initial update to get out of STATE_IDLE to make onIsPlaying() be called.
|
||||||
|
remoteMediaClientCallback.onStatusUpdated();
|
||||||
|
reset(mockListener);
|
||||||
when(mockRemoteMediaClient.play()).thenReturn(mockPendingResult);
|
when(mockRemoteMediaClient.play()).thenReturn(mockPendingResult);
|
||||||
assertThat(castPlayer.getPlayWhenReady()).isFalse();
|
assertThat(castPlayer.getPlayWhenReady()).isFalse();
|
||||||
|
|
||||||
castPlayer.play();
|
castPlayer.play();
|
||||||
verify(mockPendingResult).setResultCallback(setResultCallbackArgumentCaptor.capture());
|
verify(mockPendingResult).setResultCallback(setResultCallbackArgumentCaptor.capture());
|
||||||
assertThat(castPlayer.getPlayWhenReady()).isTrue();
|
assertThat(castPlayer.getPlayWhenReady()).isTrue();
|
||||||
verify(mockListener).onPlayerStateChanged(true, Player.STATE_IDLE);
|
verify(mockListener).onPlayerStateChanged(true, Player.STATE_READY);
|
||||||
|
verify(mockListener).onIsPlayingChanged(true);
|
||||||
verify(mockListener)
|
verify(mockListener)
|
||||||
.onPlayWhenReadyChanged(true, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
.onPlayWhenReadyChanged(true, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
||||||
|
|
||||||
@ -163,13 +169,18 @@ public class CastPlayerTest {
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@Test
|
@Test
|
||||||
public void setPlayWhenReadyMasking_updatesUponResultChange() {
|
public void setPlayWhenReadyMasking_updatesUponResultChange() {
|
||||||
|
when(mockRemoteMediaClient.getPlayerState()).thenReturn(MediaStatus.PLAYER_STATE_PLAYING);
|
||||||
|
// Trigger initial update to get out of STATE_IDLE to make onIsPlaying() be called.
|
||||||
|
remoteMediaClientCallback.onStatusUpdated();
|
||||||
|
reset(mockListener);
|
||||||
when(mockRemoteMediaClient.play()).thenReturn(mockPendingResult);
|
when(mockRemoteMediaClient.play()).thenReturn(mockPendingResult);
|
||||||
assertThat(castPlayer.getPlayWhenReady()).isFalse();
|
assertThat(castPlayer.getPlayWhenReady()).isFalse();
|
||||||
|
|
||||||
castPlayer.play();
|
castPlayer.play();
|
||||||
verify(mockPendingResult).setResultCallback(setResultCallbackArgumentCaptor.capture());
|
verify(mockPendingResult).setResultCallback(setResultCallbackArgumentCaptor.capture());
|
||||||
assertThat(castPlayer.getPlayWhenReady()).isTrue();
|
assertThat(castPlayer.getPlayWhenReady()).isTrue();
|
||||||
verify(mockListener).onPlayerStateChanged(true, Player.STATE_IDLE);
|
verify(mockListener).onIsPlayingChanged(true);
|
||||||
|
verify(mockListener).onPlayerStateChanged(true, Player.STATE_READY);
|
||||||
verify(mockListener)
|
verify(mockListener)
|
||||||
.onPlayWhenReadyChanged(true, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
.onPlayWhenReadyChanged(true, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
||||||
|
|
||||||
@ -177,38 +188,52 @@ public class CastPlayerTest {
|
|||||||
setResultCallbackArgumentCaptor
|
setResultCallbackArgumentCaptor
|
||||||
.getValue()
|
.getValue()
|
||||||
.onResult(mock(RemoteMediaClient.MediaChannelResult.class));
|
.onResult(mock(RemoteMediaClient.MediaChannelResult.class));
|
||||||
verify(mockListener).onPlayerStateChanged(false, Player.STATE_IDLE);
|
verify(mockListener).onPlayerStateChanged(false, Player.STATE_READY);
|
||||||
|
verify(mockListener).onIsPlayingChanged(false);
|
||||||
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();
|
||||||
|
verifyNoMoreInteractions(mockListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@Test
|
@Test
|
||||||
public void setPlayWhenReady_correctChangeReasonOnPause() {
|
public void setPlayWhenReady_correctChangeReasonOnPause() {
|
||||||
|
when(mockRemoteMediaClient.getPlayerState()).thenReturn(MediaStatus.PLAYER_STATE_PLAYING);
|
||||||
|
// Trigger initial update to get out of STATE_IDLE to make onIsPlaying() be called.
|
||||||
|
remoteMediaClientCallback.onStatusUpdated();
|
||||||
|
reset(mockListener);
|
||||||
when(mockRemoteMediaClient.play()).thenReturn(mockPendingResult);
|
when(mockRemoteMediaClient.play()).thenReturn(mockPendingResult);
|
||||||
when(mockRemoteMediaClient.pause()).thenReturn(mockPendingResult);
|
when(mockRemoteMediaClient.pause()).thenReturn(mockPendingResult);
|
||||||
|
|
||||||
castPlayer.play();
|
castPlayer.play();
|
||||||
assertThat(castPlayer.getPlayWhenReady()).isTrue();
|
assertThat(castPlayer.getPlayWhenReady()).isTrue();
|
||||||
verify(mockListener).onPlayerStateChanged(true, Player.STATE_IDLE);
|
verify(mockListener).onIsPlayingChanged(true);
|
||||||
|
verify(mockListener).onPlayerStateChanged(true, Player.STATE_READY);
|
||||||
verify(mockListener)
|
verify(mockListener)
|
||||||
.onPlayWhenReadyChanged(true, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
.onPlayWhenReadyChanged(true, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
||||||
|
|
||||||
castPlayer.pause();
|
castPlayer.pause();
|
||||||
assertThat(castPlayer.getPlayWhenReady()).isFalse();
|
assertThat(castPlayer.getPlayWhenReady()).isFalse();
|
||||||
verify(mockListener).onPlayerStateChanged(false, Player.STATE_IDLE);
|
verify(mockListener).onIsPlayingChanged(false);
|
||||||
verify(mockListener)
|
verify(mockListener)
|
||||||
.onPlayWhenReadyChanged(false, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
.onPlayWhenReadyChanged(false, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
||||||
|
verify(mockListener).onPlayerStateChanged(false, Player.STATE_READY);
|
||||||
|
verifyNoMoreInteractions(mockListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@Test
|
@Test
|
||||||
public void playWhenReady_changesOnStatusUpdates() {
|
public void playWhenReady_changesOnStatusUpdates() {
|
||||||
|
when(mockRemoteMediaClient.getPlayerState()).thenReturn(MediaStatus.PLAYER_STATE_PLAYING);
|
||||||
assertThat(castPlayer.getPlayWhenReady()).isFalse();
|
assertThat(castPlayer.getPlayWhenReady()).isFalse();
|
||||||
when(mockRemoteMediaClient.isPaused()).thenReturn(false);
|
when(mockRemoteMediaClient.isPaused()).thenReturn(false);
|
||||||
remoteMediaClientCallback.onStatusUpdated();
|
remoteMediaClientCallback.onStatusUpdated();
|
||||||
verify(mockListener).onPlayerStateChanged(true, Player.STATE_IDLE);
|
verify(mockListener).onPlayerStateChanged(true, Player.STATE_READY);
|
||||||
|
verify(mockListener).onPlaybackStateChanged(Player.STATE_READY);
|
||||||
verify(mockListener).onPlayWhenReadyChanged(true, Player.PLAY_WHEN_READY_CHANGE_REASON_REMOTE);
|
verify(mockListener).onPlayWhenReadyChanged(true, Player.PLAY_WHEN_READY_CHANGE_REASON_REMOTE);
|
||||||
assertThat(castPlayer.getPlayWhenReady()).isTrue();
|
assertThat(castPlayer.getPlayWhenReady()).isTrue();
|
||||||
|
verify(mockListener).onIsPlayingChanged(true);
|
||||||
|
verifyNoMoreInteractions(mockListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
x
Reference in New Issue
Block a user