diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 93bdd43a99..19abe55582 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -2,6 +2,10 @@ ### Unreleased changes +* Core library: + * Add `Player.replaceMediaItem(s)` as a shortcut to adding and removing + items at the same position + ([#8046](https://github.com/google/ExoPlayer/issues/8046)). * Session: * Add `androidx.media3.session.MediaButtonReceiver` to enable apps to implement playback resumption with media button events sent by, for diff --git a/api.txt b/api.txt index 14a72e7596..d6dc7db144 100644 --- a/api.txt +++ b/api.txt @@ -751,6 +751,8 @@ package androidx.media3.common { method public void removeListener(androidx.media3.common.Player.Listener); method public void removeMediaItem(int); method public void removeMediaItems(int, int); + method public default void replaceMediaItem(int, androidx.media3.common.MediaItem); + method public default void replaceMediaItems(int, int, java.util.List); method public void seekBack(); method public void seekForward(); method public void seekTo(long); diff --git a/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java b/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java index 9695c998b7..d2162e5611 100644 --- a/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java +++ b/libraries/common/src/main/java/androidx/media3/common/ForwardingPlayer.java @@ -147,6 +147,18 @@ public class ForwardingPlayer implements Player { player.moveMediaItems(fromIndex, toIndex, newIndex); } + /** Calls {@link Player#replaceMediaItem(int, MediaItem)} on the delegate. */ + @Override + public void replaceMediaItem(int index, MediaItem mediaItem) { + player.replaceMediaItem(index, mediaItem); + } + + /** Calls {@link Player#replaceMediaItems(int, int, List)} on the delegate. */ + @Override + public void replaceMediaItems(int fromIndex, int toIndex, List mediaItems) { + player.replaceMediaItems(fromIndex, toIndex, mediaItems); + } + /** Calls {@link Player#removeMediaItem(int)} on the delegate. */ @Override public void removeMediaItem(int index) { diff --git a/libraries/common/src/main/java/androidx/media3/common/Player.java b/libraries/common/src/main/java/androidx/media3/common/Player.java index 9875690658..8d8e440175 100644 --- a/libraries/common/src/main/java/androidx/media3/common/Player.java +++ b/libraries/common/src/main/java/androidx/media3/common/Player.java @@ -37,6 +37,7 @@ import androidx.media3.common.util.Size; import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.Util; import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.lang.annotation.Documented; import java.lang.annotation.Retention; @@ -1754,6 +1755,8 @@ public interface Player { *
  • {@link #setMediaItems(List)} *
  • {@link #setMediaItems(List, boolean)} *
  • {@link #setMediaItems(List, int, long)} + *
  • {@link #replaceMediaItem(int, MediaItem)} + *
  • {@link #replaceMediaItems(int, int, List)} * */ int COMMAND_CHANGE_MEDIA_ITEMS = 20; @@ -2055,6 +2058,38 @@ public interface Player { */ void moveMediaItems(int fromIndex, int toIndex, int newIndex); + /** + * Replaces the media item at the given index of the playlist. + * + *

    This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain + * #getAvailableCommands() available}. + * + * @param index The index at which to replace the media item. If the index is larger than the size + * of the playlist, the request is ignored. + * @param mediaItem The new {@link MediaItem}. + */ + default void replaceMediaItem(int index, MediaItem mediaItem) { + replaceMediaItems( + /* fromIndex= */ index, /* toIndex= */ index + 1, ImmutableList.of(mediaItem)); + } + + /** + * Replaces the media items at the given range of the playlist. + * + *

    This method must only be called if {@link #COMMAND_CHANGE_MEDIA_ITEMS} is {@linkplain + * #getAvailableCommands() available}. + * + * @param fromIndex The start of the range. If the index is larger than the size of the playlist, + * the request is ignored. + * @param toIndex The first item not to be included in the range (exclusive). If the index is + * larger than the size of the playlist, items up to the end of the playlist are replaced. + * @param mediaItems The {@linkplain MediaItem media items} to replace the range with. + */ + default void replaceMediaItems(int fromIndex, int toIndex, List mediaItems) { + addMediaItems(toIndex, mediaItems); + removeMediaItems(fromIndex, toIndex); + } + /** * Removes the media item at the given index of the playlist. * diff --git a/libraries/common/src/main/java/androidx/media3/common/SimpleBasePlayer.java b/libraries/common/src/main/java/androidx/media3/common/SimpleBasePlayer.java index 63ec4f7dc5..a7bde0bc87 100644 --- a/libraries/common/src/main/java/androidx/media3/common/SimpleBasePlayer.java +++ b/libraries/common/src/main/java/androidx/media3/common/SimpleBasePlayer.java @@ -2141,6 +2141,18 @@ public abstract class SimpleBasePlayer extends BasePlayer { }); } + @Override + public final void replaceMediaItem(int index, MediaItem mediaItem) { + replaceMediaItems( + /* fromIndex= */ index, /* toIndex= */ index + 1, ImmutableList.of(mediaItem)); + } + + @Override + public final void replaceMediaItems(int fromIndex, int toIndex, List mediaItems) { + addMediaItems(toIndex, mediaItems); + removeMediaItems(fromIndex, toIndex); + } + @Override public final void removeMediaItems(int fromIndex, int toIndex) { verifyApplicationThreadAndInitState();