Align navigation implementation across UI components
This change also paves the way for splitting out functionality into a utility class. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=221070262
This commit is contained in:
parent
7508219416
commit
eb6859e436
@ -212,7 +212,7 @@ public final class MediaSessionConnector {
|
|||||||
* @param player The player connected to the media session.
|
* @param player The player connected to the media session.
|
||||||
* @return The bitmask of the supported media actions.
|
* @return The bitmask of the supported media actions.
|
||||||
*/
|
*/
|
||||||
long getSupportedQueueNavigatorActions(@Nullable Player player);
|
long getSupportedQueueNavigatorActions(Player player);
|
||||||
/**
|
/**
|
||||||
* Called when the timeline of the player has changed.
|
* Called when the timeline of the player has changed.
|
||||||
*
|
*
|
||||||
@ -586,7 +586,7 @@ public final class MediaSessionConnector {
|
|||||||
public final void invalidateMediaSessionPlaybackState() {
|
public final void invalidateMediaSessionPlaybackState() {
|
||||||
PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder();
|
PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder();
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
builder.setActions(buildPlaybackActions()).setState(PlaybackStateCompat.STATE_NONE, 0, 0, 0);
|
builder.setActions(/* capabilities= */ 0).setState(PlaybackStateCompat.STATE_NONE, 0, 0, 0);
|
||||||
mediaSession.setPlaybackState(builder.build());
|
mediaSession.setPlaybackState(builder.build());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -622,7 +622,7 @@ public final class MediaSessionConnector {
|
|||||||
Bundle extras = new Bundle();
|
Bundle extras = new Bundle();
|
||||||
extras.putFloat(EXTRAS_PITCH, player.getPlaybackParameters().pitch);
|
extras.putFloat(EXTRAS_PITCH, player.getPlaybackParameters().pitch);
|
||||||
builder
|
builder
|
||||||
.setActions(buildPlaybackActions())
|
.setActions(buildPlaybackActions(player))
|
||||||
.setActiveQueueItemId(activeQueueItemId)
|
.setActiveQueueItemId(activeQueueItemId)
|
||||||
.setBufferedPosition(player.getBufferedPosition())
|
.setBufferedPosition(player.getBufferedPosition())
|
||||||
.setState(
|
.setState(
|
||||||
@ -657,21 +657,32 @@ public final class MediaSessionConnector {
|
|||||||
commandReceivers.remove(commandReceiver);
|
commandReceivers.remove(commandReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
private long buildPlaybackActions() {
|
private long buildPlaybackActions(Player player) {
|
||||||
long actions = 0;
|
boolean enableSeeking = false;
|
||||||
if (player != null && !player.getCurrentTimeline().isEmpty()) {
|
boolean enableRewind = false;
|
||||||
long playbackActions = BASE_PLAYBACK_ACTIONS;
|
boolean enableFastForward = false;
|
||||||
if (player.isCurrentWindowSeekable()) {
|
boolean enableSetRating = false;
|
||||||
playbackActions |= PlaybackStateCompat.ACTION_SEEK_TO;
|
Timeline timeline = player.getCurrentTimeline();
|
||||||
if (fastForwardMs > 0) {
|
if (!timeline.isEmpty() && !player.isPlayingAd()) {
|
||||||
playbackActions |= PlaybackStateCompat.ACTION_FAST_FORWARD;
|
enableSeeking = player.isCurrentWindowSeekable();
|
||||||
}
|
enableRewind = enableSeeking && rewindMs > 0;
|
||||||
if (rewindMs > 0) {
|
enableFastForward = enableSeeking && fastForwardMs > 0;
|
||||||
playbackActions |= PlaybackStateCompat.ACTION_REWIND;
|
enableSetRating = true;
|
||||||
}
|
|
||||||
}
|
|
||||||
actions |= (playbackActions & enabledPlaybackActions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long playbackActions = BASE_PLAYBACK_ACTIONS;
|
||||||
|
if (enableSeeking) {
|
||||||
|
playbackActions |= PlaybackStateCompat.ACTION_SEEK_TO;
|
||||||
|
}
|
||||||
|
if (enableFastForward) {
|
||||||
|
playbackActions |= PlaybackStateCompat.ACTION_FAST_FORWARD;
|
||||||
|
}
|
||||||
|
if (enableRewind) {
|
||||||
|
playbackActions |= PlaybackStateCompat.ACTION_REWIND;
|
||||||
|
}
|
||||||
|
playbackActions &= enabledPlaybackActions;
|
||||||
|
|
||||||
|
long actions = playbackActions;
|
||||||
if (playbackPreparer != null) {
|
if (playbackPreparer != null) {
|
||||||
actions |= (PlaybackPreparer.ACTIONS & playbackPreparer.getSupportedPrepareActions());
|
actions |= (PlaybackPreparer.ACTIONS & playbackPreparer.getSupportedPrepareActions());
|
||||||
}
|
}
|
||||||
@ -679,7 +690,7 @@ public final class MediaSessionConnector {
|
|||||||
actions |=
|
actions |=
|
||||||
(QueueNavigator.ACTIONS & queueNavigator.getSupportedQueueNavigatorActions(player));
|
(QueueNavigator.ACTIONS & queueNavigator.getSupportedQueueNavigatorActions(player));
|
||||||
}
|
}
|
||||||
if (ratingCallback != null) {
|
if (ratingCallback != null && enableSetRating) {
|
||||||
actions |= PlaybackStateCompat.ACTION_SET_RATING;
|
actions |= PlaybackStateCompat.ACTION_SET_RATING;
|
||||||
}
|
}
|
||||||
return actions;
|
return actions;
|
||||||
@ -699,39 +710,46 @@ public final class MediaSessionConnector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean canDispatchPlaybackAction(long action) {
|
private boolean canDispatchPlaybackAction(long action) {
|
||||||
return (enabledPlaybackActions & action) != 0;
|
return player != null && (enabledPlaybackActions & action) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canDispatchToPlaybackPreparer(long action) {
|
private boolean canDispatchToPlaybackPreparer(long action) {
|
||||||
return playbackPreparer != null
|
return player != null
|
||||||
&& (playbackPreparer.getSupportedPrepareActions() & PlaybackPreparer.ACTIONS & action) != 0;
|
&& playbackPreparer != null
|
||||||
|
&& (playbackPreparer.getSupportedPrepareActions() & action) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canDispatchToQueueNavigator(long action) {
|
private boolean canDispatchToQueueNavigator(long action) {
|
||||||
return queueNavigator != null
|
return player != null
|
||||||
&& (queueNavigator.getSupportedQueueNavigatorActions(player)
|
&& queueNavigator != null
|
||||||
& QueueNavigator.ACTIONS
|
&& (queueNavigator.getSupportedQueueNavigatorActions(player) & action) != 0;
|
||||||
& action)
|
|
||||||
!= 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rewind() {
|
private boolean canDispatchSetRating() {
|
||||||
if (rewindMs > 0) {
|
return player != null && ratingCallback != null;
|
||||||
seekTo(player.getCurrentPosition() - rewindMs);
|
}
|
||||||
|
|
||||||
|
private boolean canDispatchQueueEdit() {
|
||||||
|
return player != null && queueEditor != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rewind(Player player) {
|
||||||
|
if (player.isCurrentWindowSeekable() && rewindMs > 0) {
|
||||||
|
seekTo(player, player.getCurrentPosition() - rewindMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fastForward() {
|
private void fastForward(Player player) {
|
||||||
if (fastForwardMs > 0) {
|
if (player.isCurrentWindowSeekable() && fastForwardMs > 0) {
|
||||||
seekTo(player.getCurrentPosition() + fastForwardMs);
|
seekTo(player, player.getCurrentPosition() + fastForwardMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void seekTo(long positionMs) {
|
private void seekTo(Player player, long positionMs) {
|
||||||
seekTo(player.getCurrentWindowIndex(), positionMs);
|
seekTo(player, player.getCurrentWindowIndex(), positionMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void seekTo(int windowIndex, long positionMs) {
|
private void seekTo(Player player, int windowIndex, long positionMs) {
|
||||||
long durationMs = player.getDuration();
|
long durationMs = player.getDuration();
|
||||||
if (durationMs != C.TIME_UNSET) {
|
if (durationMs != C.TIME_UNSET) {
|
||||||
positionMs = Math.min(positionMs, durationMs);
|
positionMs = Math.min(positionMs, durationMs);
|
||||||
@ -930,21 +948,21 @@ public final class MediaSessionConnector {
|
|||||||
@Override
|
@Override
|
||||||
public void onSeekTo(long positionMs) {
|
public void onSeekTo(long positionMs) {
|
||||||
if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_SEEK_TO)) {
|
if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_SEEK_TO)) {
|
||||||
seekTo(positionMs);
|
seekTo(player, positionMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFastForward() {
|
public void onFastForward() {
|
||||||
if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_FAST_FORWARD)) {
|
if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_FAST_FORWARD)) {
|
||||||
fastForward();
|
fastForward(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRewind() {
|
public void onRewind() {
|
||||||
if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_REWIND)) {
|
if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_REWIND)) {
|
||||||
rewind();
|
rewind(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1008,7 +1026,7 @@ public final class MediaSessionConnector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
|
public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
|
||||||
if (customActionMap.containsKey(action)) {
|
if (player != null && customActionMap.containsKey(action)) {
|
||||||
customActionMap.get(action).onCustomAction(player, controlDispatcher, action, extras);
|
customActionMap.get(action).onCustomAction(player, controlDispatcher, action, extras);
|
||||||
invalidateMediaSessionPlaybackState();
|
invalidateMediaSessionPlaybackState();
|
||||||
}
|
}
|
||||||
@ -1016,9 +1034,11 @@ public final class MediaSessionConnector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCommand(String command, Bundle extras, ResultReceiver cb) {
|
public void onCommand(String command, Bundle extras, ResultReceiver cb) {
|
||||||
for (int i = 0; i < commandReceivers.size(); i++) {
|
if (player != null) {
|
||||||
if (commandReceivers.get(i).onCommand(player, controlDispatcher, command, extras, cb)) {
|
for (int i = 0; i < commandReceivers.size(); i++) {
|
||||||
return;
|
if (commandReceivers.get(i).onCommand(player, controlDispatcher, command, extras, cb)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1088,35 +1108,35 @@ public final class MediaSessionConnector {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSetRating(RatingCompat rating) {
|
public void onSetRating(RatingCompat rating) {
|
||||||
if (ratingCallback != null) {
|
if (canDispatchSetRating()) {
|
||||||
ratingCallback.onSetRating(player, rating);
|
ratingCallback.onSetRating(player, rating);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSetRating(RatingCompat rating, Bundle extras) {
|
public void onSetRating(RatingCompat rating, Bundle extras) {
|
||||||
if (ratingCallback != null) {
|
if (canDispatchSetRating()) {
|
||||||
ratingCallback.onSetRating(player, rating, extras);
|
ratingCallback.onSetRating(player, rating, extras);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAddQueueItem(MediaDescriptionCompat description) {
|
public void onAddQueueItem(MediaDescriptionCompat description) {
|
||||||
if (queueEditor != null) {
|
if (canDispatchQueueEdit()) {
|
||||||
queueEditor.onAddQueueItem(player, description);
|
queueEditor.onAddQueueItem(player, description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAddQueueItem(MediaDescriptionCompat description, int index) {
|
public void onAddQueueItem(MediaDescriptionCompat description, int index) {
|
||||||
if (queueEditor != null) {
|
if (canDispatchQueueEdit()) {
|
||||||
queueEditor.onAddQueueItem(player, description, index);
|
queueEditor.onAddQueueItem(player, description, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRemoveQueueItem(MediaDescriptionCompat description) {
|
public void onRemoveQueueItem(MediaDescriptionCompat description) {
|
||||||
if (queueEditor != null) {
|
if (canDispatchQueueEdit()) {
|
||||||
queueEditor.onRemoveQueueItem(player, description);
|
queueEditor.onRemoveQueueItem(player, description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,21 +84,25 @@ public abstract class TimelineQueueNavigator implements MediaSessionConnector.Qu
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getSupportedQueueNavigatorActions(Player player) {
|
public long getSupportedQueueNavigatorActions(Player player) {
|
||||||
if (player == null) {
|
boolean enableSkipTo = false;
|
||||||
return 0;
|
boolean enablePrevious = false;
|
||||||
}
|
boolean enableNext = false;
|
||||||
Timeline timeline = player.getCurrentTimeline();
|
Timeline timeline = player.getCurrentTimeline();
|
||||||
if (timeline.isEmpty() || player.isPlayingAd()) {
|
if (!timeline.isEmpty() && !player.isPlayingAd()) {
|
||||||
return 0;
|
timeline.getWindow(player.getCurrentWindowIndex(), window);
|
||||||
|
enableSkipTo = timeline.getWindowCount() > 1;
|
||||||
|
enablePrevious = window.isSeekable || !window.isDynamic || player.hasPrevious();
|
||||||
|
enableNext = window.isDynamic || player.hasNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
long actions = 0;
|
long actions = 0;
|
||||||
if (timeline.getWindowCount() > 1) {
|
if (enableSkipTo) {
|
||||||
actions |= PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM;
|
actions |= PlaybackStateCompat.ACTION_SKIP_TO_QUEUE_ITEM;
|
||||||
}
|
}
|
||||||
if (window.isSeekable || !window.isDynamic || player.hasPrevious()) {
|
if (enablePrevious) {
|
||||||
actions |= PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
|
actions |= PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS;
|
||||||
}
|
}
|
||||||
if (window.isDynamic || player.hasNext()) {
|
if (enableNext) {
|
||||||
actions |= PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
|
actions |= PlaybackStateCompat.ACTION_SKIP_TO_NEXT;
|
||||||
}
|
}
|
||||||
return actions;
|
return actions;
|
||||||
|
@ -224,10 +224,10 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
private final String repeatOneButtonContentDescription;
|
private final String repeatOneButtonContentDescription;
|
||||||
private final String repeatAllButtonContentDescription;
|
private final String repeatAllButtonContentDescription;
|
||||||
|
|
||||||
private Player player;
|
@Nullable private Player player;
|
||||||
private com.google.android.exoplayer2.ControlDispatcher controlDispatcher;
|
private com.google.android.exoplayer2.ControlDispatcher controlDispatcher;
|
||||||
private VisibilityListener visibilityListener;
|
private VisibilityListener visibilityListener;
|
||||||
private @Nullable PlaybackPreparer playbackPreparer;
|
@Nullable private PlaybackPreparer playbackPreparer;
|
||||||
|
|
||||||
private boolean isAttachedToWindow;
|
private boolean isAttachedToWindow;
|
||||||
private boolean showMultiWindowTimeBar;
|
private boolean showMultiWindowTimeBar;
|
||||||
@ -363,6 +363,7 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
* Returns the {@link Player} currently being controlled by this view, or null if no player is
|
* Returns the {@link Player} currently being controlled by this view, or null if no player is
|
||||||
* set.
|
* set.
|
||||||
*/
|
*/
|
||||||
|
@Nullable
|
||||||
public Player getPlayer() {
|
public Player getPlayer() {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
@ -411,8 +412,8 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
*
|
*
|
||||||
* @param extraAdGroupTimesMs The millisecond timestamps of the extra ad markers to show, or
|
* @param extraAdGroupTimesMs The millisecond timestamps of the extra ad markers to show, or
|
||||||
* {@code null} to show no extra ad markers.
|
* {@code null} to show no extra ad markers.
|
||||||
* @param extraPlayedAdGroups Whether each ad has been played, or {@code null} to show no extra ad
|
* @param extraPlayedAdGroups Whether each ad has been played. Must be the same length as {@code
|
||||||
* markers.
|
* extraAdGroupTimesMs}, or {@code null} if {@code extraAdGroupTimesMs} is {@code null}.
|
||||||
*/
|
*/
|
||||||
public void setExtraAdGroupMarkers(
|
public void setExtraAdGroupMarkers(
|
||||||
@Nullable long[] extraAdGroupTimesMs, @Nullable boolean[] extraPlayedAdGroups) {
|
@Nullable long[] extraAdGroupTimesMs, @Nullable boolean[] extraPlayedAdGroups) {
|
||||||
@ -420,6 +421,7 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
this.extraAdGroupTimesMs = new long[0];
|
this.extraAdGroupTimesMs = new long[0];
|
||||||
this.extraPlayedAdGroups = new boolean[0];
|
this.extraPlayedAdGroups = new boolean[0];
|
||||||
} else {
|
} else {
|
||||||
|
extraPlayedAdGroups = Assertions.checkNotNull(extraPlayedAdGroups);
|
||||||
Assertions.checkArgument(extraAdGroupTimesMs.length == extraPlayedAdGroups.length);
|
Assertions.checkArgument(extraAdGroupTimesMs.length == extraPlayedAdGroups.length);
|
||||||
this.extraAdGroupTimesMs = extraAdGroupTimesMs;
|
this.extraAdGroupTimesMs = extraAdGroupTimesMs;
|
||||||
this.extraPlayedAdGroups = extraPlayedAdGroups;
|
this.extraPlayedAdGroups = extraPlayedAdGroups;
|
||||||
@ -659,24 +661,30 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
if (!isVisible() || !isAttachedToWindow) {
|
if (!isVisible() || !isAttachedToWindow) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Timeline timeline = player != null ? player.getCurrentTimeline() : null;
|
boolean enableSeeking = false;
|
||||||
boolean haveNonEmptyTimeline = timeline != null && !timeline.isEmpty();
|
|
||||||
boolean isSeekable = false;
|
|
||||||
boolean enablePrevious = false;
|
boolean enablePrevious = false;
|
||||||
|
boolean enableRewind = false;
|
||||||
|
boolean enableFastForward = false;
|
||||||
boolean enableNext = false;
|
boolean enableNext = false;
|
||||||
if (haveNonEmptyTimeline && !player.isPlayingAd()) {
|
if (player != null) {
|
||||||
int windowIndex = player.getCurrentWindowIndex();
|
Timeline timeline = player.getCurrentTimeline();
|
||||||
timeline.getWindow(windowIndex, window);
|
if (!timeline.isEmpty() && !player.isPlayingAd()) {
|
||||||
isSeekable = window.isSeekable;
|
timeline.getWindow(player.getCurrentWindowIndex(), window);
|
||||||
enablePrevious = isSeekable || !window.isDynamic || player.hasPrevious();
|
boolean isSeekable = window.isSeekable;
|
||||||
enableNext = window.isDynamic || player.hasNext();
|
enableSeeking = isSeekable;
|
||||||
|
enablePrevious = isSeekable || !window.isDynamic || player.hasPrevious();
|
||||||
|
enableRewind = isSeekable && rewindMs > 0;
|
||||||
|
enableFastForward = isSeekable && fastForwardMs > 0;
|
||||||
|
enableNext = window.isDynamic || player.hasNext();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setButtonEnabled(enablePrevious, previousButton);
|
setButtonEnabled(enablePrevious, previousButton);
|
||||||
|
setButtonEnabled(enableRewind, rewindButton);
|
||||||
|
setButtonEnabled(enableFastForward, fastForwardButton);
|
||||||
setButtonEnabled(enableNext, nextButton);
|
setButtonEnabled(enableNext, nextButton);
|
||||||
setButtonEnabled(fastForwardMs > 0 && isSeekable, fastForwardButton);
|
|
||||||
setButtonEnabled(rewindMs > 0 && isSeekable, rewindButton);
|
|
||||||
if (timeBar != null) {
|
if (timeBar != null) {
|
||||||
timeBar.setEnabled(isSeekable);
|
timeBar.setEnabled(enableSeeking);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,7 +870,7 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
view.setVisibility(VISIBLE);
|
view.setVisibility(VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void previous() {
|
private void previous(Player player) {
|
||||||
Timeline timeline = player.getCurrentTimeline();
|
Timeline timeline = player.getCurrentTimeline();
|
||||||
if (timeline.isEmpty() || player.isPlayingAd()) {
|
if (timeline.isEmpty() || player.isPlayingAd()) {
|
||||||
return;
|
return;
|
||||||
@ -873,13 +881,13 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
if (previousWindowIndex != C.INDEX_UNSET
|
if (previousWindowIndex != C.INDEX_UNSET
|
||||||
&& (player.getCurrentPosition() <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS
|
&& (player.getCurrentPosition() <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS
|
||||||
|| (window.isDynamic && !window.isSeekable))) {
|
|| (window.isDynamic && !window.isSeekable))) {
|
||||||
seekTo(previousWindowIndex, C.TIME_UNSET);
|
seekTo(player, previousWindowIndex, C.TIME_UNSET);
|
||||||
} else {
|
} else {
|
||||||
seekTo(0);
|
seekTo(player, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void next() {
|
private void next(Player player) {
|
||||||
Timeline timeline = player.getCurrentTimeline();
|
Timeline timeline = player.getCurrentTimeline();
|
||||||
if (timeline.isEmpty() || player.isPlayingAd()) {
|
if (timeline.isEmpty() || player.isPlayingAd()) {
|
||||||
return;
|
return;
|
||||||
@ -887,29 +895,29 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
int windowIndex = player.getCurrentWindowIndex();
|
int windowIndex = player.getCurrentWindowIndex();
|
||||||
int nextWindowIndex = player.getNextWindowIndex();
|
int nextWindowIndex = player.getNextWindowIndex();
|
||||||
if (nextWindowIndex != C.INDEX_UNSET) {
|
if (nextWindowIndex != C.INDEX_UNSET) {
|
||||||
seekTo(nextWindowIndex, C.TIME_UNSET);
|
seekTo(player, nextWindowIndex, C.TIME_UNSET);
|
||||||
} else if (timeline.getWindow(windowIndex, window).isDynamic) {
|
} else if (timeline.getWindow(windowIndex, window).isDynamic) {
|
||||||
seekTo(windowIndex, C.TIME_UNSET);
|
seekTo(player, windowIndex, C.TIME_UNSET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void rewind() {
|
private void rewind(Player player) {
|
||||||
if (rewindMs > 0) {
|
if (player.isCurrentWindowSeekable() && rewindMs > 0) {
|
||||||
seekTo(player.getCurrentPosition() - rewindMs);
|
seekTo(player, player.getCurrentPosition() - rewindMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fastForward() {
|
private void fastForward(Player player) {
|
||||||
if (fastForwardMs > 0) {
|
if (player.isCurrentWindowSeekable() && fastForwardMs > 0) {
|
||||||
seekTo(player.getCurrentPosition() + fastForwardMs);
|
seekTo(player, player.getCurrentPosition() + fastForwardMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void seekTo(long positionMs) {
|
private void seekTo(Player player, long positionMs) {
|
||||||
seekTo(player.getCurrentWindowIndex(), positionMs);
|
seekTo(player, player.getCurrentWindowIndex(), positionMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean seekTo(int windowIndex, long positionMs) {
|
private boolean seekTo(Player player, int windowIndex, long positionMs) {
|
||||||
long durationMs = player.getDuration();
|
long durationMs = player.getDuration();
|
||||||
if (durationMs != C.TIME_UNSET) {
|
if (durationMs != C.TIME_UNSET) {
|
||||||
positionMs = Math.min(positionMs, durationMs);
|
positionMs = Math.min(positionMs, durationMs);
|
||||||
@ -918,7 +926,7 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
return controlDispatcher.dispatchSeekTo(player, windowIndex, positionMs);
|
return controlDispatcher.dispatchSeekTo(player, windowIndex, positionMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void seekToTimeBarPosition(long positionMs) {
|
private void seekToTimeBarPosition(Player player, long positionMs) {
|
||||||
int windowIndex;
|
int windowIndex;
|
||||||
Timeline timeline = player.getCurrentTimeline();
|
Timeline timeline = player.getCurrentTimeline();
|
||||||
if (multiWindowTimeBar && !timeline.isEmpty()) {
|
if (multiWindowTimeBar && !timeline.isEmpty()) {
|
||||||
@ -939,7 +947,7 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
} else {
|
} else {
|
||||||
windowIndex = player.getCurrentWindowIndex();
|
windowIndex = player.getCurrentWindowIndex();
|
||||||
}
|
}
|
||||||
boolean dispatched = seekTo(windowIndex, positionMs);
|
boolean dispatched = seekTo(player, windowIndex, positionMs);
|
||||||
if (!dispatched) {
|
if (!dispatched) {
|
||||||
// The seek wasn't dispatched then the progress bar scrubber will be in the wrong position.
|
// The seek wasn't dispatched then the progress bar scrubber will be in the wrong position.
|
||||||
// Trigger a progress update to snap it back.
|
// Trigger a progress update to snap it back.
|
||||||
@ -1001,9 +1009,9 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
}
|
}
|
||||||
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
if (event.getAction() == KeyEvent.ACTION_DOWN) {
|
||||||
if (keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
|
if (keyCode == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
|
||||||
fastForward();
|
fastForward(player);
|
||||||
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_REWIND) {
|
} else if (keyCode == KeyEvent.KEYCODE_MEDIA_REWIND) {
|
||||||
rewind();
|
rewind(player);
|
||||||
} else if (event.getRepeatCount() == 0) {
|
} else if (event.getRepeatCount() == 0) {
|
||||||
switch (keyCode) {
|
switch (keyCode) {
|
||||||
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
|
||||||
@ -1016,10 +1024,10 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
controlDispatcher.dispatchSetPlayWhenReady(player, false);
|
controlDispatcher.dispatchSetPlayWhenReady(player, false);
|
||||||
break;
|
break;
|
||||||
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
case KeyEvent.KEYCODE_MEDIA_NEXT:
|
||||||
next();
|
next(player);
|
||||||
break;
|
break;
|
||||||
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
|
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
|
||||||
previous();
|
previous(player);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -1086,7 +1094,7 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
public void onScrubStop(TimeBar timeBar, long position, boolean canceled) {
|
public void onScrubStop(TimeBar timeBar, long position, boolean canceled) {
|
||||||
scrubbing = false;
|
scrubbing = false;
|
||||||
if (!canceled && player != null) {
|
if (!canceled && player != null) {
|
||||||
seekToTimeBarPosition(position);
|
seekToTimeBarPosition(player, position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1124,32 +1132,34 @@ public class PlayerControlView extends FrameLayout {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onClick(View view) {
|
||||||
if (player != null) {
|
Player player = PlayerControlView.this.player;
|
||||||
if (nextButton == view) {
|
if (player == null) {
|
||||||
next();
|
return;
|
||||||
} else if (previousButton == view) {
|
}
|
||||||
previous();
|
if (nextButton == view) {
|
||||||
} else if (fastForwardButton == view) {
|
next(player);
|
||||||
fastForward();
|
} else if (previousButton == view) {
|
||||||
} else if (rewindButton == view) {
|
previous(player);
|
||||||
rewind();
|
} else if (fastForwardButton == view) {
|
||||||
} else if (playButton == view) {
|
fastForward(player);
|
||||||
if (player.getPlaybackState() == Player.STATE_IDLE) {
|
} else if (rewindButton == view) {
|
||||||
if (playbackPreparer != null) {
|
rewind(player);
|
||||||
playbackPreparer.preparePlayback();
|
} else if (playButton == view) {
|
||||||
}
|
if (player.getPlaybackState() == Player.STATE_IDLE) {
|
||||||
} else if (player.getPlaybackState() == Player.STATE_ENDED) {
|
if (playbackPreparer != null) {
|
||||||
controlDispatcher.dispatchSeekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET);
|
playbackPreparer.preparePlayback();
|
||||||
}
|
}
|
||||||
controlDispatcher.dispatchSetPlayWhenReady(player, true);
|
} else if (player.getPlaybackState() == Player.STATE_ENDED) {
|
||||||
} else if (pauseButton == view) {
|
controlDispatcher.dispatchSeekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET);
|
||||||
controlDispatcher.dispatchSetPlayWhenReady(player, false);
|
|
||||||
} else if (repeatToggleButton == view) {
|
|
||||||
controlDispatcher.dispatchSetRepeatMode(
|
|
||||||
player, RepeatModeUtil.getNextRepeatMode(player.getRepeatMode(), repeatToggleModes));
|
|
||||||
} else if (shuffleButton == view) {
|
|
||||||
controlDispatcher.dispatchSetShuffleModeEnabled(player, !player.getShuffleModeEnabled());
|
|
||||||
}
|
}
|
||||||
|
controlDispatcher.dispatchSetPlayWhenReady(player, true);
|
||||||
|
} else if (pauseButton == view) {
|
||||||
|
controlDispatcher.dispatchSetPlayWhenReady(player, false);
|
||||||
|
} else if (repeatToggleButton == view) {
|
||||||
|
controlDispatcher.dispatchSetRepeatMode(
|
||||||
|
player, RepeatModeUtil.getNextRepeatMode(player.getRepeatMode(), repeatToggleModes));
|
||||||
|
} else if (shuffleButton == view) {
|
||||||
|
controlDispatcher.dispatchSetShuffleModeEnabled(player, !player.getShuffleModeEnabled());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -299,8 +299,9 @@ public class PlayerNotificationManager {
|
|||||||
private final Map<String, NotificationCompat.Action> playbackActions;
|
private final Map<String, NotificationCompat.Action> playbackActions;
|
||||||
private final Map<String, NotificationCompat.Action> customActions;
|
private final Map<String, NotificationCompat.Action> customActions;
|
||||||
private final int instanceId;
|
private final int instanceId;
|
||||||
|
private final Timeline.Window window;
|
||||||
|
|
||||||
private @Nullable Player player;
|
@Nullable private Player player;
|
||||||
private ControlDispatcher controlDispatcher;
|
private ControlDispatcher controlDispatcher;
|
||||||
private boolean isNotificationStarted;
|
private boolean isNotificationStarted;
|
||||||
private int currentNotificationTag;
|
private int currentNotificationTag;
|
||||||
@ -485,7 +486,8 @@ public class PlayerNotificationManager {
|
|||||||
this.mediaDescriptionAdapter = mediaDescriptionAdapter;
|
this.mediaDescriptionAdapter = mediaDescriptionAdapter;
|
||||||
this.notificationListener = notificationListener;
|
this.notificationListener = notificationListener;
|
||||||
this.customActionReceiver = customActionReceiver;
|
this.customActionReceiver = customActionReceiver;
|
||||||
this.controlDispatcher = new DefaultControlDispatcher();
|
controlDispatcher = new DefaultControlDispatcher();
|
||||||
|
window = new Timeline.Window();
|
||||||
instanceId = instanceIdCounter++;
|
instanceId = instanceIdCounter++;
|
||||||
mainHandler = new Handler(Looper.getMainLooper());
|
mainHandler = new Handler(Looper.getMainLooper());
|
||||||
notificationManager = NotificationManagerCompat.from(context);
|
notificationManager = NotificationManagerCompat.from(context);
|
||||||
@ -968,15 +970,25 @@ public class PlayerNotificationManager {
|
|||||||
* action name is ignored.
|
* action name is ignored.
|
||||||
*/
|
*/
|
||||||
protected List<String> getActions(Player player) {
|
protected List<String> getActions(Player player) {
|
||||||
boolean isPlayingAd = player.isPlayingAd();
|
boolean enablePrevious = false;
|
||||||
|
boolean enableRewind = false;
|
||||||
|
boolean enableFastForward = false;
|
||||||
|
boolean enableNext = false;
|
||||||
|
Timeline timeline = player.getCurrentTimeline();
|
||||||
|
if (!timeline.isEmpty() && !player.isPlayingAd()) {
|
||||||
|
timeline.getWindow(player.getCurrentWindowIndex(), window);
|
||||||
|
enablePrevious = window.isSeekable || !window.isDynamic || player.hasPrevious();
|
||||||
|
enableRewind = rewindMs > 0;
|
||||||
|
enableFastForward = fastForwardMs > 0;
|
||||||
|
enableNext = window.isDynamic || player.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
List<String> stringActions = new ArrayList<>();
|
List<String> stringActions = new ArrayList<>();
|
||||||
if (!isPlayingAd) {
|
if (useNavigationActions && enablePrevious) {
|
||||||
if (useNavigationActions) {
|
stringActions.add(ACTION_PREVIOUS);
|
||||||
stringActions.add(ACTION_PREVIOUS);
|
}
|
||||||
}
|
if (enableRewind) {
|
||||||
if (rewindMs > 0) {
|
stringActions.add(ACTION_REWIND);
|
||||||
stringActions.add(ACTION_REWIND);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (usePlayPauseActions) {
|
if (usePlayPauseActions) {
|
||||||
if (player.getPlayWhenReady()) {
|
if (player.getPlayWhenReady()) {
|
||||||
@ -985,13 +997,11 @@ public class PlayerNotificationManager {
|
|||||||
stringActions.add(ACTION_PLAY);
|
stringActions.add(ACTION_PLAY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isPlayingAd) {
|
if (enableFastForward) {
|
||||||
if (fastForwardMs > 0) {
|
stringActions.add(ACTION_FAST_FORWARD);
|
||||||
stringActions.add(ACTION_FAST_FORWARD);
|
}
|
||||||
}
|
if (useNavigationActions && enableNext) {
|
||||||
if (useNavigationActions && player.getNextWindowIndex() != C.INDEX_UNSET) {
|
stringActions.add(ACTION_NEXT);
|
||||||
stringActions.add(ACTION_NEXT);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (customActionReceiver != null) {
|
if (customActionReceiver != null) {
|
||||||
stringActions.addAll(customActionReceiver.getCustomActions(player));
|
stringActions.addAll(customActionReceiver.getCustomActions(player));
|
||||||
@ -1011,6 +1021,7 @@ public class PlayerNotificationManager {
|
|||||||
* @param actionNames The names of the actions included in the notification.
|
* @param actionNames The names of the actions included in the notification.
|
||||||
* @param player The player for which state to build a notification.
|
* @param player The player for which state to build a notification.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
protected int[] getActionIndicesForCompactView(List<String> actionNames, Player player) {
|
protected int[] getActionIndicesForCompactView(List<String> actionNames, Player player) {
|
||||||
int pauseActionIndex = actionNames.indexOf(ACTION_PAUSE);
|
int pauseActionIndex = actionNames.indexOf(ACTION_PAUSE);
|
||||||
int playActionIndex = actionNames.indexOf(ACTION_PLAY);
|
int playActionIndex = actionNames.indexOf(ACTION_PLAY);
|
||||||
@ -1067,6 +1078,62 @@ public class PlayerNotificationManager {
|
|||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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, 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) {
|
||||||
|
seekTo(player, Math.max(player.getCurrentPosition() - rewindMs, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fastForward(Player player) {
|
||||||
|
if (player.isCurrentWindowSeekable() && fastForwardMs > 0) {
|
||||||
|
seekTo(player, player.getCurrentPosition() + fastForwardMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void seekTo(Player player, long positionMs) {
|
||||||
|
seekTo(player, player.getCurrentWindowIndex(), positionMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void seekTo(Player player, int windowIndex, long positionMs) {
|
||||||
|
long duration = player.getDuration();
|
||||||
|
if (duration != C.TIME_UNSET) {
|
||||||
|
positionMs = Math.min(positionMs, duration);
|
||||||
|
}
|
||||||
|
positionMs = Math.max(positionMs, 0);
|
||||||
|
controlDispatcher.dispatchSeekTo(player, windowIndex, positionMs);
|
||||||
|
}
|
||||||
|
|
||||||
private static PendingIntent createBroadcastIntent(
|
private static PendingIntent createBroadcastIntent(
|
||||||
String action, Context context, int instanceId) {
|
String action, Context context, int instanceId) {
|
||||||
Intent intent = new Intent(action).setPackage(context.getPackageName());
|
Intent intent = new Intent(action).setPackage(context.getPackageName());
|
||||||
@ -1119,13 +1186,6 @@ public class PlayerNotificationManager {
|
|||||||
|
|
||||||
private class NotificationBroadcastReceiver extends BroadcastReceiver {
|
private class NotificationBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
private final Timeline.Window window;
|
|
||||||
|
|
||||||
/** Creates the broadcast receiver. */
|
|
||||||
public NotificationBroadcastReceiver() {
|
|
||||||
window = new Timeline.Window();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
Player player = PlayerNotificationManager.this.player;
|
Player player = PlayerNotificationManager.this.player;
|
||||||
@ -1137,25 +1197,14 @@ public class PlayerNotificationManager {
|
|||||||
String action = intent.getAction();
|
String action = intent.getAction();
|
||||||
if (ACTION_PLAY.equals(action) || ACTION_PAUSE.equals(action)) {
|
if (ACTION_PLAY.equals(action) || ACTION_PAUSE.equals(action)) {
|
||||||
controlDispatcher.dispatchSetPlayWhenReady(player, ACTION_PLAY.equals(action));
|
controlDispatcher.dispatchSetPlayWhenReady(player, ACTION_PLAY.equals(action));
|
||||||
} else if (ACTION_FAST_FORWARD.equals(action) || ACTION_REWIND.equals(action)) {
|
|
||||||
long increment = ACTION_FAST_FORWARD.equals(action) ? fastForwardMs : -rewindMs;
|
|
||||||
controlDispatcher.dispatchSeekTo(
|
|
||||||
player, player.getCurrentWindowIndex(), player.getCurrentPosition() + increment);
|
|
||||||
} else if (ACTION_NEXT.equals(action)) {
|
|
||||||
int nextWindowIndex = player.getNextWindowIndex();
|
|
||||||
if (nextWindowIndex != C.INDEX_UNSET) {
|
|
||||||
controlDispatcher.dispatchSeekTo(player, nextWindowIndex, C.TIME_UNSET);
|
|
||||||
}
|
|
||||||
} else if (ACTION_PREVIOUS.equals(action)) {
|
} else if (ACTION_PREVIOUS.equals(action)) {
|
||||||
player.getCurrentTimeline().getWindow(player.getCurrentWindowIndex(), window);
|
previous(player);
|
||||||
int previousWindowIndex = player.getPreviousWindowIndex();
|
} else if (ACTION_REWIND.equals(action)) {
|
||||||
if (previousWindowIndex != C.INDEX_UNSET
|
rewind(player);
|
||||||
&& (player.getCurrentPosition() <= MAX_POSITION_FOR_SEEK_TO_PREVIOUS
|
} else if (ACTION_FAST_FORWARD.equals(action)) {
|
||||||
|| (window.isDynamic && !window.isSeekable))) {
|
fastForward(player);
|
||||||
controlDispatcher.dispatchSeekTo(player, previousWindowIndex, C.TIME_UNSET);
|
} else if (ACTION_NEXT.equals(action)) {
|
||||||
} else {
|
next(player);
|
||||||
controlDispatcher.dispatchSeekTo(player, player.getCurrentWindowIndex(), C.TIME_UNSET);
|
|
||||||
}
|
|
||||||
} else if (ACTION_STOP.equals(action)) {
|
} else if (ACTION_STOP.equals(action)) {
|
||||||
controlDispatcher.dispatchStop(player, true);
|
controlDispatcher.dispatchStop(player, true);
|
||||||
stopNotification();
|
stopNotification();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user