mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Clear one-off events from state as soon as they are triggered.
This ensures they are not accidentally triggered again when the state is rebuilt with a buildUpon method. PiperOrigin-RevId: 495280711
This commit is contained in:
parent
21ae403049
commit
a123134892
@ -2888,6 +2888,15 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
||||
// Assign new state immediately such that all getters return the right values, but use a
|
||||
// snapshot of the previous and new state so that listener invocations are triggered correctly.
|
||||
this.state = newState;
|
||||
if (newState.hasPositionDiscontinuity || newState.newlyRenderedFirstFrame) {
|
||||
// Clear one-time events to avoid signalling them again later.
|
||||
this.state =
|
||||
this.state
|
||||
.buildUpon()
|
||||
.clearPositionDiscontinuity()
|
||||
.setNewlyRenderedFirstFrame(false)
|
||||
.build();
|
||||
}
|
||||
|
||||
boolean playWhenReadyChanged = previousState.playWhenReady != newState.playWhenReady;
|
||||
boolean playbackStateChanged = previousState.playbackState != newState.playbackState;
|
||||
@ -2914,7 +2923,7 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
||||
PositionInfo positionInfo =
|
||||
getPositionInfo(
|
||||
newState,
|
||||
/* useDiscontinuityPosition= */ state.hasPositionDiscontinuity,
|
||||
/* useDiscontinuityPosition= */ newState.hasPositionDiscontinuity,
|
||||
window,
|
||||
period);
|
||||
listeners.queueEvent(
|
||||
@ -2928,9 +2937,9 @@ public abstract class SimpleBasePlayer extends BasePlayer {
|
||||
if (mediaItemTransitionReason != C.INDEX_UNSET) {
|
||||
@Nullable
|
||||
MediaItem mediaItem =
|
||||
state.timeline.isEmpty()
|
||||
newState.timeline.isEmpty()
|
||||
? null
|
||||
: state.playlist.get(state.currentMediaItemIndex).mediaItem;
|
||||
: newState.playlist.get(state.currentMediaItemIndex).mediaItem;
|
||||
listeners.queueEvent(
|
||||
Player.EVENT_MEDIA_ITEM_TRANSITION,
|
||||
listener -> listener.onMediaItemTransition(mediaItem, mediaItemTransitionReason));
|
||||
|
@ -1697,6 +1697,82 @@ public class SimpleBasePlayerTest {
|
||||
verify(listener, never()).onMediaItemTransition(any(), anyInt());
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // Verifying deprecated listener call.
|
||||
@Test
|
||||
public void invalidateStateAndOtherOperation_withDiscontinuity_reportsDiscontinuityOnlyOnce() {
|
||||
State state =
|
||||
new State.Builder()
|
||||
.setAvailableCommands(new Commands.Builder().addAllCommands().build())
|
||||
.setPlaylist(
|
||||
ImmutableList.of(new SimpleBasePlayer.MediaItemData.Builder(/* uid= */ 0).build()))
|
||||
.setPositionDiscontinuity(
|
||||
Player.DISCONTINUITY_REASON_INTERNAL, /* discontinuityPositionMs= */ 2000)
|
||||
.build();
|
||||
SimpleBasePlayer player =
|
||||
new SimpleBasePlayer(Looper.myLooper()) {
|
||||
@Override
|
||||
protected State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<?> handlePrepare() {
|
||||
// We just care about the placeholder state, so return an unfulfilled future.
|
||||
return SettableFuture.create();
|
||||
}
|
||||
};
|
||||
Listener listener = mock(Listener.class);
|
||||
player.addListener(listener);
|
||||
|
||||
player.invalidateState();
|
||||
player.prepare();
|
||||
|
||||
// Assert listener calls (in particular getting only a single discontinuity).
|
||||
verify(listener)
|
||||
.onPositionDiscontinuity(any(), any(), eq(Player.DISCONTINUITY_REASON_INTERNAL));
|
||||
verify(listener).onPositionDiscontinuity(Player.DISCONTINUITY_REASON_INTERNAL);
|
||||
verify(listener).onPlaybackStateChanged(Player.STATE_BUFFERING);
|
||||
verify(listener).onPlayerStateChanged(/* playWhenReady= */ false, Player.STATE_BUFFERING);
|
||||
verifyNoMoreInteractions(listener);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation") // Verifying deprecated listener call.
|
||||
@Test
|
||||
public void
|
||||
invalidateStateAndOtherOperation_withRenderedFirstFrame_reportsRenderedFirstFrameOnlyOnce() {
|
||||
State state =
|
||||
new State.Builder()
|
||||
.setAvailableCommands(new Commands.Builder().addAllCommands().build())
|
||||
.setPlaylist(
|
||||
ImmutableList.of(new SimpleBasePlayer.MediaItemData.Builder(/* uid= */ 0).build()))
|
||||
.setNewlyRenderedFirstFrame(true)
|
||||
.build();
|
||||
SimpleBasePlayer player =
|
||||
new SimpleBasePlayer(Looper.myLooper()) {
|
||||
@Override
|
||||
protected State getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ListenableFuture<?> handlePrepare() {
|
||||
// We just care about the placeholder state, so return an unfulfilled future.
|
||||
return SettableFuture.create();
|
||||
}
|
||||
};
|
||||
Listener listener = mock(Listener.class);
|
||||
player.addListener(listener);
|
||||
|
||||
player.invalidateState();
|
||||
player.prepare();
|
||||
|
||||
// Assert listener calls (in particular getting only a single rendered first frame).
|
||||
verify(listener).onRenderedFirstFrame();
|
||||
verify(listener).onPlaybackStateChanged(Player.STATE_BUFFERING);
|
||||
verify(listener).onPlayerStateChanged(/* playWhenReady= */ false, Player.STATE_BUFFERING);
|
||||
verifyNoMoreInteractions(listener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidateState_duringAsyncMethodHandling_isIgnored() {
|
||||
State state1 =
|
||||
|
Loading…
x
Reference in New Issue
Block a user