diff --git a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java index d01fb6eee3..4e075c18bd 100644 --- a/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java +++ b/libraries/session/src/main/java/androidx/media3/session/MediaSessionImpl.java @@ -121,6 +121,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; @Nullable private final BroadcastReceiver broadcastReceiver; private final Handler applicationHandler; private final BitmapLoader bitmapLoader; + private final Runnable periodicSessionPositionInfoUpdateRunnable; @Nullable private PlayerListener playerListener; @Nullable private MediaSession.Listener mediaSessionListener; @@ -246,8 +247,9 @@ import org.checkerframework.checker.initialization.qual.Initialized; /* oldPlayerWrapper= */ null, /* newPlayerWrapper= */ playerWrapper)); sessionPositionUpdateDelayMs = DEFAULT_SESSION_POSITION_UPDATE_DELAY_MS; - applicationHandler.postDelayed( - thisRef::notifyPeriodicSessionPositionInfoChangesOnHandler, sessionPositionUpdateDelayMs); + periodicSessionPositionInfoUpdateRunnable = + thisRef::notifyPeriodicSessionPositionInfoChangesOnHandler; + postOrRun(applicationHandler, thisRef::schedulePeriodicSessionPositionInfoChanges); } public void setPlayer(Player player) { @@ -567,10 +569,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; protected void setSessionPositionUpdateDelayMsOnHandler(long updateDelayMs) { verifyApplicationThread(); sessionPositionUpdateDelayMs = updateDelayMs; - - applicationHandler.removeCallbacks(this::notifyPeriodicSessionPositionInfoChangesOnHandler); - applicationHandler.postDelayed( - this::notifyPeriodicSessionPositionInfoChangesOnHandler, updateDelayMs); + schedulePeriodicSessionPositionInfoChanges(); } @Nullable @@ -718,9 +717,15 @@ import org.checkerframework.checker.initialization.qual.Initialized; SessionPositionInfo sessionPositionInfo = playerWrapper.createSessionPositionInfoForBundling(); dispatchRemoteControllerTaskWithoutReturn( (callback, seq) -> callback.onPeriodicSessionPositionInfoChanged(seq, sessionPositionInfo)); - if (sessionPositionUpdateDelayMs > 0) { + schedulePeriodicSessionPositionInfoChanges(); + } + + private void schedulePeriodicSessionPositionInfoChanges() { + applicationHandler.removeCallbacks(periodicSessionPositionInfoUpdateRunnable); + if (sessionPositionUpdateDelayMs > 0 + && (playerWrapper.isPlaying() || playerWrapper.isLoading())) { applicationHandler.postDelayed( - this::notifyPeriodicSessionPositionInfoChangesOnHandler, sessionPositionUpdateDelayMs); + periodicSessionPositionInfoUpdateRunnable, sessionPositionUpdateDelayMs); } } @@ -859,6 +864,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; /* excludeTimeline= */ true, /* excludeTracks= */ true); session.dispatchRemoteControllerTaskToLegacyStub( (callback, seq) -> callback.onIsPlayingChanged(seq, isPlaying)); + session.schedulePeriodicSessionPositionInfoChanges(); } @Override @@ -877,6 +883,7 @@ import org.checkerframework.checker.initialization.qual.Initialized; /* excludeTimeline= */ true, /* excludeTracks= */ true); session.dispatchRemoteControllerTaskToLegacyStub( (callback, seq) -> callback.onIsLoadingChanged(seq, isLoading)); + session.schedulePeriodicSessionPositionInfoChanges(); } @Override diff --git a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerTest.java b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerTest.java index 3c13e756ce..a7b5dbfc6c 100644 --- a/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerTest.java +++ b/libraries/test_session_current/src/androidTest/java/androidx/media3/session/MediaControllerTest.java @@ -24,6 +24,7 @@ import static androidx.media3.test.session.common.MediaSessionConstants.KEY_AVAI import static androidx.media3.test.session.common.MediaSessionConstants.TEST_GET_SESSION_ACTIVITY; import static androidx.media3.test.session.common.MediaSessionConstants.TEST_IS_SESSION_COMMAND_AVAILABLE; import static androidx.media3.test.session.common.TestUtils.LONG_TIMEOUT_MS; +import static androidx.media3.test.session.common.TestUtils.NO_RESPONSE_TIMEOUT_MS; import static androidx.media3.test.session.common.TestUtils.TIMEOUT_MS; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; @@ -984,11 +985,18 @@ public class MediaControllerTest { @Test public void getBufferedPosition_withPeriodicUpdate_updatedWithoutCallback() throws Exception { long testBufferedPosition = 999L; + Bundle playerConfig = + new RemoteMediaSession.MockPlayerConfigBuilder() + .setPlayWhenReady(true) + .setPlaybackSuppressionReason(Player.PLAYBACK_SUPPRESSION_REASON_NONE) + .setPlaybackState(Player.STATE_READY) + .setIsLoading(true) + .build(); + remoteSession.setPlayer(playerConfig); MediaController controller = controllerTestRule.createController(remoteSession.getToken()); + remoteSession.setSessionPositionUpdateDelayMs(10L); + remoteSession.getMockPlayer().setBufferedPosition(testBufferedPosition); - - remoteSession.setSessionPositionUpdateDelayMs(0L); - PollingCheck.waitFor( TIMEOUT_MS, () -> { @@ -998,6 +1006,31 @@ public class MediaControllerTest { }); } + @Test + public void getBufferedPosition_whilePausedAndNotLoading_isNotUpdatedPeriodically() + throws Exception { + long testBufferedPosition = 999L; + Bundle playerConfig = + new RemoteMediaSession.MockPlayerConfigBuilder() + .setPlayWhenReady(false) + .setPlaybackSuppressionReason(Player.PLAYBACK_SUPPRESSION_REASON_NONE) + .setPlaybackState(Player.STATE_READY) + .setIsLoading(false) + .build(); + remoteSession.setPlayer(playerConfig); + MediaController controller = controllerTestRule.createController(remoteSession.getToken()); + remoteSession.setSessionPositionUpdateDelayMs(10L); + + remoteSession.getMockPlayer().setBufferedPosition(testBufferedPosition); + Thread.sleep(NO_RESPONSE_TIMEOUT_MS); + AtomicLong bufferedPositionAfterDelay = new AtomicLong(); + threadTestRule + .getHandler() + .postAndSync(() -> bufferedPositionAfterDelay.set(controller.getBufferedPosition())); + + assertThat(bufferedPositionAfterDelay.get()).isNotEqualTo(testBufferedPosition); + } + @Test public void getContentBufferedPosition_byDefault_returnsZero() throws Exception { MediaController controller = controllerTestRule.createController(remoteSession.getToken());