Add MediaSession.Builder().setPeriodicPositionUpdateEnabled()

This allows to disable periodic position updates when building
the session.

#minor-release

PiperOrigin-RevId: 572531837
This commit is contained in:
bachinger 2023-10-11 04:07:05 -07:00 committed by Copybara-Service
parent 164e658839
commit 4dc3db4da3
5 changed files with 127 additions and 15 deletions

View File

@ -518,6 +518,20 @@ public abstract class MediaLibraryService extends MediaSessionService {
return super.setShowPlayButtonIfPlaybackIsSuppressed(showPlayButtonIfPlaybackIsSuppressed);
}
/**
* Sets whether periodic position updates should be sent to controllers while playing. If
* false, no periodic position updates are sent to controllers.
*
* <p>The default is {@code true}.
*
* @param isEnabled Whether periodic position update is enabled.
*/
@UnstableApi
@Override
public Builder setPeriodicPositionUpdateEnabled(boolean isEnabled) {
return super.setPeriodicPositionUpdateEnabled(isEnabled);
}
/**
* Builds a {@link MediaLibrarySession}.
*
@ -539,7 +553,8 @@ public abstract class MediaLibraryService extends MediaSessionService {
callback,
extras,
checkNotNull(bitmapLoader),
playIfSuppressed);
playIfSuppressed,
isPeriodicPositionUpdateEnabled);
}
}
@ -552,7 +567,8 @@ public abstract class MediaLibraryService extends MediaSessionService {
MediaSession.Callback callback,
Bundle tokenExtras,
BitmapLoader bitmapLoader,
boolean playIfSuppressed) {
boolean playIfSuppressed,
boolean isPeriodicPositionUpdateEnabled) {
super(
context,
id,
@ -562,7 +578,8 @@ public abstract class MediaLibraryService extends MediaSessionService {
callback,
tokenExtras,
bitmapLoader,
playIfSuppressed);
playIfSuppressed,
isPeriodicPositionUpdateEnabled);
}
@Override
@ -575,7 +592,8 @@ public abstract class MediaLibraryService extends MediaSessionService {
MediaSession.Callback callback,
Bundle tokenExtras,
BitmapLoader bitmapLoader,
boolean playIfSuppressed) {
boolean playIfSuppressed,
boolean isPeriodicPositionUpdateEnabled) {
return new MediaLibrarySessionImpl(
this,
context,
@ -586,7 +604,8 @@ public abstract class MediaLibraryService extends MediaSessionService {
(Callback) callback,
tokenExtras,
bitmapLoader,
playIfSuppressed);
playIfSuppressed,
isPeriodicPositionUpdateEnabled);
}
@Override

View File

@ -75,7 +75,8 @@ import java.util.concurrent.Future;
MediaLibrarySession.Callback callback,
Bundle tokenExtras,
BitmapLoader bitmapLoader,
boolean playIfSuppressed) {
boolean playIfSuppressed,
boolean isPeriodicPositionUpdateEnabled) {
super(
instance,
context,
@ -86,7 +87,8 @@ import java.util.concurrent.Future;
callback,
tokenExtras,
bitmapLoader,
playIfSuppressed);
playIfSuppressed,
isPeriodicPositionUpdateEnabled);
this.instance = instance;
this.callback = callback;
parentIdToSubscribedControllers = HashMultimap.create();

View File

@ -376,6 +376,20 @@ public class MediaSession {
return super.setCustomLayout(customLayout);
}
/**
* Sets whether periodic position updates should be sent to controllers while playing. If false,
* no periodic position updates are sent to controllers.
*
* <p>The default is {@code true}.
*
* @param isEnabled Whether periodic position update is enabled.
*/
@UnstableApi
@Override
public Builder setPeriodicPositionUpdateEnabled(boolean isEnabled) {
return super.setPeriodicPositionUpdateEnabled(isEnabled);
}
/**
* Sets whether a play button is shown if playback is {@linkplain
* Player#getPlaybackSuppressionReason() suppressed}.
@ -413,7 +427,8 @@ public class MediaSession {
callback,
extras,
checkNotNull(bitmapLoader),
playIfSuppressed);
playIfSuppressed,
isPeriodicPositionUpdateEnabled);
}
}
@ -606,7 +621,8 @@ public class MediaSession {
Callback callback,
Bundle tokenExtras,
BitmapLoader bitmapLoader,
boolean playIfSuppressed) {
boolean playIfSuppressed,
boolean isPeriodicPositionUpdateEnabled) {
synchronized (STATIC_LOCK) {
if (SESSION_ID_TO_SESSION_MAP.containsKey(id)) {
throw new IllegalStateException("Session ID must be unique. ID=" + id);
@ -623,7 +639,8 @@ public class MediaSession {
callback,
tokenExtras,
bitmapLoader,
playIfSuppressed);
playIfSuppressed,
isPeriodicPositionUpdateEnabled);
}
/* package */ MediaSessionImpl createImpl(
@ -635,7 +652,8 @@ public class MediaSession {
Callback callback,
Bundle tokenExtras,
BitmapLoader bitmapLoader,
boolean playIfSuppressed) {
boolean playIfSuppressed,
boolean isPeriodicPositionUpdateEnabled) {
return new MediaSessionImpl(
this,
context,
@ -646,7 +664,8 @@ public class MediaSession {
callback,
tokenExtras,
bitmapLoader,
playIfSuppressed);
playIfSuppressed,
isPeriodicPositionUpdateEnabled);
}
/* package */ MediaSessionImpl getImpl() {
@ -1798,8 +1817,8 @@ public class MediaSession {
/* package */ Bundle extras;
/* package */ @MonotonicNonNull BitmapLoader bitmapLoader;
/* package */ boolean playIfSuppressed;
/* package */ ImmutableList<CommandButton> customLayout;
/* package */ boolean isPeriodicPositionUpdateEnabled;
public BuilderBase(Context context, Player player, CallbackT callback) {
this.context = checkNotNull(context);
@ -1810,6 +1829,7 @@ public class MediaSession {
extras = Bundle.EMPTY;
customLayout = ImmutableList.of();
playIfSuppressed = true;
isPeriodicPositionUpdateEnabled = true;
}
@SuppressWarnings("unchecked")
@ -1855,6 +1875,12 @@ public class MediaSession {
return (BuilderT) this;
}
@SuppressWarnings("unchecked")
public BuilderT setPeriodicPositionUpdateEnabled(boolean isPeriodicPositionUpdateEnabled) {
this.isPeriodicPositionUpdateEnabled = isPeriodicPositionUpdateEnabled;
return (BuilderT) this;
}
public abstract SessionT build();
}
}

View File

@ -117,6 +117,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final Runnable periodicSessionPositionInfoUpdateRunnable;
private final Handler mainHandler;
private final boolean playIfSuppressed;
private final boolean isPeriodicPositionUpdateEnabled;
private PlayerInfo playerInfo;
private PlayerWrapper playerWrapper;
@ -148,7 +149,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
MediaSession.Callback callback,
Bundle tokenExtras,
BitmapLoader bitmapLoader,
boolean playIfSuppressed) {
boolean playIfSuppressed,
boolean isPeriodicPositionUpdateEnabled) {
this.context = context;
this.instance = instance;
@ -166,6 +168,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
this.callback = callback;
this.bitmapLoader = bitmapLoader;
this.playIfSuppressed = playIfSuppressed;
this.isPeriodicPositionUpdateEnabled = isPeriodicPositionUpdateEnabled;
playerInfo = PlayerInfo.DEFAULT;
onPlayerInfoChangedHandler = new PlayerInfoChangedHandler(player.getApplicationLooper());
@ -1053,7 +1056,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private void schedulePeriodicSessionPositionInfoChanges() {
applicationHandler.removeCallbacks(periodicSessionPositionInfoUpdateRunnable);
if (sessionPositionUpdateDelayMs > 0
if (isPeriodicPositionUpdateEnabled
&& sessionPositionUpdateDelayMs > 0
&& (playerWrapper.isPlaying() || playerWrapper.isLoading())) {
applicationHandler.postDelayed(
periodicSessionPositionInfoUpdateRunnable, sessionPositionUpdateDelayMs);

View File

@ -33,6 +33,7 @@ import android.support.v4.media.session.MediaSessionCompat;
import android.text.TextUtils;
import androidx.media.MediaSessionManager;
import androidx.media3.common.MediaLibraryInfo;
import androidx.media3.common.Player;
import androidx.media3.common.util.Log;
import androidx.media3.common.util.Util;
import androidx.media3.test.session.common.HandlerThreadTestRule;
@ -41,6 +42,8 @@ import androidx.media3.test.session.common.TestHandler;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@ -433,4 +436,62 @@ public class MediaSessionTest {
// version of remote controller.
assertThat(controllerVersionRef.get()).isEqualTo(MediaLibraryInfo.VERSION_INT);
}
@Test
public void setPeriodicPositionUpdateEnabled_periodicUpdatesEnabled_bufferedPositionMsUpdated()
throws Exception {
player.playWhenReady = true;
player.playbackState = Player.STATE_READY;
MediaSession session =
sessionTestRule.ensureReleaseAfterTest(
new MediaSession.Builder(context, player)
.setPeriodicPositionUpdateEnabled(true)
.setId(
"setPeriodicPositionUpdateEnabled_periodicUpdatesEnabled_bufferedPositionMsUpdated")
.build());
threadTestRule.getHandler().postAndSync(() -> session.setSessionPositionUpdateDelayMs(10L));
MediaController controller =
new MediaController.Builder(ApplicationProvider.getApplicationContext(), session.getToken())
.buildAsync()
.get();
List<Long> bufferedPositionsMs = new ArrayList<>();
TestHandler testHandler = new TestHandler(controller.getApplicationLooper());
for (long bufferedPositionMs = 0; bufferedPositionMs < 5000; bufferedPositionMs += 1000) {
player.bufferedPosition = bufferedPositionMs;
Thread.sleep(50L);
bufferedPositionsMs.add(testHandler.postAndSync(controller::getBufferedPosition));
}
assertThat(bufferedPositionsMs).containsExactly(0L, 1000L, 2000L, 3000L, 4000L).inOrder();
}
@Test
public void setPeriodicPositionUpdateEnabled_periodicUpdatesDisabled_bufferedPositionMsUnchanged()
throws Exception {
player.playWhenReady = true;
player.playbackState = Player.STATE_READY;
MediaSession session =
sessionTestRule.ensureReleaseAfterTest(
new MediaSession.Builder(context, player)
.setPeriodicPositionUpdateEnabled(false)
.setId(
"setPeriodicPositionUpdateEnabled_periodicUpdatesDisabled_bufferedPositionMsUnchanged")
.build());
threadTestRule.getHandler().postAndSync(() -> session.setSessionPositionUpdateDelayMs(10L));
MediaController controller =
new MediaController.Builder(ApplicationProvider.getApplicationContext(), session.getToken())
.buildAsync()
.get();
List<Long> bufferedPositionsMs = new ArrayList<>();
TestHandler testHandler = new TestHandler(controller.getApplicationLooper());
for (long bufferedPositionMs = 0; bufferedPositionMs < 5000; bufferedPositionMs += 1000) {
player.bufferedPosition = bufferedPositionMs;
Thread.sleep(50L);
bufferedPositionsMs.add(testHandler.postAndSync(controller::getBufferedPosition));
}
assertThat(bufferedPositionsMs).containsExactly(0L, 0L, 0L, 0L, 0L).inOrder();
}
}