From ce9ec79e5977e76512162dae355a596727e02b45 Mon Sep 17 00:00:00 2001 From: olly Date: Fri, 25 Nov 2016 07:21:51 -0800 Subject: [PATCH] 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 --- .../exoplayer2/demo/PlayerActivity.java | 4 +- .../google/android/exoplayer2/ExoPlayer.java | 4 +- .../android/exoplayer2/ExoPlayerImpl.java | 17 ++++---- .../google/android/exoplayer2/Timeline.java | 40 +++++++++++++++++++ .../exoplayer2/ui/PlaybackControlView.java | 8 ++-- 5 files changed, 57 insertions(+), 16 deletions(-) diff --git a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 7589d54810..413157cbd0 100644 --- a/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demo/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -360,7 +360,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay playerWindow = player.getCurrentWindowIndex(); playerPosition = C.TIME_UNSET; Timeline timeline = player.getCurrentTimeline(); - if (timeline != null && timeline.getWindow(playerWindow, window).isSeekable) { + if (!timeline.isEmpty() && timeline.getWindow(playerWindow, window).isSeekable) { playerPosition = player.getCurrentPosition(); } player.release(); @@ -417,7 +417,7 @@ public class PlayerActivity extends Activity implements OnClickListener, ExoPlay @Override public void onTimelineChanged(Timeline timeline, Object manifest) { - isTimelineStatic = timeline != null && timeline.getWindowCount() > 0 + isTimelineStatic = !timeline.isEmpty() && !timeline.getWindow(timeline.getWindowCount() - 1, window).isDynamic; } diff --git a/library/src/main/java/com/google/android/exoplayer2/ExoPlayer.java b/library/src/main/java/com/google/android/exoplayer2/ExoPlayer.java index 83e4fd7e30..c84e6f9985 100644 --- a/library/src/main/java/com/google/android/exoplayer2/ExoPlayer.java +++ b/library/src/main/java/com/google/android/exoplayer2/ExoPlayer.java @@ -403,12 +403,12 @@ public interface ExoPlayer { /** * Returns the current manifest. The type depends on the {@link MediaSource} passed to - * {@link #prepare}. + * {@link #prepare}. May be null. */ 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(); diff --git a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 5bf1b599e2..af4416e4a1 100644 --- a/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -82,6 +82,7 @@ import java.util.concurrent.CopyOnWriteArraySet; this.playbackState = STATE_IDLE; this.listeners = new CopyOnWriteArraySet<>(); emptyTrackSelections = new TrackSelectionArray(new TrackSelection[renderers.length]); + timeline = Timeline.EMPTY; window = new Timeline.Window(); period = new Timeline.Period(); trackGroups = TrackGroupArray.EMPTY; @@ -120,8 +121,8 @@ import java.util.concurrent.CopyOnWriteArraySet; @Override public void prepare(MediaSource mediaSource, boolean resetPosition, boolean resetState) { if (resetState) { - if (timeline != null || manifest != null) { - timeline = null; + if (!timeline.isEmpty() || manifest != null) { + timeline = Timeline.EMPTY; manifest = null; for (EventListener listener : listeners) { listener.onTimelineChanged(null, null); @@ -178,7 +179,7 @@ import java.util.concurrent.CopyOnWriteArraySet; @Override 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(); } pendingSeekAcks++; @@ -223,7 +224,7 @@ import java.util.concurrent.CopyOnWriteArraySet; @Override public int getCurrentWindowIndex() { - if (timeline == null || pendingSeekAcks > 0) { + if (timeline.isEmpty() || pendingSeekAcks > 0) { return maskingWindowIndex; } else { return timeline.getPeriod(playbackInfo.periodIndex, period).windowIndex; @@ -232,7 +233,7 @@ import java.util.concurrent.CopyOnWriteArraySet; @Override public long getDuration() { - if (timeline == null) { + if (timeline.isEmpty()) { return C.TIME_UNSET; } return timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs(); @@ -240,7 +241,7 @@ import java.util.concurrent.CopyOnWriteArraySet; @Override public long getCurrentPosition() { - if (timeline == null || pendingSeekAcks > 0) { + if (timeline.isEmpty() || pendingSeekAcks > 0) { return maskingWindowPositionMs; } else { timeline.getPeriod(playbackInfo.periodIndex, period); @@ -251,7 +252,7 @@ import java.util.concurrent.CopyOnWriteArraySet; @Override public long getBufferedPosition() { // TODO - Implement this properly. - if (timeline == null || pendingSeekAcks > 0) { + if (timeline.isEmpty() || pendingSeekAcks > 0) { return maskingWindowPositionMs; } else { timeline.getPeriod(playbackInfo.periodIndex, period); @@ -261,7 +262,7 @@ import java.util.concurrent.CopyOnWriteArraySet; @Override public int getBufferedPercentage() { - if (timeline == null) { + if (timeline.isEmpty()) { return 0; } long bufferedPosition = getBufferedPosition(); diff --git a/library/src/main/java/com/google/android/exoplayer2/Timeline.java b/library/src/main/java/com/google/android/exoplayer2/Timeline.java index 1b0d03676b..32af48bd59 100644 --- a/library/src/main/java/com/google/android/exoplayer2/Timeline.java +++ b/library/src/main/java/com/google/android/exoplayer2/Timeline.java @@ -91,6 +91,46 @@ package com.google.android.exoplayer2; */ 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. */ diff --git a/library/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java b/library/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java index 29772dcc89..83f1615310 100644 --- a/library/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java +++ b/library/src/main/java/com/google/android/exoplayer2/ui/PlaybackControlView.java @@ -422,11 +422,11 @@ public class PlaybackControlView extends FrameLayout { return; } Timeline currentTimeline = player != null ? player.getCurrentTimeline() : null; - boolean haveTimeline = currentTimeline != null; + boolean haveNonEmptyTimeline = currentTimeline != null && !currentTimeline.isEmpty(); boolean isSeekable = false; boolean enablePrevious = false; boolean enableNext = false; - if (haveTimeline) { + if (haveNonEmptyTimeline) { int currentWindowIndex = player.getCurrentWindowIndex(); currentTimeline.getWindow(currentWindowIndex, currentWindow); isSeekable = currentWindow.isSeekable; @@ -525,7 +525,7 @@ public class PlaybackControlView extends FrameLayout { private void previous() { Timeline currentTimeline = player.getCurrentTimeline(); - if (currentTimeline == null) { + if (currentTimeline.isEmpty()) { return; } int currentWindowIndex = player.getCurrentWindowIndex(); @@ -540,7 +540,7 @@ public class PlaybackControlView extends FrameLayout { private void next() { Timeline currentTimeline = player.getCurrentTimeline(); - if (currentTimeline == null) { + if (currentTimeline.isEmpty()) { return; } int currentWindowIndex = player.getCurrentWindowIndex();