From bbd82cf5da8072a0c67f5a422c426ef2d71e315e Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 2 Oct 2018 05:52:56 -0700 Subject: [PATCH] Add BasePlayer to avoid code duplication for common convenience methods. A lot of methods just forward to other methods and there is no conceivable way a player should implement it another way. Moving these methods to a base player class allows to remove duplicated code across our player implementations. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=215374192 --- .../exoplayer2/ext/cast/CastPlayer.java | 75 +--------- .../exoplayer2/ext/ima/FakePlayer.java | 12 -- .../google/android/exoplayer2/BasePlayer.java | 132 ++++++++++++++++++ .../android/exoplayer2/ExoPlayerImpl.java | 78 +---------- .../android/exoplayer2/SimpleExoPlayer.java | 70 +--------- .../exoplayer2/testutil/StubExoPlayer.java | 59 +------- 6 files changed, 140 insertions(+), 286 deletions(-) create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/BasePlayer.java diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java index 97b05e3f0a..6cf6309796 100644 --- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java +++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastPlayer.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2.ext.cast; import android.os.Looper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import com.google.android.exoplayer2.BasePlayer; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.PlaybackParameters; @@ -31,7 +32,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.MimeTypes; -import com.google.android.exoplayer2.util.Util; import com.google.android.gms.cast.CastStatusCodes; import com.google.android.gms.cast.MediaInfo; import com.google.android.gms.cast.MediaQueueItem; @@ -62,7 +62,7 @@ import java.util.concurrent.CopyOnWriteArraySet; * *

Methods should be called on the application's main thread.

*/ -public final class CastPlayer implements Player { +public final class CastPlayer extends BasePlayer { /** * Listener of changes in the cast session availability. @@ -95,7 +95,6 @@ public final class CastPlayer implements Player { private final CastContext castContext; // TODO: Allow custom implementations of CastTimelineTracker. private final CastTimelineTracker timelineTracker; - private final Timeline.Window window; private final Timeline.Period period; private RemoteMediaClient remoteMediaClient; @@ -128,7 +127,6 @@ public final class CastPlayer implements Player { public CastPlayer(CastContext castContext) { this.castContext = castContext; timelineTracker = new CastTimelineTracker(); - window = new Timeline.Window(); period = new Timeline.Period(); statusListener = new StatusListener(); seekResultCallback = new SeekResultCallback(); @@ -341,21 +339,6 @@ public final class CastPlayer implements Player { return playWhenReady; } - @Override - public void seekToDefaultPosition() { - seekTo(0); - } - - @Override - public void seekToDefaultPosition(int windowIndex) { - seekTo(windowIndex, 0); - } - - @Override - public void seekTo(long positionMs) { - seekTo(getCurrentWindowIndex(), positionMs); - } - @Override public void seekTo(int windowIndex, long positionMs) { MediaStatus mediaStatus = getMediaStatus(); @@ -392,11 +375,6 @@ public final class CastPlayer implements Player { return PlaybackParameters.DEFAULT; } - @Override - public void stop() { - stop(/* reset= */ false); - } - @Override public void stop(boolean reset) { playbackState = STATE_IDLE; @@ -486,32 +464,11 @@ public final class CastPlayer implements Player { return pendingSeekWindowIndex != C.INDEX_UNSET ? pendingSeekWindowIndex : currentWindowIndex; } - @Override - public int getNextWindowIndex() { - return currentTimeline.isEmpty() ? C.INDEX_UNSET - : currentTimeline.getNextWindowIndex(getCurrentWindowIndex(), repeatMode, false); - } - - @Override - public int getPreviousWindowIndex() { - return currentTimeline.isEmpty() ? C.INDEX_UNSET - : currentTimeline.getPreviousWindowIndex(getCurrentWindowIndex(), repeatMode, false); - } - - @Override - public @Nullable Object getCurrentTag() { - int windowIndex = getCurrentWindowIndex(); - return windowIndex >= currentTimeline.getWindowCount() - ? null - : currentTimeline.getWindow(windowIndex, window, /* setTag= */ true).tag; - } - // TODO: Fill the cast timeline information with ProgressListener's duration updates. // See [Internal: b/65152553]. @Override public long getDuration() { - return currentTimeline.isEmpty() ? C.TIME_UNSET - : currentTimeline.getWindow(getCurrentWindowIndex(), window).getDurationMs(); + return getContentDuration(); } @Override @@ -528,15 +485,6 @@ public final class CastPlayer implements Player { return getCurrentPosition(); } - @Override - public int getBufferedPercentage() { - long position = getBufferedPosition(); - long duration = getDuration(); - return position == C.TIME_UNSET || duration == C.TIME_UNSET - ? 0 - : duration == 0 ? 100 : Util.constrainValue((int) ((position * 100) / duration), 0, 100); - } - @Override public long getTotalBufferedDuration() { long bufferedPosition = getBufferedPosition(); @@ -546,18 +494,6 @@ public final class CastPlayer implements Player { : bufferedPosition - currentPosition; } - @Override - public boolean isCurrentWindowDynamic() { - return !currentTimeline.isEmpty() - && currentTimeline.getWindow(getCurrentWindowIndex(), window).isDynamic; - } - - @Override - public boolean isCurrentWindowSeekable() { - return !currentTimeline.isEmpty() - && currentTimeline.getWindow(getCurrentWindowIndex(), window).isSeekable; - } - @Override public boolean isPlayingAd() { return false; @@ -573,11 +509,6 @@ public final class CastPlayer implements Player { return C.INDEX_UNSET; } - @Override - public long getContentDuration() { - return getDuration(); - } - @Override public boolean isLoading() { return false; diff --git a/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/FakePlayer.java b/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/FakePlayer.java index 0c35c9b66d..b8024d6534 100644 --- a/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/FakePlayer.java +++ b/extensions/ima/src/test/java/com/google/android/exoplayer2/ext/ima/FakePlayer.java @@ -26,7 +26,6 @@ import java.util.ArrayList; /* package */ final class FakePlayer extends StubExoPlayer { private final ArrayList listeners; - private final Timeline.Window window; private final Timeline.Period period; private final Timeline timeline; @@ -41,7 +40,6 @@ import java.util.ArrayList; public FakePlayer() { listeners = new ArrayList<>(); - window = new Timeline.Window(); period = new Timeline.Period(); state = Player.STATE_IDLE; playWhenReady = true; @@ -151,16 +149,6 @@ import java.util.ArrayList; return 0; } - @Override - public int getNextWindowIndex() { - return C.INDEX_UNSET; - } - - @Override - public int getPreviousWindowIndex() { - return C.INDEX_UNSET; - } - @Override public long getDuration() { if (timeline.isEmpty()) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/BasePlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/BasePlayer.java new file mode 100644 index 0000000000..6ff0853d9b --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/BasePlayer.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2; + +import android.support.annotation.Nullable; +import com.google.android.exoplayer2.util.Util; + +/** Abstract base {@link Player} which implements common implementation independent methods. */ +public abstract class BasePlayer implements Player { + + protected final Timeline.Window window; + + public BasePlayer() { + window = new Timeline.Window(); + } + + @Override + public final void seekToDefaultPosition() { + seekToDefaultPosition(getCurrentWindowIndex()); + } + + @Override + public final void seekToDefaultPosition(int windowIndex) { + seekTo(windowIndex, /* positionMs= */ C.TIME_UNSET); + } + + @Override + public final void seekTo(long positionMs) { + seekTo(getCurrentWindowIndex(), positionMs); + } + + @Override + public final boolean hasPrevious() { + return getPreviousWindowIndex() != C.INDEX_UNSET; + } + + @Override + public final void previous() { + int previousWindowIndex = getPreviousWindowIndex(); + if (previousWindowIndex != C.INDEX_UNSET) { + seekToDefaultPosition(previousWindowIndex); + } + } + + @Override + public final boolean hasNext() { + return getNextWindowIndex() != C.INDEX_UNSET; + } + + @Override + public final void next() { + int nextWindowIndex = getPreviousWindowIndex(); + if (nextWindowIndex != C.INDEX_UNSET) { + seekToDefaultPosition(nextWindowIndex); + } + } + + @Override + public final void stop() { + stop(/* reset= */ false); + } + + @Override + public final int getNextWindowIndex() { + Timeline timeline = getCurrentTimeline(); + return timeline.isEmpty() + ? C.INDEX_UNSET + : timeline.getNextWindowIndex( + getCurrentWindowIndex(), getRepeatMode(), getShuffleModeEnabled()); + } + + @Override + public final int getPreviousWindowIndex() { + Timeline timeline = getCurrentTimeline(); + return timeline.isEmpty() + ? C.INDEX_UNSET + : timeline.getPreviousWindowIndex( + getCurrentWindowIndex(), getRepeatMode(), getShuffleModeEnabled()); + } + + @Override + @Nullable + public final Object getCurrentTag() { + int windowIndex = getCurrentWindowIndex(); + Timeline timeline = getCurrentTimeline(); + return windowIndex >= timeline.getWindowCount() + ? null + : timeline.getWindow(windowIndex, window, /* setTag= */ true).tag; + } + + @Override + public final int getBufferedPercentage() { + long position = getBufferedPosition(); + long duration = getDuration(); + return position == C.TIME_UNSET || duration == C.TIME_UNSET + ? 0 + : duration == 0 ? 100 : Util.constrainValue((int) ((position * 100) / duration), 0, 100); + } + + @Override + public final boolean isCurrentWindowDynamic() { + Timeline timeline = getCurrentTimeline(); + return !timeline.isEmpty() && timeline.getWindow(getCurrentWindowIndex(), window).isDynamic; + } + + @Override + public final boolean isCurrentWindowSeekable() { + Timeline timeline = getCurrentTimeline(); + return !timeline.isEmpty() && timeline.getWindow(getCurrentWindowIndex(), window).isSeekable; + } + + @Override + public final long getContentDuration() { + Timeline timeline = getCurrentTimeline(); + return timeline.isEmpty() + ? C.TIME_UNSET + : timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs(); + } +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java index 04bc1c611d..ffdadb78f7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlayerImpl.java @@ -40,10 +40,8 @@ import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArraySet; -/** - * An {@link ExoPlayer} implementation. Instances can be obtained from {@link ExoPlayerFactory}. - */ -/* package */ final class ExoPlayerImpl implements ExoPlayer { +/** An {@link ExoPlayer} implementation. Instances can be obtained from {@link ExoPlayerFactory}. */ +/* package */ final class ExoPlayerImpl extends BasePlayer implements ExoPlayer { private static final String TAG = "ExoPlayerImpl"; @@ -61,7 +59,6 @@ import java.util.concurrent.CopyOnWriteArraySet; private final ExoPlayerImplInternal internalPlayer; private final Handler internalPlayerHandler; private final CopyOnWriteArraySet listeners; - private final Timeline.Window window; private final Timeline.Period period; private final ArrayDeque pendingPlaybackInfoUpdates; @@ -118,7 +115,6 @@ import java.util.concurrent.CopyOnWriteArraySet; new RendererConfiguration[renderers.length], new TrackSelection[renderers.length], null); - window = new Timeline.Window(); period = new Timeline.Period(); playbackParameters = PlaybackParameters.DEFAULT; seekParameters = SeekParameters.DEFAULT; @@ -293,21 +289,6 @@ import java.util.concurrent.CopyOnWriteArraySet; return playbackInfo.isLoading; } - @Override - public void seekToDefaultPosition() { - seekToDefaultPosition(getCurrentWindowIndex()); - } - - @Override - public void seekToDefaultPosition(int windowIndex) { - seekTo(windowIndex, C.TIME_UNSET); - } - - @Override - public void seekTo(long positionMs) { - seekTo(getCurrentWindowIndex(), positionMs); - } - @Override public void seekTo(int windowIndex, long positionMs) { Timeline timeline = playbackInfo.timeline; @@ -377,19 +358,6 @@ import java.util.concurrent.CopyOnWriteArraySet; return seekParameters; } - @Override - public @Nullable Object getCurrentTag() { - int windowIndex = getCurrentWindowIndex(); - return windowIndex >= playbackInfo.timeline.getWindowCount() - ? null - : playbackInfo.timeline.getWindow(windowIndex, window, /* setTag= */ true).tag; - } - - @Override - public void stop() { - stop(/* reset= */ false); - } - @Override public void stop(boolean reset) { if (reset) { @@ -494,20 +462,6 @@ import java.util.concurrent.CopyOnWriteArraySet; } } - @Override - public int getNextWindowIndex() { - Timeline timeline = playbackInfo.timeline; - return timeline.isEmpty() ? C.INDEX_UNSET - : timeline.getNextWindowIndex(getCurrentWindowIndex(), repeatMode, shuffleModeEnabled); - } - - @Override - public int getPreviousWindowIndex() { - Timeline timeline = playbackInfo.timeline; - return timeline.isEmpty() ? C.INDEX_UNSET - : timeline.getPreviousWindowIndex(getCurrentWindowIndex(), repeatMode, shuffleModeEnabled); - } - @Override public long getDuration() { if (isPlayingAd()) { @@ -540,32 +494,11 @@ import java.util.concurrent.CopyOnWriteArraySet; return getContentBufferedPosition(); } - @Override - public int getBufferedPercentage() { - long position = getBufferedPosition(); - long duration = getDuration(); - return position == C.TIME_UNSET || duration == C.TIME_UNSET - ? 0 - : (duration == 0 ? 100 : Util.constrainValue((int) ((position * 100) / duration), 0, 100)); - } - @Override public long getTotalBufferedDuration() { return Math.max(0, C.usToMs(playbackInfo.totalBufferedDurationUs)); } - @Override - public boolean isCurrentWindowDynamic() { - Timeline timeline = playbackInfo.timeline; - return !timeline.isEmpty() && timeline.getWindow(getCurrentWindowIndex(), window).isDynamic; - } - - @Override - public boolean isCurrentWindowSeekable() { - Timeline timeline = playbackInfo.timeline; - return !timeline.isEmpty() && timeline.getWindow(getCurrentWindowIndex(), window).isSeekable; - } - @Override public boolean isPlayingAd() { return !shouldMaskPosition() && playbackInfo.periodId.isAd(); @@ -581,13 +514,6 @@ import java.util.concurrent.CopyOnWriteArraySet; return isPlayingAd() ? playbackInfo.periodId.adIndexInAdGroup : C.INDEX_UNSET; } - @Override - public long getContentDuration() { - return playbackInfo.timeline.isEmpty() - ? C.TIME_UNSET - : playbackInfo.timeline.getWindow(getCurrentWindowIndex(), window).getDurationMs(); - } - @Override public long getContentPosition() { if (isPlayingAd()) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 39f1655ab5..8517556887 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -64,7 +64,7 @@ import java.util.concurrent.CopyOnWriteArraySet; * be obtained from {@link ExoPlayerFactory}. */ @TargetApi(16) -public class SimpleExoPlayer +public class SimpleExoPlayer extends BasePlayer implements ExoPlayer, Player.AudioComponent, Player.VideoComponent, Player.TextComponent { /** @deprecated Use {@link com.google.android.exoplayer2.video.VideoListener}. */ @@ -927,27 +927,6 @@ public class SimpleExoPlayer return player.isLoading(); } - @Override - public void seekToDefaultPosition() { - verifyApplicationThread(); - analyticsCollector.notifySeekStarted(); - player.seekToDefaultPosition(); - } - - @Override - public void seekToDefaultPosition(int windowIndex) { - verifyApplicationThread(); - analyticsCollector.notifySeekStarted(); - player.seekToDefaultPosition(windowIndex); - } - - @Override - public void seekTo(long positionMs) { - verifyApplicationThread(); - analyticsCollector.notifySeekStarted(); - player.seekTo(positionMs); - } - @Override public void seekTo(int windowIndex, long positionMs) { verifyApplicationThread(); @@ -979,17 +958,6 @@ public class SimpleExoPlayer return player.getSeekParameters(); } - @Override - public @Nullable Object getCurrentTag() { - verifyApplicationThread(); - return player.getCurrentTag(); - } - - @Override - public void stop() { - stop(/* reset= */ false); - } - @Override public void stop(boolean reset) { verifyApplicationThread(); @@ -1092,18 +1060,6 @@ public class SimpleExoPlayer return player.getCurrentWindowIndex(); } - @Override - public int getNextWindowIndex() { - verifyApplicationThread(); - return player.getNextWindowIndex(); - } - - @Override - public int getPreviousWindowIndex() { - verifyApplicationThread(); - return player.getPreviousWindowIndex(); - } - @Override public long getDuration() { verifyApplicationThread(); @@ -1122,30 +1078,12 @@ public class SimpleExoPlayer return player.getBufferedPosition(); } - @Override - public int getBufferedPercentage() { - verifyApplicationThread(); - return player.getBufferedPercentage(); - } - @Override public long getTotalBufferedDuration() { verifyApplicationThread(); return player.getTotalBufferedDuration(); } - @Override - public boolean isCurrentWindowDynamic() { - verifyApplicationThread(); - return player.isCurrentWindowDynamic(); - } - - @Override - public boolean isCurrentWindowSeekable() { - verifyApplicationThread(); - return player.isCurrentWindowSeekable(); - } - @Override public boolean isPlayingAd() { verifyApplicationThread(); @@ -1164,12 +1102,6 @@ public class SimpleExoPlayer return player.getCurrentAdIndexInAdGroup(); } - @Override - public long getContentDuration() { - verifyApplicationThread(); - return player.getContentDuration(); - } - @Override public long getContentPosition() { verifyApplicationThread(); diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java index f1349c1158..156b573df8 100644 --- a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java +++ b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/StubExoPlayer.java @@ -16,7 +16,7 @@ package com.google.android.exoplayer2.testutil; import android.os.Looper; -import android.support.annotation.Nullable; +import com.google.android.exoplayer2.BasePlayer; import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.PlaybackParameters; @@ -32,7 +32,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray; * An abstract {@link ExoPlayer} implementation that throws {@link UnsupportedOperationException} * from every method. */ -public abstract class StubExoPlayer implements ExoPlayer { +public abstract class StubExoPlayer extends BasePlayer implements ExoPlayer { @Override public AudioComponent getAudioComponent() { @@ -129,21 +129,6 @@ public abstract class StubExoPlayer implements ExoPlayer { throw new UnsupportedOperationException(); } - @Override - public void seekToDefaultPosition() { - throw new UnsupportedOperationException(); - } - - @Override - public void seekToDefaultPosition(int windowIndex) { - throw new UnsupportedOperationException(); - } - - @Override - public void seekTo(long positionMs) { - throw new UnsupportedOperationException(); - } - @Override public void seekTo(int windowIndex, long positionMs) { throw new UnsupportedOperationException(); @@ -169,16 +154,6 @@ public abstract class StubExoPlayer implements ExoPlayer { throw new UnsupportedOperationException(); } - @Override - public @Nullable Object getCurrentTag() { - throw new UnsupportedOperationException(); - } - - @Override - public void stop() { - throw new UnsupportedOperationException(); - } - @Override public void stop(boolean resetStateAndPosition) { throw new UnsupportedOperationException(); @@ -248,16 +223,6 @@ public abstract class StubExoPlayer implements ExoPlayer { throw new UnsupportedOperationException(); } - @Override - public int getNextWindowIndex() { - throw new UnsupportedOperationException(); - } - - @Override - public int getPreviousWindowIndex() { - throw new UnsupportedOperationException(); - } - @Override public long getDuration() { throw new UnsupportedOperationException(); @@ -273,26 +238,11 @@ public abstract class StubExoPlayer implements ExoPlayer { throw new UnsupportedOperationException(); } - @Override - public int getBufferedPercentage() { - throw new UnsupportedOperationException(); - } - @Override public long getTotalBufferedDuration() { throw new UnsupportedOperationException(); } - @Override - public boolean isCurrentWindowDynamic() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isCurrentWindowSeekable() { - throw new UnsupportedOperationException(); - } - @Override public boolean isPlayingAd() { throw new UnsupportedOperationException(); @@ -308,11 +258,6 @@ public abstract class StubExoPlayer implements ExoPlayer { throw new UnsupportedOperationException(); } - @Override - public long getContentDuration() { - throw new UnsupportedOperationException(); - } - @Override public long getContentPosition() { throw new UnsupportedOperationException();