Clarify that onPlayWhenReadyChanged can be called again with new reason
Sometimes the reason for the current state may change. If we don't report this again, users have no way of knowing that the reason changed. Also adjust ExoPlayerImpl and MediaControllerImplBase accordingly. SimpleBasePlayer already adheres to this logic. #cherrypick PiperOrigin-RevId: 644970236
This commit is contained in:
parent
c0abd6f91e
commit
1d26d1891e
@ -922,6 +922,9 @@ public interface Player {
|
||||
/**
|
||||
* Called when the value returned from {@link #getPlayWhenReady()} changes.
|
||||
*
|
||||
* <p>The current {@code playWhenReady} value may be re-reported if the {@code reason} for this
|
||||
* value changes.
|
||||
*
|
||||
* <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
|
||||
* other events that happen in the same {@link Looper} message queue iteration.
|
||||
*
|
||||
|
@ -2154,7 +2154,9 @@ import java.util.concurrent.TimeoutException;
|
||||
Player.EVENT_PLAYBACK_STATE_CHANGED,
|
||||
listener -> listener.onPlaybackStateChanged(newPlaybackInfo.playbackState));
|
||||
}
|
||||
if (playWhenReadyChanged) {
|
||||
if (playWhenReadyChanged
|
||||
|| previousPlaybackInfo.playWhenReadyChangeReason
|
||||
!= newPlaybackInfo.playWhenReadyChangeReason) {
|
||||
listeners.queueEvent(
|
||||
Player.EVENT_PLAY_WHEN_READY_CHANGED,
|
||||
listener ->
|
||||
@ -2798,7 +2800,8 @@ import java.util.concurrent.TimeoutException;
|
||||
@PlaybackSuppressionReason
|
||||
int playbackSuppressionReason = computePlaybackSuppressionReason(playWhenReady, playerCommand);
|
||||
if (playbackInfo.playWhenReady == playWhenReady
|
||||
&& playbackInfo.playbackSuppressionReason == playbackSuppressionReason) {
|
||||
&& playbackInfo.playbackSuppressionReason == playbackSuppressionReason
|
||||
&& playbackInfo.playWhenReadyChangeReason == playWhenReadyChangeReason) {
|
||||
return;
|
||||
}
|
||||
updatePlaybackInfoForPlayWhenReadyAndSuppressionReasonStates(
|
||||
|
@ -4392,7 +4392,9 @@ public class ExoPlayerTest {
|
||||
assertThat(playWhenReady).isFalse();
|
||||
assertThat(suppressionReason).isEqualTo(Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
verify(listener, never()).onPlaybackSuppressionReasonChanged(anyInt());
|
||||
// TODO: Fix behavior and assert that audio focus loss is reported via onPlayWhenReadyChanged.
|
||||
verify(listener)
|
||||
.onPlayWhenReadyChanged(
|
||||
/* playWhenReady= */ false, Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -2746,7 +2746,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
@Nullable
|
||||
@Player.PlayWhenReadyChangeReason
|
||||
Integer playWhenReadyChangeReason =
|
||||
oldPlayerInfo.playWhenReady != finalPlayerInfo.playWhenReady
|
||||
oldPlayerInfo.playWhenReadyChangeReason != finalPlayerInfo.playWhenReadyChangeReason
|
||||
|| oldPlayerInfo.playWhenReady != finalPlayerInfo.playWhenReady
|
||||
? finalPlayerInfo.playWhenReadyChangeReason
|
||||
: null;
|
||||
|
||||
|
@ -59,7 +59,7 @@ interface IRemoteMediaSession {
|
||||
void increaseDeviceVolume(String sessionId, int flags);
|
||||
void setDeviceMuted(String sessionId, boolean muted, int flags);
|
||||
void notifyPlayerError(String sessionId, in Bundle playerErrorBundle);
|
||||
void notifyPlayWhenReadyChanged(String sessionId, boolean playWhenReady, int reason);
|
||||
void notifyPlayWhenReadyChanged(String sessionId, boolean playWhenReady, int playWhenReadyChangeReason, int suppressionReason);
|
||||
void notifyPlaybackStateChanged(String sessionId, int state);
|
||||
void notifyIsLoadingChanged(String sessionId, boolean isLoading);
|
||||
void notifyPositionDiscontinuity(String sessionId,
|
||||
|
@ -789,7 +789,9 @@ public class MediaControllerCompatCallbackWithMediaSessionTest {
|
||||
session
|
||||
.getMockPlayer()
|
||||
.notifyPlayWhenReadyChanged(
|
||||
/* playWhenReady= */ false, Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
/* playWhenReady= */ false,
|
||||
Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||
Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
assertThat(playbackStateCompatRef.get().getState()).isEqualTo(PlaybackStateCompat.STATE_PAUSED);
|
||||
@ -833,7 +835,9 @@ public class MediaControllerCompatCallbackWithMediaSessionTest {
|
||||
session
|
||||
.getMockPlayer()
|
||||
.notifyPlayWhenReadyChanged(
|
||||
/* playWhenReady= */ true, Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
/* playWhenReady= */ true,
|
||||
Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||
Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
assertThat(playbackStateCompatRef.get().getState())
|
||||
@ -919,6 +923,7 @@ public class MediaControllerCompatCallbackWithMediaSessionTest {
|
||||
.getMockPlayer()
|
||||
.notifyPlayWhenReadyChanged(
|
||||
/* playWhenReady= */ true,
|
||||
Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||
Player.PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS);
|
||||
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
@ -969,6 +974,7 @@ public class MediaControllerCompatCallbackWithMediaSessionTest {
|
||||
.getMockPlayer()
|
||||
.notifyPlayWhenReadyChanged(
|
||||
/* playWhenReady= */ true,
|
||||
Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||
Player.PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS);
|
||||
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
@ -1015,7 +1021,9 @@ public class MediaControllerCompatCallbackWithMediaSessionTest {
|
||||
session
|
||||
.getMockPlayer()
|
||||
.notifyPlayWhenReadyChanged(
|
||||
/* playWhenReady= */ true, Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
/* playWhenReady= */ true,
|
||||
Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||
Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
assertThat(playbackStateCompatRef.get().getState())
|
||||
|
@ -1454,7 +1454,9 @@ public class MediaControllerListenerTest {
|
||||
};
|
||||
threadTestRule.getHandler().postAndSync(() -> controller.addListener(listener));
|
||||
|
||||
remoteSession.getMockPlayer().notifyPlayWhenReadyChanged(testPlayWhenReady, testReason);
|
||||
remoteSession
|
||||
.getMockPlayer()
|
||||
.notifyPlayWhenReadyChanged(testPlayWhenReady, testReason, testSuppressionReason);
|
||||
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
assertThat(playWhenReadyParamRef.get()).isEqualTo(testPlayWhenReady);
|
||||
@ -1469,6 +1471,44 @@ public class MediaControllerListenerTest {
|
||||
Player.EVENT_PLAY_WHEN_READY_CHANGED, Player.EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPlayWhenReadyReasonChanged_isNotified() throws Exception {
|
||||
remoteSession
|
||||
.getMockPlayer()
|
||||
.setPlayWhenReady(
|
||||
/* playWhenReady= */ false,
|
||||
Player.PLAYBACK_SUPPRESSION_REASON_TRANSIENT_AUDIO_FOCUS_LOSS);
|
||||
MediaController controller = controllerTestRule.createController(remoteSession.getToken());
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicBoolean playWhenReadyParamRef = new AtomicBoolean();
|
||||
AtomicBoolean playWhenReadyGetterRef = new AtomicBoolean();
|
||||
AtomicInteger playWhenReadyReasonParamRef = new AtomicInteger();
|
||||
Player.Listener listener =
|
||||
new Player.Listener() {
|
||||
@Override
|
||||
public void onPlayWhenReadyChanged(boolean playWhenReady, int reason) {
|
||||
playWhenReadyParamRef.set(playWhenReady);
|
||||
playWhenReadyGetterRef.set(controller.getPlayWhenReady());
|
||||
playWhenReadyReasonParamRef.set(reason);
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
threadTestRule.getHandler().postAndSync(() -> controller.addListener(listener));
|
||||
|
||||
remoteSession
|
||||
.getMockPlayer()
|
||||
.notifyPlayWhenReadyChanged(
|
||||
/* playWhenReady= */ false,
|
||||
Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS,
|
||||
Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
assertThat(playWhenReadyParamRef.get()).isFalse();
|
||||
assertThat(playWhenReadyGetterRef.get()).isFalse();
|
||||
assertThat(playWhenReadyReasonParamRef.get())
|
||||
.isEqualTo(Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onPlayWhenReadyChanged_updatesGetters() throws Exception {
|
||||
boolean testPlayWhenReady = true;
|
||||
@ -1550,7 +1590,10 @@ public class MediaControllerListenerTest {
|
||||
remoteSession.getMockPlayer().setTotalBufferedDuration(testTotalBufferedDurationMs);
|
||||
remoteSession.getMockPlayer().setCurrentLiveOffset(testCurrentLiveOffsetMs);
|
||||
remoteSession.getMockPlayer().setContentBufferedPosition(testContentBufferedPositionMs);
|
||||
remoteSession.getMockPlayer().notifyPlayWhenReadyChanged(testPlayWhenReady, testReason);
|
||||
remoteSession
|
||||
.getMockPlayer()
|
||||
.notifyPlayWhenReadyChanged(
|
||||
testPlayWhenReady, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, testReason);
|
||||
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
assertThat(playWhenReadyRef.get()).isEqualTo(testPlayWhenReady);
|
||||
@ -1604,7 +1647,10 @@ public class MediaControllerListenerTest {
|
||||
};
|
||||
threadTestRule.getHandler().postAndSync(() -> controller.addListener(listener));
|
||||
|
||||
remoteSession.getMockPlayer().notifyPlayWhenReadyChanged(testPlayWhenReady, testReason);
|
||||
remoteSession
|
||||
.getMockPlayer()
|
||||
.notifyPlayWhenReadyChanged(
|
||||
testPlayWhenReady, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, testReason);
|
||||
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
assertThat(playbackSuppressionReasonParamRef.get()).isEqualTo(testReason);
|
||||
@ -1686,7 +1732,10 @@ public class MediaControllerListenerTest {
|
||||
remoteSession.getMockPlayer().setTotalBufferedDuration(testTotalBufferedDurationMs);
|
||||
remoteSession.getMockPlayer().setCurrentLiveOffset(testCurrentLiveOffsetMs);
|
||||
remoteSession.getMockPlayer().setContentBufferedPosition(testContentBufferedPositionMs);
|
||||
remoteSession.getMockPlayer().notifyPlayWhenReadyChanged(testPlayWhenReady, testReason);
|
||||
remoteSession
|
||||
.getMockPlayer()
|
||||
.notifyPlayWhenReadyChanged(
|
||||
testPlayWhenReady, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST, testReason);
|
||||
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
assertThat(playbackSuppressionReasonRef.get()).isEqualTo(testReason);
|
||||
|
@ -225,7 +225,9 @@ public class MediaSessionAndControllerTest {
|
||||
.postAndSync(
|
||||
() ->
|
||||
player.notifyPlayWhenReadyChanged(
|
||||
testPlayWhenReady, Player.PLAYBACK_SUPPRESSION_REASON_NONE));
|
||||
testPlayWhenReady,
|
||||
Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||
Player.PLAYBACK_SUPPRESSION_REASON_NONE));
|
||||
|
||||
assertThat(latch.await(TIMEOUT_MS, MILLISECONDS)).isTrue();
|
||||
assertThat(playWhenReadyRef.get()).isEqualTo(testPlayWhenReady);
|
||||
|
@ -101,7 +101,9 @@ public class MediaSessionKeyEventTest {
|
||||
handler.postAndSync(
|
||||
() -> {
|
||||
player.notifyPlayWhenReadyChanged(
|
||||
/* playWhenReady= */ true, Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
/* playWhenReady= */ true,
|
||||
Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||
Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
player.notifyPlaybackStateChanged(Player.STATE_READY);
|
||||
});
|
||||
} else {
|
||||
|
@ -856,13 +856,17 @@ public class MediaSessionProviderService extends Service {
|
||||
|
||||
@Override
|
||||
public void notifyPlayWhenReadyChanged(
|
||||
String sessionId, boolean playWhenReady, @Player.PlaybackSuppressionReason int reason)
|
||||
String sessionId,
|
||||
boolean playWhenReady,
|
||||
@Player.PlayWhenReadyChangeReason int playWhenReadyChangeReason,
|
||||
@Player.PlaybackSuppressionReason int suppressionReason)
|
||||
throws RemoteException {
|
||||
runOnHandler(
|
||||
() -> {
|
||||
MediaSession session = sessionMap.get(sessionId);
|
||||
MockPlayer player = (MockPlayer) session.getPlayer();
|
||||
player.notifyPlayWhenReadyChanged(playWhenReady, reason);
|
||||
player.notifyPlayWhenReadyChanged(
|
||||
playWhenReady, playWhenReadyChangeReason, suppressionReason);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -310,6 +310,7 @@ public class MockPlayer implements Player {
|
||||
public int deviceVolume;
|
||||
public boolean deviceMuted;
|
||||
public boolean playWhenReady;
|
||||
public @PlayWhenReadyChangeReason int playWhenReadyChangeReason;
|
||||
public @PlaybackSuppressionReason int playbackSuppressionReason;
|
||||
public @State int playbackState;
|
||||
public boolean isLoading;
|
||||
@ -404,7 +405,9 @@ public class MockPlayer implements Player {
|
||||
checkNotNull(conditionVariables.get(METHOD_PLAY)).open();
|
||||
if (changePlayerStateWithTransportControl) {
|
||||
notifyPlayWhenReadyChanged(
|
||||
/* playWhenReady= */ true, Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
/* playWhenReady= */ true,
|
||||
Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||
Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -413,7 +416,9 @@ public class MockPlayer implements Player {
|
||||
checkNotNull(conditionVariables.get(METHOD_PAUSE)).open();
|
||||
if (changePlayerStateWithTransportControl) {
|
||||
notifyPlayWhenReadyChanged(
|
||||
/* playWhenReady= */ false, Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
/* playWhenReady= */ false,
|
||||
Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||
Player.PLAYBACK_SUPPRESSION_REASON_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -585,22 +590,26 @@ public class MockPlayer implements Player {
|
||||
* Player.Listener#onIsPlayingChanged} as appropriate.
|
||||
*/
|
||||
public void notifyPlayWhenReadyChanged(
|
||||
boolean playWhenReady, @PlaybackSuppressionReason int playbackSuppressionReason) {
|
||||
boolean playWhenReadyChanged = (this.playWhenReady != playWhenReady);
|
||||
boolean playWhenReady,
|
||||
@PlayWhenReadyChangeReason int playWhenReadyChangeReason,
|
||||
@PlaybackSuppressionReason int playbackSuppressionReason) {
|
||||
boolean playWhenReadyChanged = this.playWhenReady != playWhenReady;
|
||||
boolean playWhenReadyReasonChanged =
|
||||
this.playWhenReadyChangeReason != playWhenReadyChangeReason;
|
||||
boolean playbackSuppressionReasonChanged =
|
||||
(this.playbackSuppressionReason != playbackSuppressionReason);
|
||||
if (!playWhenReadyChanged && !playbackSuppressionReasonChanged) {
|
||||
this.playbackSuppressionReason != playbackSuppressionReason;
|
||||
if (!playWhenReadyChanged && !playbackSuppressionReasonChanged && !playWhenReadyReasonChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean wasPlaying = isPlaying();
|
||||
this.playWhenReady = playWhenReady;
|
||||
this.playWhenReadyChangeReason = playWhenReadyChangeReason;
|
||||
this.playbackSuppressionReason = playbackSuppressionReason;
|
||||
boolean isPlaying = isPlaying();
|
||||
for (Listener listener : listeners) {
|
||||
if (playWhenReadyChanged) {
|
||||
listener.onPlayWhenReadyChanged(
|
||||
playWhenReady, Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
|
||||
if (playWhenReadyChanged || playWhenReadyReasonChanged) {
|
||||
listener.onPlayWhenReadyChanged(playWhenReady, playWhenReadyChangeReason);
|
||||
}
|
||||
if (playbackSuppressionReasonChanged) {
|
||||
listener.onPlaybackSuppressionReasonChanged(playbackSuppressionReason);
|
||||
|
@ -314,9 +314,12 @@ public class RemoteMediaSession {
|
||||
}
|
||||
|
||||
public void notifyPlayWhenReadyChanged(
|
||||
boolean playWhenReady, @Player.PlaybackSuppressionReason int reason)
|
||||
boolean playWhenReady,
|
||||
@Player.PlayWhenReadyChangeReason int playWhenReadyChangeReason,
|
||||
@Player.PlaybackSuppressionReason int suppressionReason)
|
||||
throws RemoteException {
|
||||
binder.notifyPlayWhenReadyChanged(sessionId, playWhenReady, reason);
|
||||
binder.notifyPlayWhenReadyChanged(
|
||||
sessionId, playWhenReady, playWhenReadyChangeReason, suppressionReason);
|
||||
}
|
||||
|
||||
public void notifyPlaybackStateChanged(@Player.State int state) throws RemoteException {
|
||||
|
Loading…
x
Reference in New Issue
Block a user