Split available command filtering and bundling

A few methods in PlayerInfo and related classes combine filtering
information with bundling in one method. This makes it impossible
to use just the filtering for example and it's also easier to reason
about than two dedicated methods. This change splits these methods
into two parts accordingly.

PiperOrigin-RevId: 572592458
This commit is contained in:
tonihei 2023-10-11 09:06:31 -07:00 committed by Copybara-Service
parent 7fdc5b22ba
commit 4ebe630a80
7 changed files with 374 additions and 208 deletions

View File

@ -350,15 +350,9 @@ public interface Player {
return false;
}
PositionInfo that = (PositionInfo) o;
return mediaItemIndex == that.mediaItemIndex
&& periodIndex == that.periodIndex
&& positionMs == that.positionMs
&& contentPositionMs == that.contentPositionMs
&& adGroupIndex == that.adGroupIndex
&& adIndexInAdGroup == that.adIndexInAdGroup
return equalsForBundling(that)
&& Objects.equal(windowUid, that.windowUid)
&& Objects.equal(periodUid, that.periodUid)
&& Objects.equal(mediaItem, that.mediaItem);
&& Objects.equal(periodUid, that.periodUid);
}
@Override
@ -375,6 +369,21 @@ public interface Player {
adIndexInAdGroup);
}
/**
* Returns whether this position info and the other position info would result in the same
* {@link #toBundle() Bundle}.
*/
@UnstableApi
public boolean equalsForBundling(PositionInfo other) {
return mediaItemIndex == other.mediaItemIndex
&& periodIndex == other.periodIndex
&& positionMs == other.positionMs
&& contentPositionMs == other.contentPositionMs
&& adGroupIndex == other.adGroupIndex
&& adIndexInAdGroup == other.adIndexInAdGroup
&& Objects.equal(mediaItem, other.mediaItem);
}
// Bundleable implementation.
private static final String FIELD_MEDIA_ITEM_INDEX = Util.intToStringMaxRadix(0);
@ -385,6 +394,36 @@ public interface Player {
private static final String FIELD_AD_GROUP_INDEX = Util.intToStringMaxRadix(5);
private static final String FIELD_AD_INDEX_IN_AD_GROUP = Util.intToStringMaxRadix(6);
/**
* Returns a copy of this position info, filtered by the specified available commands.
*
* <p>The filtered fields are reset to their default values.
*
* <p>The return value may be the same object if nothing is filtered.
*
* @param canAccessCurrentMediaItem Whether {@link Player#COMMAND_GET_CURRENT_MEDIA_ITEM} is
* available.
* @param canAccessTimeline Whether {@link Player#COMMAND_GET_TIMELINE} is available.
* @return The filtered position info.
*/
@UnstableApi
public PositionInfo filterByAvailableCommands(
boolean canAccessCurrentMediaItem, boolean canAccessTimeline) {
if (canAccessCurrentMediaItem && canAccessTimeline) {
return this;
}
return new PositionInfo(
windowUid,
canAccessTimeline ? mediaItemIndex : 0,
canAccessCurrentMediaItem ? mediaItem : null,
periodUid,
canAccessTimeline ? periodIndex : 0,
canAccessCurrentMediaItem ? positionMs : 0,
canAccessCurrentMediaItem ? contentPositionMs : 0,
canAccessCurrentMediaItem ? adGroupIndex : C.INDEX_UNSET,
canAccessCurrentMediaItem ? adIndexInAdGroup : C.INDEX_UNSET);
}
/**
* {@inheritDoc}
*
@ -394,31 +433,28 @@ public interface Player {
@UnstableApi
@Override
public Bundle toBundle() {
return toBundle(/* canAccessCurrentMediaItem= */ true, /* canAccessTimeline= */ true);
}
/**
* Returns a {@link Bundle} representing the information stored in this object, filtered by
* available commands.
*
* @param canAccessCurrentMediaItem Whether the {@link Bundle} should contain information
* accessbile with {@link #COMMAND_GET_CURRENT_MEDIA_ITEM}.
* @param canAccessTimeline Whether the {@link Bundle} should contain information accessbile
* with {@link #COMMAND_GET_TIMELINE}.
*/
@UnstableApi
public Bundle toBundle(boolean canAccessCurrentMediaItem, boolean canAccessTimeline) {
Bundle bundle = new Bundle();
bundle.putInt(FIELD_MEDIA_ITEM_INDEX, canAccessTimeline ? mediaItemIndex : 0);
if (mediaItem != null && canAccessCurrentMediaItem) {
if (mediaItemIndex != 0) {
bundle.putInt(FIELD_MEDIA_ITEM_INDEX, mediaItemIndex);
}
if (mediaItem != null) {
bundle.putBundle(FIELD_MEDIA_ITEM, mediaItem.toBundle());
}
bundle.putInt(FIELD_PERIOD_INDEX, canAccessTimeline ? periodIndex : 0);
bundle.putLong(FIELD_POSITION_MS, canAccessCurrentMediaItem ? positionMs : 0);
bundle.putLong(FIELD_CONTENT_POSITION_MS, canAccessCurrentMediaItem ? contentPositionMs : 0);
bundle.putInt(FIELD_AD_GROUP_INDEX, canAccessCurrentMediaItem ? adGroupIndex : C.INDEX_UNSET);
bundle.putInt(
FIELD_AD_INDEX_IN_AD_GROUP, canAccessCurrentMediaItem ? adIndexInAdGroup : C.INDEX_UNSET);
if (periodIndex != 0) {
bundle.putInt(FIELD_PERIOD_INDEX, periodIndex);
}
if (positionMs != 0) {
bundle.putLong(FIELD_POSITION_MS, positionMs);
}
if (contentPositionMs != 0) {
bundle.putLong(FIELD_CONTENT_POSITION_MS, contentPositionMs);
}
if (adGroupIndex != C.INDEX_UNSET) {
bundle.putInt(FIELD_AD_GROUP_INDEX, adGroupIndex);
}
if (adIndexInAdGroup != C.INDEX_UNSET) {
bundle.putInt(FIELD_AD_INDEX_IN_AD_GROUP, adIndexInAdGroup);
}
return bundle;
}

View File

@ -1443,36 +1443,29 @@ public abstract class Timeline implements Bundleable {
}
/**
* Returns a {@link Bundle} containing just the specified {@link Window}.
* Returns a copy of this timeline containing just the single specified {@link Window}.
*
* <p>The {@link #getWindow(int, Window)} windows} and {@link #getPeriod(int, Period) periods} of
* an instance restored by {@link #CREATOR} may have missing fields as described in {@link
* Window#toBundle()} and {@link Period#toBundle()}.
* <p>The method returns the same instance if there is only one window.
*
* @param windowIndex The index of the {@link Window} to include in the {@link Bundle}.
* @param windowIndex The index of the {@link Window} to include in the copy.
* @return A {@link Timeline} with just the single specified {@link Window}.
*/
@UnstableApi
public final Bundle toBundleWithOneWindowOnly(int windowIndex) {
Window window = getWindow(windowIndex, new Window(), /* defaultPositionProjectionUs= */ 0);
List<Bundle> periodBundles = new ArrayList<>();
Period period = new Period();
for (int i = window.firstPeriodIndex; i <= window.lastPeriodIndex; i++) {
getPeriod(i, period, /* setIds= */ false);
period.windowIndex = 0;
periodBundles.add(period.toBundle());
public final Timeline copyWithSingleWindow(int windowIndex) {
if (getWindowCount() == 1) {
return this;
}
Window window = getWindow(windowIndex, new Window(), /* defaultPositionProjectionUs= */ 0);
ImmutableList.Builder<Period> periods = ImmutableList.builder();
for (int i = window.firstPeriodIndex; i <= window.lastPeriodIndex; i++) {
Period period = getPeriod(i, new Period(), /* setIds= */ true);
period.windowIndex = 0;
periods.add(period);
}
window.lastPeriodIndex = window.lastPeriodIndex - window.firstPeriodIndex;
window.firstPeriodIndex = 0;
Bundle windowBundle = window.toBundle();
Bundle bundle = new Bundle();
BundleUtil.putBinder(
bundle, FIELD_WINDOWS, new BundleListRetriever(ImmutableList.of(windowBundle)));
BundleUtil.putBinder(bundle, FIELD_PERIODS, new BundleListRetriever(periodBundles));
bundle.putIntArray(FIELD_SHUFFLED_WINDOW_INDICES, new int[] {0});
return bundle;
return new RemotableTimeline(
ImmutableList.of(window), periods.build(), /* shuffledWindowIndices= */ new int[] {0});
}
/**

View File

@ -111,8 +111,10 @@ import java.util.List;
MediaUtils.intersect(playerCommandsFromSession, playerCommandsFromPlayer);
bundle.putBundle(
FIELD_PLAYER_INFO,
playerInfo.toBundle(
intersectedCommands, /* excludeTimeline= */ false, /* excludeTracks= */ false));
playerInfo
.filterByAvailableCommands(
intersectedCommands, /* excludeTimeline= */ false, /* excludeTracks= */ false)
.toBundle());
bundle.putInt(FIELD_SESSION_INTERFACE_VERSION, sessionInterfaceVersion);
return bundle;
}

View File

@ -1913,17 +1913,20 @@ import java.util.concurrent.ExecutionException;
boolean bundlingExclusionsTracks =
excludeTracks || !availableCommands.contains(Player.COMMAND_GET_TRACKS);
if (controllerInterfaceVersion >= 2) {
PlayerInfo filteredPlayerInfo =
playerInfo.filterByAvailableCommands(availableCommands, excludeTimeline, excludeTracks);
iController.onPlayerInfoChangedWithExclusions(
sequenceNumber,
playerInfo.toBundle(availableCommands, excludeTimeline, excludeTracks),
filteredPlayerInfo.toBundle(),
new PlayerInfo.BundlingExclusions(bundlingExclusionsTimeline, bundlingExclusionsTracks)
.toBundle());
} else {
PlayerInfo filteredPlayerInfo =
playerInfo.filterByAvailableCommands(
availableCommands, excludeTimeline, /* excludeTracks= */ true);
//noinspection deprecation
iController.onPlayerInfoChanged(
sequenceNumber,
playerInfo.toBundle(availableCommands, excludeTimeline, /* excludeTracks= */ true),
bundlingExclusionsTimeline);
sequenceNumber, filteredPlayerInfo.toBundle(), bundlingExclusionsTimeline);
}
}
@ -1992,7 +1995,9 @@ import java.util.concurrent.ExecutionException;
throws RemoteException {
iController.onPeriodicSessionPositionInfoChanged(
sequenceNumber,
sessionPositionInfo.toBundle(canAccessCurrentMediaItem, canAccessTimeline));
sessionPositionInfo
.filterByAvailableCommands(canAccessCurrentMediaItem, canAccessTimeline)
.toBundle());
}
@Override

View File

@ -827,79 +827,158 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
// Next field key = 32
public Bundle toBundle(
/**
* Returns a copy of this player info, filtered by the specified available commands.
*
* <p>The filtered fields are reset to their default values.
*
* @param availableCommands The available {@link Player.Commands} used to filter values.
* @param excludeTimeline Whether to filter the {@link #timeline} even if {@link
* Player#COMMAND_GET_TIMELINE} is available.
* @param excludeTracks Whether to filter the {@link #currentTracks} even if {@link
* Player#COMMAND_GET_TRACKS} is available.
* @return The filtered player info.
*/
public PlayerInfo filterByAvailableCommands(
Player.Commands availableCommands, boolean excludeTimeline, boolean excludeTracks) {
Bundle bundle = new Bundle();
PlayerInfo.Builder builder = new Builder(this);
boolean canAccessCurrentMediaItem =
availableCommands.contains(Player.COMMAND_GET_CURRENT_MEDIA_ITEM);
boolean canAccessTimeline = availableCommands.contains(Player.COMMAND_GET_TIMELINE);
if (playerError != null) {
bundle.putBundle(FIELD_PLAYBACK_ERROR, playerError.toBundle());
builder.setSessionPositionInfo(
sessionPositionInfo.filterByAvailableCommands(
canAccessCurrentMediaItem, canAccessTimeline));
builder.setOldPositionInfo(
oldPositionInfo.filterByAvailableCommands(canAccessCurrentMediaItem, canAccessTimeline));
builder.setNewPositionInfo(
newPositionInfo.filterByAvailableCommands(canAccessCurrentMediaItem, canAccessTimeline));
if (!canAccessTimeline && canAccessCurrentMediaItem && !timeline.isEmpty()) {
builder.setTimeline(
timeline.copyWithSingleWindow(sessionPositionInfo.positionInfo.mediaItemIndex));
} else if (excludeTimeline || !canAccessTimeline) {
builder.setTimeline(Timeline.EMPTY);
}
bundle.putInt(FIELD_MEDIA_ITEM_TRANSITION_REASON, mediaItemTransitionReason);
bundle.putBundle(
FIELD_SESSION_POSITION_INFO,
sessionPositionInfo.toBundle(canAccessCurrentMediaItem, canAccessTimeline));
bundle.putBundle(
FIELD_OLD_POSITION_INFO,
oldPositionInfo.toBundle(canAccessCurrentMediaItem, canAccessTimeline));
bundle.putBundle(
FIELD_NEW_POSITION_INFO,
newPositionInfo.toBundle(canAccessCurrentMediaItem, canAccessTimeline));
bundle.putInt(FIELD_DISCONTINUITY_REASON, discontinuityReason);
bundle.putBundle(FIELD_PLAYBACK_PARAMETERS, playbackParameters.toBundle());
bundle.putInt(FIELD_REPEAT_MODE, repeatMode);
bundle.putBoolean(FIELD_SHUFFLE_MODE_ENABLED, shuffleModeEnabled);
if (!excludeTimeline && canAccessTimeline) {
bundle.putBundle(FIELD_TIMELINE, timeline.toBundle());
} else if (!canAccessTimeline && canAccessCurrentMediaItem && !timeline.isEmpty()) {
bundle.putBundle(
FIELD_TIMELINE,
timeline.toBundleWithOneWindowOnly(sessionPositionInfo.positionInfo.mediaItemIndex));
if (!availableCommands.contains(Player.COMMAND_GET_METADATA)) {
builder.setPlaylistMetadata(MediaMetadata.EMPTY);
}
bundle.putInt(FIELD_TIMELINE_CHANGE_REASON, timelineChangeReason);
bundle.putBundle(FIELD_VIDEO_SIZE, videoSize.toBundle());
if (availableCommands.contains(Player.COMMAND_GET_METADATA)) {
bundle.putBundle(FIELD_PLAYLIST_METADATA, playlistMetadata.toBundle());
if (!availableCommands.contains(Player.COMMAND_GET_VOLUME)) {
builder.setVolume(1);
}
if (availableCommands.contains(Player.COMMAND_GET_VOLUME)) {
bundle.putFloat(FIELD_VOLUME, volume);
if (!availableCommands.contains(Player.COMMAND_GET_AUDIO_ATTRIBUTES)) {
builder.setAudioAttributes(AudioAttributes.DEFAULT);
}
if (availableCommands.contains(Player.COMMAND_GET_AUDIO_ATTRIBUTES)) {
bundle.putBundle(FIELD_AUDIO_ATTRIBUTES, audioAttributes.toBundle());
if (!availableCommands.contains(Player.COMMAND_GET_TEXT)) {
builder.setCues(CueGroup.EMPTY_TIME_ZERO);
}
if (availableCommands.contains(Player.COMMAND_GET_TEXT)) {
bundle.putBundle(FIELD_CUE_GROUP, cueGroup.toBundle());
if (!availableCommands.contains(Player.COMMAND_GET_DEVICE_VOLUME)) {
builder.setDeviceVolume(0).setDeviceMuted(false);
}
bundle.putBundle(FIELD_DEVICE_INFO, deviceInfo.toBundle());
if (availableCommands.contains(Player.COMMAND_GET_DEVICE_VOLUME)) {
bundle.putInt(FIELD_DEVICE_VOLUME, deviceVolume);
bundle.putBoolean(FIELD_DEVICE_MUTED, deviceMuted);
if (!availableCommands.contains(Player.COMMAND_GET_METADATA)) {
builder.setMediaMetadata(MediaMetadata.EMPTY);
}
bundle.putBoolean(FIELD_PLAY_WHEN_READY, playWhenReady);
bundle.putInt(FIELD_PLAYBACK_SUPPRESSION_REASON, playbackSuppressionReason);
bundle.putInt(FIELD_PLAYBACK_STATE, playbackState);
bundle.putBoolean(FIELD_IS_PLAYING, isPlaying);
bundle.putBoolean(FIELD_IS_LOADING, isLoading);
if (availableCommands.contains(Player.COMMAND_GET_METADATA)) {
bundle.putBundle(FIELD_MEDIA_METADATA, mediaMetadata.toBundle());
if (excludeTracks || !availableCommands.contains(Player.COMMAND_GET_TRACKS)) {
builder.setCurrentTracks(Tracks.EMPTY);
}
bundle.putLong(FIELD_SEEK_BACK_INCREMENT_MS, seekBackIncrementMs);
bundle.putLong(FIELD_SEEK_FORWARD_INCREMENT_MS, seekForwardIncrementMs);
bundle.putLong(FIELD_MAX_SEEK_TO_PREVIOUS_POSITION_MS, maxSeekToPreviousPositionMs);
if (!excludeTracks && availableCommands.contains(Player.COMMAND_GET_TRACKS)) {
bundle.putBundle(FIELD_CURRENT_TRACKS, currentTracks.toBundle());
}
bundle.putBundle(FIELD_TRACK_SELECTION_PARAMETERS, trackSelectionParameters.toBundle());
return bundle;
return builder.build();
}
@Override
public Bundle toBundle() {
return toBundle(
/* availableCommands= */ new Player.Commands.Builder().addAllCommands().build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false);
Bundle bundle = new Bundle();
if (playerError != null) {
bundle.putBundle(FIELD_PLAYBACK_ERROR, playerError.toBundle());
}
if (mediaItemTransitionReason != MEDIA_ITEM_TRANSITION_REASON_DEFAULT) {
bundle.putInt(FIELD_MEDIA_ITEM_TRANSITION_REASON, mediaItemTransitionReason);
}
if (!sessionPositionInfo.equals(SessionPositionInfo.DEFAULT)) {
bundle.putBundle(FIELD_SESSION_POSITION_INFO, sessionPositionInfo.toBundle());
}
if (!SessionPositionInfo.DEFAULT_POSITION_INFO.equalsForBundling(oldPositionInfo)) {
bundle.putBundle(FIELD_OLD_POSITION_INFO, oldPositionInfo.toBundle());
}
if (!SessionPositionInfo.DEFAULT_POSITION_INFO.equalsForBundling(newPositionInfo)) {
bundle.putBundle(FIELD_NEW_POSITION_INFO, newPositionInfo.toBundle());
}
if (discontinuityReason != DISCONTINUITY_REASON_DEFAULT) {
bundle.putInt(FIELD_DISCONTINUITY_REASON, discontinuityReason);
}
if (!playbackParameters.equals(PlaybackParameters.DEFAULT)) {
bundle.putBundle(FIELD_PLAYBACK_PARAMETERS, playbackParameters.toBundle());
}
if (repeatMode != Player.REPEAT_MODE_OFF) {
bundle.putInt(FIELD_REPEAT_MODE, repeatMode);
}
if (shuffleModeEnabled) {
bundle.putBoolean(FIELD_SHUFFLE_MODE_ENABLED, shuffleModeEnabled);
}
if (!timeline.equals(Timeline.EMPTY)) {
bundle.putBundle(FIELD_TIMELINE, timeline.toBundle());
}
if (timelineChangeReason != TIMELINE_CHANGE_REASON_DEFAULT) {
bundle.putInt(FIELD_TIMELINE_CHANGE_REASON, timelineChangeReason);
}
if (!videoSize.equals(VideoSize.UNKNOWN)) {
bundle.putBundle(FIELD_VIDEO_SIZE, videoSize.toBundle());
}
if (!playlistMetadata.equals(MediaMetadata.EMPTY)) {
bundle.putBundle(FIELD_PLAYLIST_METADATA, playlistMetadata.toBundle());
}
if (volume != 1) {
bundle.putFloat(FIELD_VOLUME, volume);
}
if (!audioAttributes.equals(AudioAttributes.DEFAULT)) {
bundle.putBundle(FIELD_AUDIO_ATTRIBUTES, audioAttributes.toBundle());
}
if (!cueGroup.equals(CueGroup.EMPTY_TIME_ZERO)) {
bundle.putBundle(FIELD_CUE_GROUP, cueGroup.toBundle());
}
if (!deviceInfo.equals(DeviceInfo.UNKNOWN)) {
bundle.putBundle(FIELD_DEVICE_INFO, deviceInfo.toBundle());
}
if (deviceVolume != 0) {
bundle.putInt(FIELD_DEVICE_VOLUME, deviceVolume);
}
if (deviceMuted) {
bundle.putBoolean(FIELD_DEVICE_MUTED, deviceMuted);
}
if (playWhenReady) {
bundle.putBoolean(FIELD_PLAY_WHEN_READY, playWhenReady);
}
if (playWhenReadyChangeReason != PLAY_WHEN_READY_CHANGE_REASON_DEFAULT) {
bundle.putInt(FIELD_PLAY_WHEN_READY_CHANGE_REASON, playWhenReadyChangeReason);
}
if (playbackSuppressionReason != PLAYBACK_SUPPRESSION_REASON_NONE) {
bundle.putInt(FIELD_PLAYBACK_SUPPRESSION_REASON, playbackSuppressionReason);
}
if (playbackState != STATE_IDLE) {
bundle.putInt(FIELD_PLAYBACK_STATE, playbackState);
}
if (isPlaying) {
bundle.putBoolean(FIELD_IS_PLAYING, isPlaying);
}
if (isLoading) {
bundle.putBoolean(FIELD_IS_LOADING, isLoading);
}
if (!mediaMetadata.equals(MediaMetadata.EMPTY)) {
bundle.putBundle(FIELD_MEDIA_METADATA, mediaMetadata.toBundle());
}
if (seekBackIncrementMs != 0) {
bundle.putLong(FIELD_SEEK_BACK_INCREMENT_MS, seekBackIncrementMs);
}
if (seekForwardIncrementMs != 0) {
bundle.putLong(FIELD_SEEK_FORWARD_INCREMENT_MS, seekForwardIncrementMs);
}
if (maxSeekToPreviousPositionMs != 0) {
bundle.putLong(FIELD_MAX_SEEK_TO_PREVIOUS_POSITION_MS, maxSeekToPreviousPositionMs);
}
if (!currentTracks.equals(Tracks.EMPTY)) {
bundle.putBundle(FIELD_CURRENT_TRACKS, currentTracks.toBundle());
}
if (!trackSelectionParameters.equals(TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT)) {
bundle.putBundle(FIELD_TRACK_SELECTION_PARAMETERS, trackSelectionParameters.toBundle());
}
return bundle;
}
/** Object that can restore {@link PlayerInfo} from a {@link Bundle}. */
@ -911,7 +990,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
PlaybackException playerError =
playerErrorBundle == null ? null : PlaybackException.CREATOR.fromBundle(playerErrorBundle);
int mediaItemTransitionReason =
bundle.getInt(FIELD_MEDIA_ITEM_TRANSITION_REASON, MEDIA_ITEM_TRANSITION_REASON_REPEAT);
bundle.getInt(FIELD_MEDIA_ITEM_TRANSITION_REASON, MEDIA_ITEM_TRANSITION_REASON_DEFAULT);
@Nullable Bundle sessionPositionInfoBundle = bundle.getBundle(FIELD_SESSION_POSITION_INFO);
SessionPositionInfo sessionPositionInfo =
sessionPositionInfoBundle == null
@ -928,7 +1007,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
? SessionPositionInfo.DEFAULT_POSITION_INFO
: PositionInfo.CREATOR.fromBundle(newPositionInfoBundle);
int discontinuityReason =
bundle.getInt(FIELD_DISCONTINUITY_REASON, DISCONTINUITY_REASON_AUTO_TRANSITION);
bundle.getInt(FIELD_DISCONTINUITY_REASON, DISCONTINUITY_REASON_DEFAULT);
@Nullable Bundle playbackParametersBundle = bundle.getBundle(FIELD_PLAYBACK_PARAMETERS);
PlaybackParameters playbackParameters =
playbackParametersBundle == null
@ -974,7 +1053,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
int playWhenReadyChangeReason =
bundle.getInt(
FIELD_PLAY_WHEN_READY_CHANGE_REASON,
/* defaultValue= */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
/* defaultValue= */ PLAY_WHEN_READY_CHANGE_REASON_DEFAULT);
@Player.PlaybackSuppressionReason
int playbackSuppressionReason =
bundle.getInt(

View File

@ -21,6 +21,7 @@ import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.media3.common.Bundleable;
import androidx.media3.common.C;
import androidx.media3.common.Player;
import androidx.media3.common.Player.PositionInfo;
import androidx.media3.common.util.Util;
import com.google.common.base.Objects;
@ -101,9 +102,9 @@ import com.google.common.base.Objects;
return false;
}
SessionPositionInfo other = (SessionPositionInfo) obj;
return positionInfo.equals(other.positionInfo)
return eventTimeMs == other.eventTimeMs
&& positionInfo.equals(other.positionInfo)
&& isPlayingAd == other.isPlayingAd
&& eventTimeMs == other.eventTimeMs
&& durationMs == other.durationMs
&& bufferedPositionMs == other.bufferedPositionMs
&& bufferedPercentage == other.bufferedPercentage
@ -168,30 +169,69 @@ import com.google.common.base.Objects;
private static final String FIELD_CONTENT_DURATION_MS = Util.intToStringMaxRadix(8);
private static final String FIELD_CONTENT_BUFFERED_POSITION_MS = Util.intToStringMaxRadix(9);
@Override
public Bundle toBundle() {
return toBundle(/* canAccessCurrentMediaItem= */ true, /* canAccessTimeline= */ true);
/**
* Returns a copy of this session position info, filtered by the specified available commands.
*
* <p>The filtered fields are reset to their default values.
*
* <p>The return value may be the same object if nothing is filtered.
*
* @param canAccessCurrentMediaItem Whether {@link Player#COMMAND_GET_CURRENT_MEDIA_ITEM} is
* available.
* @param canAccessTimeline Whether {@link Player#COMMAND_GET_TIMELINE} is available.
* @return The filtered session position info.
*/
public SessionPositionInfo filterByAvailableCommands(
boolean canAccessCurrentMediaItem, boolean canAccessTimeline) {
if (canAccessCurrentMediaItem && canAccessTimeline) {
return this;
}
return new SessionPositionInfo(
positionInfo.filterByAvailableCommands(canAccessCurrentMediaItem, canAccessTimeline),
canAccessCurrentMediaItem && isPlayingAd,
eventTimeMs,
canAccessCurrentMediaItem ? durationMs : C.TIME_UNSET,
canAccessCurrentMediaItem ? bufferedPositionMs : 0,
canAccessCurrentMediaItem ? bufferedPercentage : 0,
canAccessCurrentMediaItem ? totalBufferedDurationMs : 0,
canAccessCurrentMediaItem ? currentLiveOffsetMs : C.TIME_UNSET,
canAccessCurrentMediaItem ? contentDurationMs : C.TIME_UNSET,
canAccessCurrentMediaItem ? contentBufferedPositionMs : 0);
}
public Bundle toBundle(boolean canAccessCurrentMediaItem, boolean canAccessTimeline) {
@Override
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putBundle(
FIELD_POSITION_INFO, positionInfo.toBundle(canAccessCurrentMediaItem, canAccessTimeline));
bundle.putBoolean(FIELD_IS_PLAYING_AD, canAccessCurrentMediaItem && isPlayingAd);
bundle.putLong(FIELD_EVENT_TIME_MS, eventTimeMs);
bundle.putLong(FIELD_DURATION_MS, canAccessCurrentMediaItem ? durationMs : C.TIME_UNSET);
bundle.putLong(FIELD_BUFFERED_POSITION_MS, canAccessCurrentMediaItem ? bufferedPositionMs : 0);
bundle.putInt(FIELD_BUFFERED_PERCENTAGE, canAccessCurrentMediaItem ? bufferedPercentage : 0);
bundle.putLong(
FIELD_TOTAL_BUFFERED_DURATION_MS, canAccessCurrentMediaItem ? totalBufferedDurationMs : 0);
bundle.putLong(
FIELD_CURRENT_LIVE_OFFSET_MS,
canAccessCurrentMediaItem ? currentLiveOffsetMs : C.TIME_UNSET);
bundle.putLong(
FIELD_CONTENT_DURATION_MS, canAccessCurrentMediaItem ? contentDurationMs : C.TIME_UNSET);
bundle.putLong(
FIELD_CONTENT_BUFFERED_POSITION_MS,
canAccessCurrentMediaItem ? contentBufferedPositionMs : 0);
if (!DEFAULT_POSITION_INFO.equalsForBundling(positionInfo)) {
bundle.putBundle(FIELD_POSITION_INFO, positionInfo.toBundle());
}
if (isPlayingAd) {
bundle.putBoolean(FIELD_IS_PLAYING_AD, isPlayingAd);
}
if (eventTimeMs != C.TIME_UNSET) {
bundle.putLong(FIELD_EVENT_TIME_MS, eventTimeMs);
}
if (durationMs != C.TIME_UNSET) {
bundle.putLong(FIELD_DURATION_MS, durationMs);
}
if (bufferedPositionMs != 0) {
bundle.putLong(FIELD_BUFFERED_POSITION_MS, bufferedPositionMs);
}
if (bufferedPercentage != 0) {
bundle.putInt(FIELD_BUFFERED_PERCENTAGE, bufferedPercentage);
}
if (totalBufferedDurationMs != 0) {
bundle.putLong(FIELD_TOTAL_BUFFERED_DURATION_MS, totalBufferedDurationMs);
}
if (currentLiveOffsetMs != C.TIME_UNSET) {
bundle.putLong(FIELD_CURRENT_LIVE_OFFSET_MS, currentLiveOffsetMs);
}
if (contentDurationMs != C.TIME_UNSET) {
bundle.putLong(FIELD_CONTENT_DURATION_MS, contentDurationMs);
}
if (contentBufferedPositionMs != 0) {
bundle.putLong(FIELD_CONTENT_BUFFERED_POSITION_MS, contentBufferedPositionMs);
}
return bundle;
}

View File

@ -71,7 +71,7 @@ public class PlayerInfoTest {
}
@Test
public void toBundleFromBundle_withAllCommands_restoresAllData() {
public void toBundleFromBundle_restoresAllData() {
PlayerInfo playerInfo =
new PlayerInfo.Builder(PlayerInfo.DEFAULT)
.setOldPositionInfo(
@ -151,7 +151,7 @@ public class PlayerInfoTest {
new PlaybackException(
/* message= */ null, /* cause= */ null, PlaybackException.ERROR_CODE_TIMEOUT))
.setPlayWhenReady(true)
.setPlayWhenReadyChangeReason(Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
.setPlayWhenReadyChangeReason(Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS)
.setRepeatMode(Player.REPEAT_MODE_ONE)
.setSeekBackIncrement(7000)
.setSeekForwardIncrement(6000)
@ -163,12 +163,7 @@ public class PlayerInfoTest {
.setVideoSize(new VideoSize(/* width= */ 1024, /* height= */ 768))
.build();
PlayerInfo infoAfterBundling =
PlayerInfo.CREATOR.fromBundle(
playerInfo.toBundle(
new Player.Commands.Builder().addAllCommands().build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false));
PlayerInfo infoAfterBundling = PlayerInfo.CREATOR.fromBundle(playerInfo.toBundle());
assertThat(infoAfterBundling.oldPositionInfo.mediaItemIndex).isEqualTo(5);
assertThat(infoAfterBundling.oldPositionInfo.periodIndex).isEqualTo(4);
@ -229,7 +224,7 @@ public class PlayerInfoTest {
.isEqualTo(PlaybackException.ERROR_CODE_TIMEOUT);
assertThat(infoAfterBundling.playWhenReady).isTrue();
assertThat(infoAfterBundling.playWhenReadyChangeReason)
.isEqualTo(Player.PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
.isEqualTo(Player.PLAY_WHEN_READY_CHANGE_REASON_AUDIO_FOCUS_LOSS);
assertThat(infoAfterBundling.repeatMode).isEqualTo(Player.REPEAT_MODE_ONE);
assertThat(infoAfterBundling.seekBackIncrementMs).isEqualTo(7000);
assertThat(infoAfterBundling.seekForwardIncrementMs).isEqualTo(6000);
@ -289,13 +284,15 @@ public class PlayerInfoTest {
PlayerInfo infoAfterBundling =
PlayerInfo.CREATOR.fromBundle(
playerInfo.toBundle(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_CURRENT_MEDIA_ITEM)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false));
playerInfo
.filterByAvailableCommands(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_CURRENT_MEDIA_ITEM)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false)
.toBundle());
assertThat(infoAfterBundling.oldPositionInfo.mediaItemIndex).isEqualTo(5);
assertThat(infoAfterBundling.oldPositionInfo.periodIndex).isEqualTo(4);
@ -408,13 +405,15 @@ public class PlayerInfoTest {
PlayerInfo infoAfterBundling =
PlayerInfo.CREATOR.fromBundle(
playerInfo.toBundle(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_TIMELINE)
.build(),
/* excludeTimeline= */ true,
/* excludeTracks= */ false));
playerInfo
.filterByAvailableCommands(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_TIMELINE)
.build(),
/* excludeTimeline= */ true,
/* excludeTracks= */ false)
.toBundle());
assertThat(infoAfterBundling.oldPositionInfo.mediaItemIndex).isEqualTo(0);
assertThat(infoAfterBundling.oldPositionInfo.periodIndex).isEqualTo(0);
@ -475,13 +474,15 @@ public class PlayerInfoTest {
PlayerInfo infoAfterBundling =
PlayerInfo.CREATOR.fromBundle(
playerInfo.toBundle(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_METADATA)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false));
playerInfo
.filterByAvailableCommands(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_METADATA)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false)
.toBundle());
assertThat(infoAfterBundling.mediaMetadata).isEqualTo(MediaMetadata.EMPTY);
assertThat(infoAfterBundling.playlistMetadata).isEqualTo(MediaMetadata.EMPTY);
@ -493,13 +494,15 @@ public class PlayerInfoTest {
PlayerInfo infoAfterBundling =
PlayerInfo.CREATOR.fromBundle(
playerInfo.toBundle(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_VOLUME)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false));
playerInfo
.filterByAvailableCommands(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_VOLUME)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false)
.toBundle());
assertThat(infoAfterBundling.volume).isEqualTo(1f);
}
@ -511,13 +514,15 @@ public class PlayerInfoTest {
PlayerInfo infoAfterBundling =
PlayerInfo.CREATOR.fromBundle(
playerInfo.toBundle(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_DEVICE_VOLUME)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false));
playerInfo
.filterByAvailableCommands(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_DEVICE_VOLUME)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false)
.toBundle());
assertThat(infoAfterBundling.deviceVolume).isEqualTo(0);
assertThat(infoAfterBundling.deviceMuted).isFalse();
@ -533,13 +538,15 @@ public class PlayerInfoTest {
PlayerInfo infoAfterBundling =
PlayerInfo.CREATOR.fromBundle(
playerInfo.toBundle(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_AUDIO_ATTRIBUTES)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false));
playerInfo
.filterByAvailableCommands(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_AUDIO_ATTRIBUTES)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false)
.toBundle());
assertThat(infoAfterBundling.audioAttributes).isEqualTo(AudioAttributes.DEFAULT);
}
@ -553,13 +560,15 @@ public class PlayerInfoTest {
PlayerInfo infoAfterBundling =
PlayerInfo.CREATOR.fromBundle(
playerInfo.toBundle(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_TEXT)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false));
playerInfo
.filterByAvailableCommands(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_TEXT)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ false)
.toBundle());
assertThat(infoAfterBundling.cueGroup).isEqualTo(CueGroup.EMPTY_TIME_ZERO);
}
@ -581,13 +590,15 @@ public class PlayerInfoTest {
PlayerInfo infoAfterBundling =
PlayerInfo.CREATOR.fromBundle(
playerInfo.toBundle(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_TRACKS)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ true));
playerInfo
.filterByAvailableCommands(
new Player.Commands.Builder()
.addAllCommands()
.remove(Player.COMMAND_GET_TRACKS)
.build(),
/* excludeTimeline= */ false,
/* excludeTracks= */ true)
.toBundle());
assertThat(infoAfterBundling.currentTracks).isEqualTo(Tracks.EMPTY);
}