Commit c4e99902 by kimvde Committed by kim-vde

Add seekToPrevious method to Player

PiperOrigin-RevId: 383623440
parent d9618b51
......@@ -4,7 +4,7 @@
* Core Library:
* Add `needsReconfiguration` API to the `MediaCodecAdapter` interface.
* Add `seekForward` and `seekBack` methods to `Player`.
* Add `seekForward`, `seekBack` and `seekToPrevious` methods to `Player`.
* Make `Player` depend on the new `PlaybackException` class instead of
`ExoPlaybackException`:
* `Player.getPlayerError` now returns a `PlaybackException`.
......
......@@ -145,6 +145,24 @@ public abstract class BasePlayer implements Player {
}
@Override
public final void seekToPrevious() {
Timeline timeline = getCurrentTimeline();
if (timeline.isEmpty() || isPlayingAd()) {
return;
}
boolean hasPrevious = hasPrevious();
if (isCurrentWindowLive() && !isCurrentWindowSeekable()) {
if (hasPrevious) {
previous();
}
} else if (hasPrevious && getCurrentPosition() <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS_MS) {
previous();
} else {
seekTo(/* positionMs= */ 0);
}
}
@Override
public final boolean hasNext() {
return getNextWindowIndex() != C.INDEX_UNSET;
}
......
......@@ -278,6 +278,11 @@ public class ForwardingPlayer implements Player {
}
@Override
public void seekToPrevious() {
player.seekToPrevious();
}
@Override
public boolean hasNext() {
return player.hasNext();
}
......
......@@ -884,6 +884,9 @@ public interface Player {
default void onMetadata(Metadata metadata) {}
}
/** The maximum position for which {@link #seekToPrevious()} seeks to the previous window. */
int MAX_POSITION_FOR_SEEK_TO_PREVIOUS_MS = 3000;
/**
* Playback state. One of {@link #STATE_IDLE}, {@link #STATE_BUFFERING}, {@link #STATE_READY} or
* {@link #STATE_ENDED}.
......@@ -1654,6 +1657,27 @@ public interface Player {
void previous();
/**
* Seeks to an earlier position in the current or previous window (if available). More precisely:
*
* <ul>
* <li>If the timeline is empty or seeking is not possible, does nothing.
* <li>Otherwise, if the current window is {@link #isCurrentWindowLive() live} and {@link
* #isCurrentWindowSeekable() unseekable}, then:
* <ul>
* <li>If {@link #hasPrevious() a previous window exists}, seeks to the default position
* of the previous window.
* <li>Otherwise, does nothing.
* </ul>
* <li>Otherwise, if {@link #hasPrevious() a previous window exists} and the {@link
* #getCurrentPosition() current position} is less than {@link
* #MAX_POSITION_FOR_SEEK_TO_PREVIOUS_MS}, seeks to the default position of the previous
* window.
* <li>Otherwise, seeks to 0 in the current window.
* </ul>
*/
void seekToPrevious();
/**
* Returns whether a next window exists, which may depend on the current repeat mode and whether
* shuffle mode is enabled.
*
......
......@@ -40,6 +40,7 @@ import static com.google.android.exoplayer2.Player.COMMAND_SET_SHUFFLE_MODE;
import static com.google.android.exoplayer2.Player.COMMAND_SET_SPEED_AND_PITCH;
import static com.google.android.exoplayer2.Player.COMMAND_SET_VIDEO_SURFACE;
import static com.google.android.exoplayer2.Player.COMMAND_SET_VOLUME;
import static com.google.android.exoplayer2.Player.MAX_POSITION_FOR_SEEK_TO_PREVIOUS_MS;
import static com.google.android.exoplayer2.Player.STATE_ENDED;
import static com.google.android.exoplayer2.robolectric.RobolectricUtil.runMainLooperUntil;
import static com.google.android.exoplayer2.robolectric.TestPlayerRunHelper.playUntilPosition;
......@@ -10521,6 +10522,30 @@ public final class ExoPlayerTest {
}
@Test
public void seekToPrevious_closeToStart_seeksToPreviousWindow() {
ExoPlayer player = new TestExoPlayerBuilder(context).build();
player.addMediaSources(ImmutableList.of(new FakeMediaSource(), new FakeMediaSource()));
player.seekTo(/* windowIndex= */ 1, /* positionMs= */ MAX_POSITION_FOR_SEEK_TO_PREVIOUS_MS);
player.seekToPrevious();
assertThat(player.getCurrentWindowIndex()).isEqualTo(0);
assertThat(player.getCurrentPosition()).isEqualTo(0);
}
@Test
public void seekToPrevious_notCloseToStart_seeksToZero() {
ExoPlayer player = new TestExoPlayerBuilder(context).build();
player.addMediaSources(ImmutableList.of(new FakeMediaSource(), new FakeMediaSource()));
player.seekTo(/* windowIndex= */ 1, /* positionMs= */ MAX_POSITION_FOR_SEEK_TO_PREVIOUS_MS + 1);
player.seekToPrevious();
assertThat(player.getCurrentWindowIndex()).isEqualTo(1);
assertThat(player.getCurrentPosition()).isEqualTo(0);
}
@Test
public void stop_doesNotCallOnPositionDiscontinuity() throws Exception {
ExoPlayer player = new TestExoPlayerBuilder(context).build();
Player.Listener listener = mock(Player.Listener.class);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment