Make Timeline always non-null from ExoPlayer

Note that we still have null timelines in ExoPlayerImplInternal.
This is deliberate; and is likely necessary to distinguish between
the no-timeline-yet and timeline-is-empty cases (we want to try
and process a pending seek for the latter, but not the former).

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=140200980
This commit is contained in:
olly 2016-11-25 07:21:51 -08:00 committed by Oliver Woodman
parent 97a23ce572
commit ce9ec79e59
5 changed files with 57 additions and 16 deletions

View File

@ -360,7 +360,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
playerWindow = player.getCurrentWindowIndex(); playerWindow = player.getCurrentWindowIndex();
playerPosition = C.TIME_UNSET; playerPosition = C.TIME_UNSET;
Timeline timeline = player.getCurrentTimeline(); Timeline timeline = player.getCurrentTimeline();
if (timeline != null && timeline.getWindow(playerWindow, window).isSeekable) { if (!timeline.isEmpty() && timeline.getWindow(playerWindow, window).isSeekable) {
playerPosition = player.getCurrentPosition(); playerPosition = player.getCurrentPosition();
} }
player.release(); player.release();
@ -417,7 +417,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay
@Override @Override
public void onTimelineChanged(Timeline timeline, Object manifest) { public void onTimelineChanged(Timeline timeline, Object manifest) {
isTimelineStatic = timeline != null && timeline.getWindowCount() > 0 isTimelineStatic = !timeline.isEmpty()
&& !timeline.getWindow(timeline.getWindowCount() - 1, window).isDynamic; && !timeline.getWindow(timeline.getWindowCount() - 1, window).isDynamic;
} }

View File

@ -403,12 +403,12 @@ public interface ExoPlayer {
/** /**
* Returns the current manifest. The type depends on the {@link MediaSource} passed to * Returns the current manifest. The type depends on the {@link MediaSource} passed to
* {@link #prepare}. * {@link #prepare}. May be null.
*/ */
Object getCurrentManifest(); Object getCurrentManifest();
/** /**
* Returns the current {@link Timeline}, or {@code null} if there is no timeline. * Returns the current {@link Timeline}. Never null, but may be empty.
*/ */
Timeline getCurrentTimeline(); Timeline getCurrentTimeline();

View File

@ -82,6 +82,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
this.playbackState = STATE_IDLE; this.playbackState = STATE_IDLE;
this.listeners = new CopyOnWriteArraySet<>(); this.listeners = new CopyOnWriteArraySet<>();
emptyTrackSelections = new TrackSelectionArray(new TrackSelection[renderers.length]); emptyTrackSelections = new TrackSelectionArray(new TrackSelection[renderers.length]);
timeline = Timeline.EMPTY;
window = new Timeline.Window(); window = new Timeline.Window();
period = new Timeline.Period(); period = new Timeline.Period();
trackGroups = TrackGroupArray.EMPTY; trackGroups = TrackGroupArray.EMPTY;
@ -120,8 +121,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override @Override
public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) { public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) {
if (resetState) { if (resetState) {
if (timeline != null || manifest != null) { if (!timeline.isEmpty() || manifest != null) {
timeline = null; timeline = Timeline.EMPTY;
manifest = null; manifest = null;
for (EventListener listener : listeners) { for (EventListener listener : listeners) {
listener.onTimelineChanged(null, null); listener.onTimelineChanged(null, null);
@ -178,7 +179,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override @Override
public void seekTo(int windowIndex, long positionMs) { public void seekTo(int windowIndex, long positionMs) {
if (windowIndex < 0 || (timeline != null && windowIndex >= timeline.getWindowCount())) { if (windowIndex < 0 || (!timeline.isEmpty() && windowIndex >= timeline.getWindowCount())) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
pendingSeekAcks++; pendingSeekAcks++;
@ -223,7 +224,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override @Override
public int getCurrentWindowIndex() { public int getCurrentWindowIndex() {
if (timeline == null || pendingSeekAcks > 0) { if (timeline.isEmpty() || pendingSeekAcks > 0) {
return maskingWindowIndex; return maskingWindowIndex;
} else { } else {
return timeline.getPeriod(playbackInfo.periodIndex, period).windowIndex; return timeline.getPeriod(playbackInfo.periodIndex, period).windowIndex;
@ -232,7 +233,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override @Override
public long getDuration() { public long getDuration() {
if (timeline == null) { if (timeline.isEmpty()) {
return C.TIME_UNSET; return C.TIME_UNSET;
} }
return timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs(); return timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs();
@ -240,7 +241,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override @Override
public long getCurrentPosition() { public long getCurrentPosition() {
if (timeline == null || pendingSeekAcks > 0) { if (timeline.isEmpty() || pendingSeekAcks > 0) {
return maskingWindowPositionMs; return maskingWindowPositionMs;
} else { } else {
timeline.getPeriod(playbackInfo.periodIndex, period); timeline.getPeriod(playbackInfo.periodIndex, period);
@ -251,7 +252,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override @Override
public long getBufferedPosition() { public long getBufferedPosition() {
// TODO - Implement this properly. // TODO - Implement this properly.
if (timeline == null || pendingSeekAcks > 0) { if (timeline.isEmpty() || pendingSeekAcks > 0) {
return maskingWindowPositionMs; return maskingWindowPositionMs;
} else { } else {
timeline.getPeriod(playbackInfo.periodIndex, period); timeline.getPeriod(playbackInfo.periodIndex, period);
@ -261,7 +262,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override @Override
public int getBufferedPercentage() { public int getBufferedPercentage() {
if (timeline == null) { if (timeline.isEmpty()) {
return 0; return 0;
} }
long bufferedPosition = getBufferedPosition(); long bufferedPosition = getBufferedPosition();

View File

@ -91,6 +91,46 @@ package com.google.android.exoplayer2;
*/ */
public abstract class Timeline { public abstract class Timeline {
/**
* An empty timeline.
*/
public static final Timeline EMPTY = new Timeline() {
@Override
public int getWindowCount() {
return 0;
}
@Override
public Window getWindow(int windowIndex, Window window, boolean setIds,
long defaultPositionProjectionUs) {
throw new IndexOutOfBoundsException();
}
@Override
public int getPeriodCount() {
return 0;
}
@Override
public Period getPeriod(int periodIndex, Period period, boolean setIds) {
throw new IndexOutOfBoundsException();
}
@Override
public int getIndexOfPeriod(Object uid) {
return C.INDEX_UNSET;
}
};
/**
* Returns whether the timeline is empty.
*/
public final boolean isEmpty() {
return getWindowCount() == 0;
}
/** /**
* Returns the number of windows in the timeline. * Returns the number of windows in the timeline.
*/ */

View File

@ -422,11 +422,11 @@ public class PlaybackControlView extends FrameLayout {
return; return;
} }
Timeline currentTimeline = player != null ? player.getCurrentTimeline() : null; Timeline currentTimeline = player != null ? player.getCurrentTimeline() : null;
boolean haveTimeline = currentTimeline != null; boolean haveNonEmptyTimeline = currentTimeline != null && !currentTimeline.isEmpty();
boolean isSeekable = false; boolean isSeekable = false;
boolean enablePrevious = false; boolean enablePrevious = false;
boolean enableNext = false; boolean enableNext = false;
if (haveTimeline) { if (haveNonEmptyTimeline) {
int currentWindowIndex = player.getCurrentWindowIndex(); int currentWindowIndex = player.getCurrentWindowIndex();
currentTimeline.getWindow(currentWindowIndex, currentWindow); currentTimeline.getWindow(currentWindowIndex, currentWindow);
isSeekable = currentWindow.isSeekable; isSeekable = currentWindow.isSeekable;
@ -525,7 +525,7 @@ public class PlaybackControlView extends FrameLayout {
private void previous() { private void previous() {
Timeline currentTimeline = player.getCurrentTimeline(); Timeline currentTimeline = player.getCurrentTimeline();
if (currentTimeline == null) { if (currentTimeline.isEmpty()) {
return; return;
} }
int currentWindowIndex = player.getCurrentWindowIndex(); int currentWindowIndex = player.getCurrentWindowIndex();
@ -540,7 +540,7 @@ public class PlaybackControlView extends FrameLayout {
private void next() { private void next() {
Timeline currentTimeline = player.getCurrentTimeline(); Timeline currentTimeline = player.getCurrentTimeline();
if (currentTimeline == null) { if (currentTimeline.isEmpty()) {
return; return;
} }
int currentWindowIndex = player.getCurrentWindowIndex(); int currentWindowIndex = player.getCurrentWindowIndex();