diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 7ee8eae82d..d781d5f5e4 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -39,6 +39,9 @@
* Testing
* Upgrade Truth dependency from 0.44 to 1.0.
* Upgrade to JUnit 4.13-rc-2.
+* UI
+ * move logic of prev, next, fast forward and rewind to ControlDispatcher
+ [#6926](https://github.com/google/ExoPlayer/issues/6926)).
### 2.11.2 (TBD) ###
diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java
index b06db715e9..0853de4b61 100644
--- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java
+++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/MediaSessionConnector.java
@@ -127,11 +127,6 @@ public final class MediaSessionConnector {
/** The default playback actions. */
@PlaybackActions public static final long DEFAULT_PLAYBACK_ACTIONS = ALL_PLAYBACK_ACTIONS;
- /** The default fast forward increment, in milliseconds. */
- public static final int DEFAULT_FAST_FORWARD_MS = 15000;
- /** The default rewind increment, in milliseconds. */
- public static final int DEFAULT_REWIND_MS = 5000;
-
/**
* The name of the {@link PlaybackStateCompat} float extra with the value of {@link
* PlaybackParameters#speed}.
@@ -440,8 +435,6 @@ public final class MediaSessionConnector {
@Nullable private MediaButtonEventHandler mediaButtonEventHandler;
private long enabledPlaybackActions;
- private int rewindMs;
- private int fastForwardMs;
/**
* Creates an instance.
@@ -461,8 +454,6 @@ public final class MediaSessionConnector {
new DefaultMediaMetadataProvider(
mediaSession.getController(), /* metadataExtrasPrefix= */ null);
enabledPlaybackActions = DEFAULT_PLAYBACK_ACTIONS;
- rewindMs = DEFAULT_REWIND_MS;
- fastForwardMs = DEFAULT_FAST_FORWARD_MS;
mediaSession.setFlags(BASE_MEDIA_SESSION_FLAGS);
mediaSession.setCallback(componentListener, new Handler(looper));
}
@@ -504,13 +495,12 @@ public final class MediaSessionConnector {
/**
* Sets the {@link ControlDispatcher}.
*
- * @param controlDispatcher The {@link ControlDispatcher}, or null to use {@link
- * DefaultControlDispatcher}.
+ * @param controlDispatcher The {@link ControlDispatcher}.
*/
- public void setControlDispatcher(@Nullable ControlDispatcher controlDispatcher) {
+ public void setControlDispatcher(ControlDispatcher controlDispatcher) {
if (this.controlDispatcher != controlDispatcher) {
- this.controlDispatcher =
- controlDispatcher == null ? new DefaultControlDispatcher() : controlDispatcher;
+ this.controlDispatcher = controlDispatcher;
+ invalidateMediaSessionPlaybackState();
}
}
@@ -551,27 +541,27 @@ public final class MediaSessionConnector {
}
/**
- * Sets the rewind increment in milliseconds.
- *
- * @param rewindMs The rewind increment in milliseconds. A non-positive value will cause the
- * rewind button to be disabled.
+ * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} with {@link
+ * DefaultControlDispatcher#DefaultControlDispatcher(long, long)} instead.
*/
+ @SuppressWarnings("deprecation")
+ @Deprecated
public void setRewindIncrementMs(int rewindMs) {
- if (this.rewindMs != rewindMs) {
- this.rewindMs = rewindMs;
+ if (controlDispatcher instanceof DefaultControlDispatcher) {
+ ((DefaultControlDispatcher) controlDispatcher).setRewindIncrementMs(rewindMs);
invalidateMediaSessionPlaybackState();
}
}
/**
- * Sets the fast forward increment in milliseconds.
- *
- * @param fastForwardMs The fast forward increment in milliseconds. A non-positive value will
- * cause the fast forward button to be disabled.
+ * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} with {@link
+ * DefaultControlDispatcher#DefaultControlDispatcher(long, long)} instead.
*/
+ @SuppressWarnings("deprecation")
+ @Deprecated
public void setFastForwardIncrementMs(int fastForwardMs) {
- if (this.fastForwardMs != fastForwardMs) {
- this.fastForwardMs = fastForwardMs;
+ if (controlDispatcher instanceof DefaultControlDispatcher) {
+ ((DefaultControlDispatcher) controlDispatcher).setFastForwardIncrementMs(fastForwardMs);
invalidateMediaSessionPlaybackState();
}
}
@@ -875,8 +865,8 @@ public final class MediaSessionConnector {
Timeline timeline = player.getCurrentTimeline();
if (!timeline.isEmpty() && !player.isPlayingAd()) {
enableSeeking = player.isCurrentWindowSeekable();
- enableRewind = enableSeeking && rewindMs > 0;
- enableFastForward = enableSeeking && fastForwardMs > 0;
+ enableRewind = enableSeeking && controlDispatcher.isRewindEnabled();
+ enableFastForward = enableSeeking && controlDispatcher.isFastForwardEnabled();
enableSetRating = ratingCallback != null;
enableSetCaptioningEnabled = captionCallback != null && captionCallback.hasCaptions(player);
}
@@ -955,28 +945,6 @@ public final class MediaSessionConnector {
return player != null && mediaButtonEventHandler != null;
}
- private void rewind(Player player) {
- if (player.isCurrentWindowSeekable() && rewindMs > 0) {
- seekToOffset(player, /* offsetMs= */ -rewindMs);
- }
- }
-
- private void fastForward(Player player) {
- if (player.isCurrentWindowSeekable() && fastForwardMs > 0) {
- seekToOffset(player, /* offsetMs= */ fastForwardMs);
- }
- }
-
- private void seekToOffset(Player player, long offsetMs) {
- long positionMs = player.getCurrentPosition() + offsetMs;
- long durationMs = player.getDuration();
- if (durationMs != C.TIME_UNSET) {
- positionMs = Math.min(positionMs, durationMs);
- }
- positionMs = Math.max(positionMs, 0);
- seekTo(player, player.getCurrentWindowIndex(), positionMs);
- }
-
private void seekTo(Player player, int windowIndex, long positionMs) {
controlDispatcher.dispatchSeekTo(player, windowIndex, positionMs);
}
@@ -1203,14 +1171,14 @@ public final class MediaSessionConnector {
@Override
public void onFastForward() {
if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_FAST_FORWARD)) {
- fastForward(player);
+ controlDispatcher.dispatchFastForward(player);
}
}
@Override
public void onRewind() {
if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_REWIND)) {
- rewind(player);
+ controlDispatcher.dispatchRewind(player);
}
}
diff --git a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java
index f9d0eca353..024faea209 100644
--- a/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java
+++ b/extensions/mediasession/src/main/java/com/google/android/exoplayer2/ext/mediasession/TimelineQueueNavigator.java
@@ -36,7 +36,6 @@ import java.util.Collections;
*/
public abstract class TimelineQueueNavigator implements MediaSessionConnector.QueueNavigator {
- public static final long MAX_POSITION_FOR_SEEK_TO_PREVIOUS = 3000;
public static final int DEFAULT_MAX_QUEUE_SIZE = 10;
private final MediaSessionCompat mediaSession;
@@ -136,20 +135,7 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu
@Override
public void onSkipToPrevious(Player player, ControlDispatcher controlDispatcher) {
- Timeline timeline = player.getCurrentTimeline();
- if (timeline.isEmpty() || player.isPlayingAd()) {
- return;
- }
- int windowIndex = player.getCurrentWindowIndex();
- timeline.getWindow(windowIndex, window);
- int previousWindowIndex = player.getPreviousWindowIndex();
- if (previousWindowIndex != C.INDEX_UNSET
- && (player.getCurrentPosition() <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS
- || (window.isDynamic && !window.isSeekable))) {
- controlDispatcher.dispatchSeekTo(player, previousWindowIndex, C.TIME_UNSET);
- } else {
- controlDispatcher.dispatchSeekTo(player, windowIndex, 0);
- }
+ controlDispatcher.dispatchPrevious(player);
}
@Override
@@ -166,17 +152,7 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu
@Override
public void onSkipToNext(Player player, ControlDispatcher controlDispatcher) {
- Timeline timeline = player.getCurrentTimeline();
- if (timeline.isEmpty() || player.isPlayingAd()) {
- return;
- }
- int windowIndex = player.getCurrentWindowIndex();
- int nextWindowIndex = player.getNextWindowIndex();
- if (nextWindowIndex != C.INDEX_UNSET) {
- controlDispatcher.dispatchSeekTo(player, nextWindowIndex, C.TIME_UNSET);
- } else if (timeline.getWindow(windowIndex, window).isDynamic) {
- controlDispatcher.dispatchSeekTo(player, windowIndex, C.TIME_UNSET);
- }
+ controlDispatcher.dispatchNext(player);
}
// CommandReceiver implementation.
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ControlDispatcher.java b/library/core/src/main/java/com/google/android/exoplayer2/ControlDispatcher.java
index f8749fc1a8..7b78147e12 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/ControlDispatcher.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/ControlDispatcher.java
@@ -46,6 +46,38 @@ public interface ControlDispatcher {
*/
boolean dispatchSeekTo(Player player, int windowIndex, long positionMs);
+ /**
+ * Dispatches a {@link Player#previous()} operation.
+ *
+ * @param player The {@link Player} to which the operation should be dispatched.
+ * @return True if the operation was dispatched. False if suppressed.
+ */
+ boolean dispatchPrevious(Player player);
+
+ /**
+ * Dispatches a {@link Player#next()} operation.
+ *
+ * @param player The {@link Player} to which the operation should be dispatched.
+ * @return True if the operation was dispatched. False if suppressed.
+ */
+ boolean dispatchNext(Player player);
+
+ /**
+ * Dispatches a rewind operation.
+ *
+ * @param player The {@link Player} to which the operation should be dispatched.
+ * @return True if the operation was dispatched. False if suppressed.
+ */
+ boolean dispatchRewind(Player player);
+
+ /**
+ * Dispatches a fast forward operation.
+ *
+ * @param player The {@link Player} to which the operation should be dispatched.
+ * @return True if the operation was dispatched. False if suppressed.
+ */
+ boolean dispatchFastForward(Player player);
+
/**
* Dispatches a {@link Player#setRepeatMode(int)} operation.
*
@@ -72,4 +104,10 @@ public interface ControlDispatcher {
* @return True if the operation was dispatched. False if suppressed.
*/
boolean dispatchStop(Player player, boolean reset);
+
+ /** Returns {@code true} if rewind is enabled, {@code false} otherwise. */
+ boolean isRewindEnabled();
+
+ /** Returns {@code true} if fast forward is enabled, {@code false} otherwise. */
+ boolean isFastForwardEnabled();
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java b/library/core/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java
index df3ef36b88..4d812d2d9a 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/DefaultControlDispatcher.java
@@ -15,14 +15,40 @@
*/
package com.google.android.exoplayer2;
-import com.google.android.exoplayer2.Player.RepeatMode;
-
-/**
- * Default {@link ControlDispatcher} that dispatches all operations to the player without
- * modification.
- */
+/** Default {@link ControlDispatcher}. */
public class DefaultControlDispatcher implements ControlDispatcher {
+ /** The default fast forward increment, in milliseconds. */
+ public static final int DEFAULT_FAST_FORWARD_MS = 15000;
+ /** The default rewind increment, in milliseconds. */
+ public static final int DEFAULT_REWIND_MS = 5000;
+
+ private static final int MAX_POSITION_FOR_SEEK_TO_PREVIOUS = 3000;
+
+ private final Timeline.Window window;
+
+ private long rewindIncrementMs;
+ private long fastForwardIncrementMs;
+
+ /** Creates an instance. */
+ public DefaultControlDispatcher() {
+ this(DEFAULT_FAST_FORWARD_MS, DEFAULT_REWIND_MS);
+ }
+
+ /**
+ * Creates an instance with the given increments.
+ *
+ * @param fastForwardIncrementMs The fast forward increment in milliseconds. A non-positive value
+ * disables the fast forward operation.
+ * @param rewindIncrementMs The rewind increment in milliseconds. A non-positive value disables
+ * the rewind operation.
+ */
+ public DefaultControlDispatcher(long fastForwardIncrementMs, long rewindIncrementMs) {
+ this.fastForwardIncrementMs = fastForwardIncrementMs;
+ this.rewindIncrementMs = rewindIncrementMs;
+ window = new Timeline.Window();
+ }
+
@Override
public boolean dispatchSetPlayWhenReady(Player player, boolean playWhenReady) {
player.setPlayWhenReady(playWhenReady);
@@ -36,7 +62,58 @@ public class DefaultControlDispatcher implements ControlDispatcher {
}
@Override
- public boolean dispatchSetRepeatMode(Player player, @RepeatMode int repeatMode) {
+ public boolean dispatchPrevious(Player player) {
+ Timeline timeline = player.getCurrentTimeline();
+ if (timeline.isEmpty() || player.isPlayingAd()) {
+ return true;
+ }
+ int windowIndex = player.getCurrentWindowIndex();
+ timeline.getWindow(windowIndex, window);
+ int previousWindowIndex = player.getPreviousWindowIndex();
+ if (previousWindowIndex != C.INDEX_UNSET
+ && (player.getCurrentPosition() <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS
+ || (window.isDynamic && !window.isSeekable))) {
+ player.seekTo(previousWindowIndex, C.TIME_UNSET);
+ } else {
+ player.seekTo(windowIndex, /* positionMs= */ 0);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean dispatchNext(Player player) {
+ Timeline timeline = player.getCurrentTimeline();
+ if (timeline.isEmpty() || player.isPlayingAd()) {
+ return true;
+ }
+ int windowIndex = player.getCurrentWindowIndex();
+ int nextWindowIndex = player.getNextWindowIndex();
+ if (nextWindowIndex != C.INDEX_UNSET) {
+ player.seekTo(nextWindowIndex, C.TIME_UNSET);
+ } else if (timeline.getWindow(windowIndex, window).isLive) {
+ player.seekTo(windowIndex, C.TIME_UNSET);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean dispatchRewind(Player player) {
+ if (isRewindEnabled() && player.isCurrentWindowSeekable()) {
+ seekToOffset(player, -rewindIncrementMs);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean dispatchFastForward(Player player) {
+ if (isFastForwardEnabled() && player.isCurrentWindowSeekable()) {
+ seekToOffset(player, fastForwardIncrementMs);
+ }
+ return true;
+ }
+
+ @Override
+ public boolean dispatchSetRepeatMode(Player player, @Player.RepeatMode int repeatMode) {
player.setRepeatMode(repeatMode);
return true;
}
@@ -52,4 +129,44 @@ public class DefaultControlDispatcher implements ControlDispatcher {
player.stop(reset);
return true;
}
+
+ @Override
+ public boolean isRewindEnabled() {
+ return rewindIncrementMs > 0;
+ }
+
+ @Override
+ public boolean isFastForwardEnabled() {
+ return fastForwardIncrementMs > 0;
+ }
+
+ /**
+ * @deprecated Create a new instance instead and pass the new instance to the UI component. This
+ * makes sure the UI gets updated and is in sync with the new values.
+ */
+ @Deprecated
+ public void setRewindIncrementMs(long rewindMs) {
+ this.rewindIncrementMs = rewindMs;
+ }
+
+ /**
+ * @deprecated Create a new instance instead and pass the new instance to the UI component. This
+ * makes sure the UI gets updated and is in sync with the new values.
+ */
+ @Deprecated
+ public void setFastForwardIncrementMs(long fastForwardMs) {
+ this.fastForwardIncrementMs = fastForwardMs;
+ }
+
+ // Internal methods.
+
+ private static void seekToOffset(Player player, long offsetMs) {
+ long positionMs = player.getCurrentPosition() + offsetMs;
+ long durationMs = player.getDuration();
+ if (durationMs != C.TIME_UNSET) {
+ positionMs = Math.min(positionMs, durationMs);
+ }
+ positionMs = Math.max(positionMs, 0);
+ player.seekTo(player.getCurrentWindowIndex(), positionMs);
+ }
}
diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java
index bfb4e018f0..c7ecfdbf86 100644
--- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java
+++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerControlView.java
@@ -33,6 +33,8 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.ControlDispatcher;
+import com.google.android.exoplayer2.DefaultControlDispatcher;
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
import com.google.android.exoplayer2.PlaybackPreparer;
import com.google.android.exoplayer2.Player;
@@ -67,13 +69,13 @@ import java.util.concurrent.CopyOnWriteArrayList;
*
{@code rewind_increment} - The duration of the rewind applied when the user taps the
* rewind button, in milliseconds. Use zero to disable the rewind button.
*
- * - Corresponding method: {@link #setRewindIncrementMs(int)}
- *
- Default: {@link #DEFAULT_REWIND_MS}
+ *
- Corresponding method: {@link #setControlDispatcher(ControlDispatcher)}
+ *
- Default: {@link DefaultControlDispatcher#DEFAULT_REWIND_MS}
*
* {@code fastforward_increment} - Like {@code rewind_increment}, but for fast forward.
*
- * - Corresponding method: {@link #setFastForwardIncrementMs(int)}
- *
- Default: {@link #DEFAULT_FAST_FORWARD_MS}
+ *
- Corresponding method: {@link #setControlDispatcher(ControlDispatcher)}
+ *
- Default: {@link DefaultControlDispatcher#DEFAULT_FAST_FORWARD_MS}
*
* {@code repeat_toggle_modes} - A flagged enumeration value specifying which repeat
* mode toggle options are enabled. Valid values are: {@code none}, {@code one}, {@code all},
@@ -246,10 +248,6 @@ public class PlayerControlView extends FrameLayout {
void onProgressUpdate(long position, long bufferedPosition);
}
- /** The default fast forward increment, in milliseconds. */
- public static final int DEFAULT_FAST_FORWARD_MS = 15000;
- /** The default rewind increment, in milliseconds. */
- public static final int DEFAULT_REWIND_MS = 5000;
/** The default show timeout, in milliseconds. */
public static final int DEFAULT_SHOW_TIMEOUT_MS = 5000;
/** The default repeat toggle modes. */
@@ -260,7 +258,6 @@ public class PlayerControlView extends FrameLayout {
/** The maximum number of windows that can be shown in a multi-window time bar. */
public static final int MAX_WINDOWS_FOR_MULTI_WINDOW_TIME_BAR = 100;
- private static final long MAX_POSITION_FOR_SEEK_TO_PREVIOUS = 3000;
/** The maximum interval between time bar position updates. */
private static final int MAX_UPDATE_INTERVAL_MS = 1000;
@@ -307,8 +304,6 @@ public class PlayerControlView extends FrameLayout {
private boolean showMultiWindowTimeBar;
private boolean multiWindowTimeBar;
private boolean scrubbing;
- private int rewindMs;
- private int fastForwardMs;
private int showTimeoutMs;
private int timeBarMinUpdateIntervalMs;
private @RepeatModeUtil.RepeatToggleModes int repeatToggleModes;
@@ -344,13 +339,13 @@ public class PlayerControlView extends FrameLayout {
@Nullable AttributeSet playbackAttrs) {
super(context, attrs, defStyleAttr);
int controllerLayoutId = R.layout.exo_player_control_view;
- rewindMs = DEFAULT_REWIND_MS;
- fastForwardMs = DEFAULT_FAST_FORWARD_MS;
showTimeoutMs = DEFAULT_SHOW_TIMEOUT_MS;
repeatToggleModes = DEFAULT_REPEAT_TOGGLE_MODES;
timeBarMinUpdateIntervalMs = DEFAULT_TIME_BAR_MIN_UPDATE_INTERVAL_MS;
hideAtMs = C.TIME_UNSET;
showShuffleButton = false;
+ int rewindMs = DefaultControlDispatcher.DEFAULT_REWIND_MS;
+ int fastForwardMs = DefaultControlDispatcher.DEFAULT_FAST_FORWARD_MS;
if (playbackAttrs != null) {
TypedArray a =
context
@@ -384,7 +379,8 @@ public class PlayerControlView extends FrameLayout {
extraAdGroupTimesMs = new long[0];
extraPlayedAdGroups = new boolean[0];
componentListener = new ComponentListener();
- controlDispatcher = new com.google.android.exoplayer2.DefaultControlDispatcher();
+ controlDispatcher =
+ new com.google.android.exoplayer2.DefaultControlDispatcher(fastForwardMs, rewindMs);
updateProgressAction = this::updateProgress;
hideAction = this::hide;
@@ -589,37 +585,39 @@ public class PlayerControlView extends FrameLayout {
/**
* Sets the {@link com.google.android.exoplayer2.ControlDispatcher}.
*
- * @param controlDispatcher The {@link com.google.android.exoplayer2.ControlDispatcher}, or null
- * to use {@link com.google.android.exoplayer2.DefaultControlDispatcher}.
+ * @param controlDispatcher The {@link com.google.android.exoplayer2.ControlDispatcher}.
*/
- public void setControlDispatcher(
- @Nullable com.google.android.exoplayer2.ControlDispatcher controlDispatcher) {
- this.controlDispatcher =
- controlDispatcher == null
- ? new com.google.android.exoplayer2.DefaultControlDispatcher()
- : controlDispatcher;
+ public void setControlDispatcher(ControlDispatcher controlDispatcher) {
+ if (this.controlDispatcher != controlDispatcher) {
+ this.controlDispatcher = controlDispatcher;
+ updateNavigation();
+ }
}
/**
- * Sets the rewind increment in milliseconds.
- *
- * @param rewindMs The rewind increment in milliseconds. A non-positive value will cause the
- * rewind button to be disabled.
+ * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} with {@link
+ * DefaultControlDispatcher#DefaultControlDispatcher(long, long)}.
*/
+ @SuppressWarnings("deprecation")
+ @Deprecated
public void setRewindIncrementMs(int rewindMs) {
- this.rewindMs = rewindMs;
- updateNavigation();
+ if (controlDispatcher instanceof DefaultControlDispatcher) {
+ ((DefaultControlDispatcher) controlDispatcher).setRewindIncrementMs(rewindMs);
+ updateNavigation();
+ }
}
/**
- * Sets the fast forward increment in milliseconds.
- *
- * @param fastForwardMs The fast forward increment in milliseconds. A non-positive value will
- * cause the fast forward button to be disabled.
+ * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} with {@link
+ * DefaultControlDispatcher#DefaultControlDispatcher(long, long)}.
*/
+ @SuppressWarnings("deprecation")
+ @Deprecated
public void setFastForwardIncrementMs(int fastForwardMs) {
- this.fastForwardMs = fastForwardMs;
- updateNavigation();
+ if (controlDispatcher instanceof DefaultControlDispatcher) {
+ ((DefaultControlDispatcher) controlDispatcher).setFastForwardIncrementMs(fastForwardMs);
+ updateNavigation();
+ }
}
/**
@@ -830,8 +828,8 @@ public class PlayerControlView extends FrameLayout {
boolean isSeekable = window.isSeekable;
enableSeeking = isSeekable;
enablePrevious = isSeekable || !window.isDynamic || player.hasPrevious();
- enableRewind = isSeekable && rewindMs > 0;
- enableFastForward = isSeekable && fastForwardMs > 0;
+ enableRewind = isSeekable && controlDispatcher.isRewindEnabled();
+ enableFastForward = isSeekable && controlDispatcher.isFastForwardEnabled();
enableNext = window.isDynamic || player.hasNext();
}
}
@@ -1042,59 +1040,6 @@ public class PlayerControlView extends FrameLayout {
view.setVisibility(VISIBLE);
}
- private void previous(Player player) {
- Timeline timeline = player.getCurrentTimeline();
- if (timeline.isEmpty() || player.isPlayingAd()) {
- return;
- }
- int windowIndex = player.getCurrentWindowIndex();
- timeline.getWindow(windowIndex, window);
- int previousWindowIndex = player.getPreviousWindowIndex();
- if (previousWindowIndex != C.INDEX_UNSET
- && (player.getCurrentPosition() <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS
- || (window.isDynamic && !window.isSeekable))) {
- seekTo(player, previousWindowIndex, C.TIME_UNSET);
- } else {
- seekTo(player, windowIndex, /* positionMs= */ 0);
- }
- }
-
- private void next(Player player) {
- Timeline timeline = player.getCurrentTimeline();
- if (timeline.isEmpty() || player.isPlayingAd()) {
- return;
- }
- int windowIndex = player.getCurrentWindowIndex();
- int nextWindowIndex = player.getNextWindowIndex();
- if (nextWindowIndex != C.INDEX_UNSET) {
- seekTo(player, nextWindowIndex, C.TIME_UNSET);
- } else if (timeline.getWindow(windowIndex, window).isDynamic) {
- seekTo(player, windowIndex, C.TIME_UNSET);
- }
- }
-
- private void rewind(Player player) {
- if (player.isCurrentWindowSeekable() && rewindMs > 0) {
- seekToOffset(player, -rewindMs);
- }
- }
-
- private void fastForward(Player player) {
- if (player.isCurrentWindowSeekable() && fastForwardMs > 0) {
- seekToOffset(player, fastForwardMs);
- }
- }
-
- private void seekToOffset(Player player, long offsetMs) {
- long positionMs = player.getCurrentPosition() + offsetMs;
- long durationMs = player.getDuration();
- if (durationMs != C.TIME_UNSET) {
- positionMs = Math.min(positionMs, durationMs);
- }
- positionMs = Math.max(positionMs, 0);
- seekTo(player, player.getCurrentWindowIndex(), positionMs);
- }
-
private void seekToTimeBarPosition(Player player, long positionMs) {
int windowIndex;
Timeline timeline = player.getCurrentTimeline();
@@ -1183,9 +1128,9 @@ public class PlayerControlView extends FrameLayout {
}
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
- fastForward(player);
+ controlDispatcher.dispatchFastForward(player);
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_REWIND) {
- rewind(player);
+ controlDispatcher.dispatchRewind(player);
} else if (event.getRepeatCount() == 0) {
switch (keyCode) {
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
@@ -1198,10 +1143,10 @@ public class PlayerControlView extends FrameLayout {
controlDispatcher.dispatchSetPlayWhenReady(player, false);
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
- next(player);
+ controlDispatcher.dispatchNext(player);
break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- previous(player);
+ controlDispatcher.dispatchPrevious(player);
break;
default:
break;
@@ -1317,13 +1262,13 @@ public class PlayerControlView extends FrameLayout {
return;
}
if (nextButton == view) {
- next(player);
+ controlDispatcher.dispatchNext(player);
} else if (previousButton == view) {
- previous(player);
+ controlDispatcher.dispatchPrevious(player);
} else if (fastForwardButton == view) {
- fastForward(player);
+ controlDispatcher.dispatchFastForward(player);
} else if (rewindButton == view) {
- rewind(player);
+ controlDispatcher.dispatchRewind(player);
} else if (playButton == view) {
if (player.getPlaybackState() == Player.STATE_IDLE) {
if (playbackPreparer != null) {
diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java
index c9fb3c4efa..42fcd50c58 100644
--- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java
+++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerNotificationManager.java
@@ -94,14 +94,14 @@ import java.util.Map;
* {@code rewindIncrementMs} - Sets the rewind increment. If set to zero the rewind
* action is not displayed.
*
- * - Corresponding setter: {@link #setRewindIncrementMs(long)}
- *
- Default: {@link #DEFAULT_REWIND_MS} (5000)
+ *
- Corresponding setter: {@link #setControlDispatcher(ControlDispatcher)}
+ *
- Default: {@link DefaultControlDispatcher#DEFAULT_REWIND_MS} (5000)
*
* {@code fastForwardIncrementMs} - Sets the fast forward increment. If set to zero the
* fast forward action is not displayed.
*
- * - Corresponding setter: {@link #setFastForwardIncrementMs(long)}
- *
- Default: {@link #DEFAULT_FAST_FORWARD_MS} (15000)
+ *
- Corresponding setter: {@link #setControlDispatcher(ControlDispatcher)}
+ *
- Default: {@link DefaultControlDispatcher#DEFAULT_FAST_FORWARD_MS} (15000)
*
*
*
@@ -354,13 +354,6 @@ public class PlayerNotificationManager {
})
public @interface Priority {}
- /** The default fast forward increment, in milliseconds. */
- public static final int DEFAULT_FAST_FORWARD_MS = 15000;
- /** The default rewind increment, in milliseconds. */
- public static final int DEFAULT_REWIND_MS = 5000;
-
- private static final long MAX_POSITION_FOR_SEEK_TO_PREVIOUS = 3000;
-
private static int instanceIdCounter;
private final Context context;
@@ -392,8 +385,6 @@ public class PlayerNotificationManager {
private boolean useNavigationActionsInCompactView;
private boolean usePlayPauseActions;
private boolean useStopAction;
- private long fastForwardMs;
- private long rewindMs;
private int badgeIconType;
private boolean colorized;
private int defaults;
@@ -634,8 +625,6 @@ public class PlayerNotificationManager {
smallIconResourceId = R.drawable.exo_notification_small_icon;
defaults = 0;
priority = NotificationCompat.PRIORITY_LOW;
- fastForwardMs = DEFAULT_FAST_FORWARD_MS;
- rewindMs = DEFAULT_REWIND_MS;
badgeIconType = NotificationCompat.BADGE_ICON_SMALL;
visibility = NotificationCompat.VISIBILITY_PUBLIC;
@@ -701,12 +690,13 @@ public class PlayerNotificationManager {
/**
* Sets the {@link ControlDispatcher}.
*
- * @param controlDispatcher The {@link ControlDispatcher}, or null to use {@link
- * DefaultControlDispatcher}.
+ * @param controlDispatcher The {@link ControlDispatcher}.
*/
public final void setControlDispatcher(ControlDispatcher controlDispatcher) {
- this.controlDispatcher =
- controlDispatcher != null ? controlDispatcher : new DefaultControlDispatcher();
+ if (this.controlDispatcher != controlDispatcher) {
+ this.controlDispatcher = controlDispatcher;
+ invalidate();
+ }
}
/**
@@ -725,31 +715,29 @@ public class PlayerNotificationManager {
}
/**
- * Sets the fast forward increment in milliseconds.
- *
- * @param fastForwardMs The fast forward increment in milliseconds. A value of zero will cause the
- * fast forward action to be disabled.
+ * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} with {@link
+ * DefaultControlDispatcher#DefaultControlDispatcher(long, long)}.
*/
+ @SuppressWarnings("deprecation")
+ @Deprecated
public final void setFastForwardIncrementMs(long fastForwardMs) {
- if (this.fastForwardMs == fastForwardMs) {
- return;
+ if (controlDispatcher instanceof DefaultControlDispatcher) {
+ ((DefaultControlDispatcher) controlDispatcher).setFastForwardIncrementMs(fastForwardMs);
+ invalidate();
}
- this.fastForwardMs = fastForwardMs;
- invalidate();
}
/**
- * Sets the rewind increment in milliseconds.
- *
- * @param rewindMs The rewind increment in milliseconds. A value of zero will cause the rewind
- * action to be disabled.
+ * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} with {@link
+ * DefaultControlDispatcher#DefaultControlDispatcher(long, long)}.
*/
+ @SuppressWarnings("deprecation")
+ @Deprecated
public final void setRewindIncrementMs(long rewindMs) {
- if (this.rewindMs == rewindMs) {
- return;
+ if (controlDispatcher instanceof DefaultControlDispatcher) {
+ ((DefaultControlDispatcher) controlDispatcher).setRewindIncrementMs(rewindMs);
+ invalidate();
}
- this.rewindMs = rewindMs;
- invalidate();
}
/**
@@ -1047,6 +1035,7 @@ public class PlayerNotificationManager {
List actions = new ArrayList<>(actionNames.size());
for (int i = 0; i < actionNames.size(); i++) {
String actionName = actionNames.get(i);
+ @Nullable
NotificationCompat.Action action =
playbackActions.containsKey(actionName)
? playbackActions.get(actionName)
@@ -1146,8 +1135,8 @@ public class PlayerNotificationManager {
if (!timeline.isEmpty() && !player.isPlayingAd()) {
timeline.getWindow(player.getCurrentWindowIndex(), window);
enablePrevious = window.isSeekable || !window.isDynamic || player.hasPrevious();
- enableRewind = rewindMs > 0;
- enableFastForward = fastForwardMs > 0;
+ enableRewind = controlDispatcher.isRewindEnabled();
+ enableFastForward = controlDispatcher.isFastForwardEnabled();
enableNext = window.isDynamic || player.hasNext();
}
@@ -1222,63 +1211,6 @@ public class PlayerNotificationManager {
&& player.getPlayWhenReady();
}
- private void previous(Player player) {
- Timeline timeline = player.getCurrentTimeline();
- if (timeline.isEmpty() || player.isPlayingAd()) {
- return;
- }
- int windowIndex = player.getCurrentWindowIndex();
- timeline.getWindow(windowIndex, window);
- int previousWindowIndex = player.getPreviousWindowIndex();
- if (previousWindowIndex != C.INDEX_UNSET
- && (player.getCurrentPosition() <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS
- || (window.isDynamic && !window.isSeekable))) {
- seekTo(player, previousWindowIndex, C.TIME_UNSET);
- } else {
- seekTo(player, windowIndex, /* positionMs= */ 0);
- }
- }
-
- private void next(Player player) {
- Timeline timeline = player.getCurrentTimeline();
- if (timeline.isEmpty() || player.isPlayingAd()) {
- return;
- }
- int windowIndex = player.getCurrentWindowIndex();
- int nextWindowIndex = player.getNextWindowIndex();
- if (nextWindowIndex != C.INDEX_UNSET) {
- seekTo(player, nextWindowIndex, C.TIME_UNSET);
- } else if (timeline.getWindow(windowIndex, window).isDynamic) {
- seekTo(player, windowIndex, C.TIME_UNSET);
- }
- }
-
- private void rewind(Player player) {
- if (player.isCurrentWindowSeekable() && rewindMs > 0) {
- seekToOffset(player, /* offsetMs= */ -rewindMs);
- }
- }
-
- private void fastForward(Player player) {
- if (player.isCurrentWindowSeekable() && fastForwardMs > 0) {
- seekToOffset(player, /* offsetMs= */ fastForwardMs);
- }
- }
-
- private void seekToOffset(Player player, long offsetMs) {
- long positionMs = player.getCurrentPosition() + offsetMs;
- long durationMs = player.getDuration();
- if (durationMs != C.TIME_UNSET) {
- positionMs = Math.min(positionMs, durationMs);
- }
- positionMs = Math.max(positionMs, 0);
- seekTo(player, player.getCurrentWindowIndex(), positionMs);
- }
-
- private void seekTo(Player player, int windowIndex, long positionMs) {
- controlDispatcher.dispatchSeekTo(player, windowIndex, positionMs);
- }
-
private boolean shouldShowPauseButton(Player player) {
return player.getPlaybackState() != Player.STATE_ENDED
&& player.getPlaybackState() != Player.STATE_IDLE
@@ -1438,19 +1370,19 @@ public class PlayerNotificationManager {
playbackPreparer.preparePlayback();
}
} else if (player.getPlaybackState() == Player.STATE_ENDED) {
- seekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET);
+ controlDispatcher.dispatchSeekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET);
}
controlDispatcher.dispatchSetPlayWhenReady(player, /* playWhenReady= */ true);
} else if (ACTION_PAUSE.equals(action)) {
controlDispatcher.dispatchSetPlayWhenReady(player, /* playWhenReady= */ false);
} else if (ACTION_PREVIOUS.equals(action)) {
- previous(player);
+ controlDispatcher.dispatchPrevious(player);
} else if (ACTION_REWIND.equals(action)) {
- rewind(player);
+ controlDispatcher.dispatchRewind(player);
} else if (ACTION_FAST_FORWARD.equals(action)) {
- fastForward(player);
+ controlDispatcher.dispatchFastForward(player);
} else if (ACTION_NEXT.equals(action)) {
- next(player);
+ controlDispatcher.dispatchNext(player);
} else if (ACTION_STOP.equals(action)) {
controlDispatcher.dispatchStop(player, /* reset= */ true);
} else if (ACTION_DISMISS.equals(action)) {
diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java
index 13545fb9fb..8ae9492441 100644
--- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java
+++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java
@@ -965,31 +965,30 @@ public class PlayerView extends FrameLayout implements AdsLoader.AdViewProvider
/**
* Sets the {@link ControlDispatcher}.
*
- * @param controlDispatcher The {@link ControlDispatcher}, or null to use {@link
- * DefaultControlDispatcher}.
+ * @param controlDispatcher The {@link ControlDispatcher}.
*/
- public void setControlDispatcher(@Nullable ControlDispatcher controlDispatcher) {
+ public void setControlDispatcher(ControlDispatcher controlDispatcher) {
Assertions.checkStateNotNull(controller);
controller.setControlDispatcher(controlDispatcher);
}
/**
- * Sets the rewind increment in milliseconds.
- *
- * @param rewindMs The rewind increment in milliseconds. A non-positive value will cause the
- * rewind button to be disabled.
+ * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} with {@link
+ * DefaultControlDispatcher#DefaultControlDispatcher(long, long)}.
*/
+ @SuppressWarnings("deprecation")
+ @Deprecated
public void setRewindIncrementMs(int rewindMs) {
Assertions.checkStateNotNull(controller);
controller.setRewindIncrementMs(rewindMs);
}
/**
- * Sets the fast forward increment in milliseconds.
- *
- * @param fastForwardMs The fast forward increment in milliseconds. A non-positive value will
- * cause the fast forward button to be disabled.
+ * @deprecated Use {@link #setControlDispatcher(ControlDispatcher)} with {@link
+ * DefaultControlDispatcher#DefaultControlDispatcher(long, long)}.
*/
+ @SuppressWarnings("deprecation")
+ @Deprecated
public void setFastForwardIncrementMs(int fastForwardMs) {
Assertions.checkStateNotNull(controller);
controller.setFastForwardIncrementMs(fastForwardMs);