diff --git a/RELEASENOTES.md b/RELEASENOTES.md index a67de32fea..194a49db88 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -2,11 +2,14 @@ ### 2.9.1 ### +* Add convenience methods `Player.next`, `Player.previous`, `Player.hasNext` + and `Player.hasPrevious` + ([#4863](https://github.com/google/ExoPlayer/issues/4863)). * Improve initial bandwidth meter estimates using the current country and network type. * IMA extension: - * For preroll to live stream transitions, project forward the - loading position to avoid being behind the live window. + * For preroll to live stream transitions, project forward the loading position + to avoid being behind the live window. * Let apps specify whether to focus the skip button on ATV ([#5019](https://github.com/google/ExoPlayer/issues/5019)). * MP3: diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java index 6cf6309796..1573401521 100644 --- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java +++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java @@ -365,6 +365,32 @@ public final class CastPlayer extends BasePlayer { } } + @Override + public boolean hasPrevious() { + return getPreviousWindowIndex() != C.INDEX_UNSET; + } + + @Override + public void previous() { + int previousWindowIndex = getPreviousWindowIndex(); + if (previousWindowIndex != C.INDEX_UNSET) { + seekToDefaultPosition(previousWindowIndex); + } + } + + @Override + public boolean hasNext() { + return getNextWindowIndex() != C.INDEX_UNSET; + } + + @Override + public void next() { + int nextWindowIndex = getPreviousWindowIndex(); + if (nextWindowIndex != C.INDEX_UNSET) { + seekToDefaultPosition(nextWindowIndex); + } + } + @Override public void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters) { // Unsupported by the RemoteMediaClient API. Do nothing. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index ffdadb78f7..fb27452f89 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -329,6 +329,32 @@ import java.util.concurrent.CopyOnWriteArraySet; } } + @Override + public boolean hasPrevious() { + return getPreviousWindowIndex() != C.INDEX_UNSET; + } + + @Override + public void previous() { + int previousWindowIndex = getPreviousWindowIndex(); + if (previousWindowIndex != C.INDEX_UNSET) { + seekToDefaultPosition(previousWindowIndex); + } + } + + @Override + public boolean hasNext() { + return getNextWindowIndex() != C.INDEX_UNSET; + } + + @Override + public void next() { + int nextWindowIndex = getPreviousWindowIndex(); + if (nextWindowIndex != C.INDEX_UNSET) { + seekToDefaultPosition(nextWindowIndex); + } + } + @Override public void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters) { if (playbackParameters == null) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/Player.java b/library/core/src/main/java/com/google/android/exoplayer2/Player.java index 83014c6b10..16f8aa2878 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/Player.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/Player.java @@ -659,6 +659,32 @@ public interface Player { */ void seekTo(int windowIndex, long positionMs); + /** + * Returns whether a previous window exists, which may depend on the current repeat mode and + * whether shuffle mode is enabled. + */ + boolean hasPrevious(); + + /** + * Seeks to the default position of the previous window in the timeline, which may depend on the + * current repeat mode and whether shuffle mode is enabled. Does nothing if {@link #hasPrevious()} + * is {@code false}. + */ + void previous(); + + /** + * Returns whether a next window exists, which may depend on the current repeat mode and whether + * shuffle mode is enabled. + */ + boolean hasNext(); + + /** + * Seeks to the default position of the next window in the timeline, which may depend on the + * current repeat mode and whether shuffle mode is enabled. Does nothing if {@link #hasNext()} is + * {@code false}. + */ + void next(); + /** * Attempts to set the playback parameters. Passing {@code null} sets the parameters to the * default, {@link PlaybackParameters#DEFAULT}, which means there is no speed or pitch adjustment. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 8517556887..36fd0868f9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -934,6 +934,36 @@ public class SimpleExoPlayer extends BasePlayer player.seekTo(windowIndex, positionMs); } + @Override + public boolean hasPrevious() { + verifyApplicationThread(); + return getPreviousWindowIndex() != C.INDEX_UNSET; + } + + @Override + public void previous() { + verifyApplicationThread(); + if (hasPrevious()) { + analyticsCollector.notifySeekStarted(); + player.previous(); + } + } + + @Override + public boolean hasNext() { + verifyApplicationThread(); + return getNextWindowIndex() != C.INDEX_UNSET; + } + + @Override + public void next() { + verifyApplicationThread(); + if (hasNext()) { + analyticsCollector.notifySeekStarted(); + player.next(); + } + } + @Override public void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters) { verifyApplicationThread(); diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java index 156b573df8..d1236a7a2e 100644 --- a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java +++ b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java @@ -134,6 +134,26 @@ public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer { throw new UnsupportedOperationException(); } + @Override + public boolean hasPrevious() { + throw new UnsupportedOperationException(); + } + + @Override + public void previous() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasNext() { + throw new UnsupportedOperationException(); + } + + @Override + public void next() { + throw new UnsupportedOperationException(); + } + @Override public void setPlaybackParameters(PlaybackParameters playbackParameters) { throw new UnsupportedOperationException();