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; return false;
} }
PositionInfo that = (PositionInfo) o; PositionInfo that = (PositionInfo) o;
return mediaItemIndex == that.mediaItemIndex return equalsForBundling(that)
&& periodIndex == that.periodIndex
&& positionMs == that.positionMs
&& contentPositionMs == that.contentPositionMs
&& adGroupIndex == that.adGroupIndex
&& adIndexInAdGroup == that.adIndexInAdGroup
&& Objects.equal(windowUid, that.windowUid) && Objects.equal(windowUid, that.windowUid)
&& Objects.equal(periodUid, that.periodUid) && Objects.equal(periodUid, that.periodUid);
&& Objects.equal(mediaItem, that.mediaItem);
} }
@Override @Override
@ -375,6 +369,21 @@ public interface Player {
adIndexInAdGroup); 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. // Bundleable implementation.
private static final String FIELD_MEDIA_ITEM_INDEX = Util.intToStringMaxRadix(0); 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_GROUP_INDEX = Util.intToStringMaxRadix(5);
private static final String FIELD_AD_INDEX_IN_AD_GROUP = Util.intToStringMaxRadix(6); 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} * {@inheritDoc}
* *
@ -394,31 +433,28 @@ public interface Player {
@UnstableApi @UnstableApi
@Override @Override
public Bundle toBundle() { 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 bundle = new Bundle();
bundle.putInt(FIELD_MEDIA_ITEM_INDEX, canAccessTimeline ? mediaItemIndex : 0); if (mediaItemIndex != 0) {
if (mediaItem != null && canAccessCurrentMediaItem) { bundle.putInt(FIELD_MEDIA_ITEM_INDEX, mediaItemIndex);
}
if (mediaItem != null) {
bundle.putBundle(FIELD_MEDIA_ITEM, mediaItem.toBundle()); bundle.putBundle(FIELD_MEDIA_ITEM, mediaItem.toBundle());
} }
bundle.putInt(FIELD_PERIOD_INDEX, canAccessTimeline ? periodIndex : 0); if (periodIndex != 0) {
bundle.putLong(FIELD_POSITION_MS, canAccessCurrentMediaItem ? positionMs : 0); bundle.putInt(FIELD_PERIOD_INDEX, periodIndex);
bundle.putLong(FIELD_CONTENT_POSITION_MS, canAccessCurrentMediaItem ? contentPositionMs : 0); }
bundle.putInt(FIELD_AD_GROUP_INDEX, canAccessCurrentMediaItem ? adGroupIndex : C.INDEX_UNSET); if (positionMs != 0) {
bundle.putInt( bundle.putLong(FIELD_POSITION_MS, positionMs);
FIELD_AD_INDEX_IN_AD_GROUP, canAccessCurrentMediaItem ? adIndexInAdGroup : C.INDEX_UNSET); }
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; 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 * <p>The method returns the same instance if there is only one window.
* an instance restored by {@link #CREATOR} may have missing fields as described in {@link
* Window#toBundle()} and {@link Period#toBundle()}.
* *
* @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 @UnstableApi
public final Bundle toBundleWithOneWindowOnly(int windowIndex) { public final Timeline copyWithSingleWindow(int windowIndex) {
Window window = getWindow(windowIndex, new Window(), /* defaultPositionProjectionUs= */ 0); if (getWindowCount() == 1) {
return this;
List<Bundle> periodBundles = new ArrayList<>(); }
Period period = new Period(); Window window = getWindow(windowIndex, new Window(), /* defaultPositionProjectionUs= */ 0);
for (int i = window.firstPeriodIndex; i <= window.lastPeriodIndex; i++) { ImmutableList.Builder<Period> periods = ImmutableList.builder();
getPeriod(i, period, /* setIds= */ false); for (int i = window.firstPeriodIndex; i <= window.lastPeriodIndex; i++) {
period.windowIndex = 0; Period period = getPeriod(i, new Period(), /* setIds= */ true);
periodBundles.add(period.toBundle()); period.windowIndex = 0;
periods.add(period);
} }
window.lastPeriodIndex = window.lastPeriodIndex - window.firstPeriodIndex; window.lastPeriodIndex = window.lastPeriodIndex - window.firstPeriodIndex;
window.firstPeriodIndex = 0; window.firstPeriodIndex = 0;
Bundle windowBundle = window.toBundle(); return new RemotableTimeline(
ImmutableList.of(window), periods.build(), /* shuffledWindowIndices= */ new int[] {0});
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;
} }
/** /**

View File

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

View File

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

View File

@ -827,79 +827,158 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
// Next field key = 32 // 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) { Player.Commands availableCommands, boolean excludeTimeline, boolean excludeTracks) {
Bundle bundle = new Bundle(); PlayerInfo.Builder builder = new Builder(this);
boolean canAccessCurrentMediaItem = boolean canAccessCurrentMediaItem =
availableCommands.contains(Player.COMMAND_GET_CURRENT_MEDIA_ITEM); availableCommands.contains(Player.COMMAND_GET_CURRENT_MEDIA_ITEM);
boolean canAccessTimeline = availableCommands.contains(Player.COMMAND_GET_TIMELINE); boolean canAccessTimeline = availableCommands.contains(Player.COMMAND_GET_TIMELINE);
if (playerError != null) { builder.setSessionPositionInfo(
bundle.putBundle(FIELD_PLAYBACK_ERROR, playerError.toBundle()); 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); if (!availableCommands.contains(Player.COMMAND_GET_METADATA)) {
bundle.putBundle( builder.setPlaylistMetadata(MediaMetadata.EMPTY);
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));
} }
bundle.putInt(FIELD_TIMELINE_CHANGE_REASON, timelineChangeReason); if (!availableCommands.contains(Player.COMMAND_GET_VOLUME)) {
bundle.putBundle(FIELD_VIDEO_SIZE, videoSize.toBundle()); builder.setVolume(1);
if (availableCommands.contains(Player.COMMAND_GET_METADATA)) {
bundle.putBundle(FIELD_PLAYLIST_METADATA, playlistMetadata.toBundle());
} }
if (availableCommands.contains(Player.COMMAND_GET_VOLUME)) { if (!availableCommands.contains(Player.COMMAND_GET_AUDIO_ATTRIBUTES)) {
bundle.putFloat(FIELD_VOLUME, volume); builder.setAudioAttributes(AudioAttributes.DEFAULT);
} }
if (availableCommands.contains(Player.COMMAND_GET_AUDIO_ATTRIBUTES)) { if (!availableCommands.contains(Player.COMMAND_GET_TEXT)) {
bundle.putBundle(FIELD_AUDIO_ATTRIBUTES, audioAttributes.toBundle()); builder.setCues(CueGroup.EMPTY_TIME_ZERO);
} }
if (availableCommands.contains(Player.COMMAND_GET_TEXT)) { if (!availableCommands.contains(Player.COMMAND_GET_DEVICE_VOLUME)) {
bundle.putBundle(FIELD_CUE_GROUP, cueGroup.toBundle()); builder.setDeviceVolume(0).setDeviceMuted(false);
} }
bundle.putBundle(FIELD_DEVICE_INFO, deviceInfo.toBundle()); if (!availableCommands.contains(Player.COMMAND_GET_METADATA)) {
if (availableCommands.contains(Player.COMMAND_GET_DEVICE_VOLUME)) { builder.setMediaMetadata(MediaMetadata.EMPTY);
bundle.putInt(FIELD_DEVICE_VOLUME, deviceVolume);
bundle.putBoolean(FIELD_DEVICE_MUTED, deviceMuted);
} }
bundle.putBoolean(FIELD_PLAY_WHEN_READY, playWhenReady); if (excludeTracks || !availableCommands.contains(Player.COMMAND_GET_TRACKS)) {
bundle.putInt(FIELD_PLAYBACK_SUPPRESSION_REASON, playbackSuppressionReason); builder.setCurrentTracks(Tracks.EMPTY);
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());
} }
bundle.putLong(FIELD_SEEK_BACK_INCREMENT_MS, seekBackIncrementMs); return builder.build();
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;
} }
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
return toBundle( Bundle bundle = new Bundle();
/* availableCommands= */ new Player.Commands.Builder().addAllCommands().build(), if (playerError != null) {
/* excludeTimeline= */ false, bundle.putBundle(FIELD_PLAYBACK_ERROR, playerError.toBundle());
/* excludeTracks= */ false); }
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}. */ /** Object that can restore {@link PlayerInfo} from a {@link Bundle}. */
@ -911,7 +990,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
PlaybackException playerError = PlaybackException playerError =
playerErrorBundle == null ? null : PlaybackException.CREATOR.fromBundle(playerErrorBundle); playerErrorBundle == null ? null : PlaybackException.CREATOR.fromBundle(playerErrorBundle);
int mediaItemTransitionReason = 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); @Nullable Bundle sessionPositionInfoBundle = bundle.getBundle(FIELD_SESSION_POSITION_INFO);
SessionPositionInfo sessionPositionInfo = SessionPositionInfo sessionPositionInfo =
sessionPositionInfoBundle == null sessionPositionInfoBundle == null
@ -928,7 +1007,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
? SessionPositionInfo.DEFAULT_POSITION_INFO ? SessionPositionInfo.DEFAULT_POSITION_INFO
: PositionInfo.CREATOR.fromBundle(newPositionInfoBundle); : PositionInfo.CREATOR.fromBundle(newPositionInfoBundle);
int discontinuityReason = 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); @Nullable Bundle playbackParametersBundle = bundle.getBundle(FIELD_PLAYBACK_PARAMETERS);
PlaybackParameters playbackParameters = PlaybackParameters playbackParameters =
playbackParametersBundle == null playbackParametersBundle == null
@ -974,7 +1053,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue;
int playWhenReadyChangeReason = int playWhenReadyChangeReason =
bundle.getInt( bundle.getInt(
FIELD_PLAY_WHEN_READY_CHANGE_REASON, FIELD_PLAY_WHEN_READY_CHANGE_REASON,
/* defaultValue= */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST); /* defaultValue= */ PLAY_WHEN_READY_CHANGE_REASON_DEFAULT);
@Player.PlaybackSuppressionReason @Player.PlaybackSuppressionReason
int playbackSuppressionReason = int playbackSuppressionReason =
bundle.getInt( bundle.getInt(

View File

@ -21,6 +21,7 @@ import android.os.Bundle;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.Bundleable; import androidx.media3.common.Bundleable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Player;
import androidx.media3.common.Player.PositionInfo; import androidx.media3.common.Player.PositionInfo;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import com.google.common.base.Objects; import com.google.common.base.Objects;
@ -101,9 +102,9 @@ import com.google.common.base.Objects;
return false; return false;
} }
SessionPositionInfo other = (SessionPositionInfo) obj; SessionPositionInfo other = (SessionPositionInfo) obj;
return positionInfo.equals(other.positionInfo) return eventTimeMs == other.eventTimeMs
&& positionInfo.equals(other.positionInfo)
&& isPlayingAd == other.isPlayingAd && isPlayingAd == other.isPlayingAd
&& eventTimeMs == other.eventTimeMs
&& durationMs == other.durationMs && durationMs == other.durationMs
&& bufferedPositionMs == other.bufferedPositionMs && bufferedPositionMs == other.bufferedPositionMs
&& bufferedPercentage == other.bufferedPercentage && 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_DURATION_MS = Util.intToStringMaxRadix(8);
private static final String FIELD_CONTENT_BUFFERED_POSITION_MS = Util.intToStringMaxRadix(9); private static final String FIELD_CONTENT_BUFFERED_POSITION_MS = Util.intToStringMaxRadix(9);
@Override /**
public Bundle toBundle() { * Returns a copy of this session position info, filtered by the specified available commands.
return toBundle(/* canAccessCurrentMediaItem= */ true, /* canAccessTimeline= */ true); *
* <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 bundle = new Bundle();
bundle.putBundle( if (!DEFAULT_POSITION_INFO.equalsForBundling(positionInfo)) {
FIELD_POSITION_INFO, positionInfo.toBundle(canAccessCurrentMediaItem, canAccessTimeline)); bundle.putBundle(FIELD_POSITION_INFO, positionInfo.toBundle());
bundle.putBoolean(FIELD_IS_PLAYING_AD, canAccessCurrentMediaItem && isPlayingAd); }
bundle.putLong(FIELD_EVENT_TIME_MS, eventTimeMs); if (isPlayingAd) {
bundle.putLong(FIELD_DURATION_MS, canAccessCurrentMediaItem ? durationMs : C.TIME_UNSET); bundle.putBoolean(FIELD_IS_PLAYING_AD, isPlayingAd);
bundle.putLong(FIELD_BUFFERED_POSITION_MS, canAccessCurrentMediaItem ? bufferedPositionMs : 0); }
bundle.putInt(FIELD_BUFFERED_PERCENTAGE, canAccessCurrentMediaItem ? bufferedPercentage : 0); if (eventTimeMs != C.TIME_UNSET) {
bundle.putLong( bundle.putLong(FIELD_EVENT_TIME_MS, eventTimeMs);
FIELD_TOTAL_BUFFERED_DURATION_MS, canAccessCurrentMediaItem ? totalBufferedDurationMs : 0); }
bundle.putLong( if (durationMs != C.TIME_UNSET) {
FIELD_CURRENT_LIVE_OFFSET_MS, bundle.putLong(FIELD_DURATION_MS, durationMs);
canAccessCurrentMediaItem ? currentLiveOffsetMs : C.TIME_UNSET); }
bundle.putLong( if (bufferedPositionMs != 0) {
FIELD_CONTENT_DURATION_MS, canAccessCurrentMediaItem ? contentDurationMs : C.TIME_UNSET); bundle.putLong(FIELD_BUFFERED_POSITION_MS, bufferedPositionMs);
bundle.putLong( }
FIELD_CONTENT_BUFFERED_POSITION_MS, if (bufferedPercentage != 0) {
canAccessCurrentMediaItem ? contentBufferedPositionMs : 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; return bundle;
} }

View File

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