Commit 9d20a8d4 by andrewlewis Committed by Oliver Woodman

Add a custom time bar view.

Also add an isAd flag to Timeline.Period so that periods can be declared as
containing ads. The times of these periods are indicated using ad markers in
the new TimeBar.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=151116208
parent f4c33daf
...@@ -334,7 +334,7 @@ public final class ExoPlayerTest extends TestCase { ...@@ -334,7 +334,7 @@ public final class ExoPlayerTest extends TestCase {
public Period getPeriod(int periodIndex, Period period, boolean setIds) { public Period getPeriod(int periodIndex, Period period, boolean setIds) {
TimelineWindowDefinition windowDefinition = windowDefinitions[periodIndex]; TimelineWindowDefinition windowDefinition = windowDefinitions[periodIndex];
Object id = setIds ? periodIndex : null; Object id = setIds ? periodIndex : null;
return period.set(id, id, periodIndex, windowDefinition.durationUs, 0); return period.set(id, id, periodIndex, windowDefinition.durationUs, 0, false);
} }
@Override @Override
......
...@@ -383,18 +383,24 @@ public abstract class Timeline { ...@@ -383,18 +383,24 @@ public abstract class Timeline {
*/ */
public long durationUs; public long durationUs;
/**
* Whether this period contains an ad.
*/
public boolean isAd;
private long positionInWindowUs; private long positionInWindowUs;
/** /**
* Sets the data held by this period. * Sets the data held by this period.
*/ */
public Period set(Object id, Object uid, int windowIndex, long durationUs, public Period set(Object id, Object uid, int windowIndex, long durationUs,
long positionInWindowUs) { long positionInWindowUs, boolean isAd) {
this.id = id; this.id = id;
this.uid = uid; this.uid = uid;
this.windowIndex = windowIndex; this.windowIndex = windowIndex;
this.durationUs = durationUs; this.durationUs = durationUs;
this.positionInWindowUs = positionInWindowUs; this.positionInWindowUs = positionInWindowUs;
this.isAd = isAd;
return this; return this;
} }
......
...@@ -158,6 +158,7 @@ public final class LoopingMediaSource implements MediaSource { ...@@ -158,6 +158,7 @@ public final class LoopingMediaSource implements MediaSource {
int periodIndexOffset = loopCount * childPeriodCount; int periodIndexOffset = loopCount * childPeriodCount;
return childTimeline.getIndexOfPeriod(loopCountAndChildUid.second) + periodIndexOffset; return childTimeline.getIndexOfPeriod(loopCountAndChildUid.second) + periodIndexOffset;
} }
} }
} }
...@@ -99,7 +99,7 @@ public final class SinglePeriodTimeline extends Timeline { ...@@ -99,7 +99,7 @@ public final class SinglePeriodTimeline extends Timeline {
public Period getPeriod(int periodIndex, Period period, boolean setIds) { public Period getPeriod(int periodIndex, Period period, boolean setIds) {
Assertions.checkIndex(periodIndex, 0, 1); Assertions.checkIndex(periodIndex, 0, 1);
Object id = setIds ? ID : null; Object id = setIds ? ID : null;
return period.set(id, id, 0, periodDurationUs, -windowPositionInPeriodUs); return period.set(id, id, 0, periodDurationUs, -windowPositionInPeriodUs, false);
} }
@Override @Override
......
/*
* Copyright (C) 2016 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.util;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* An annotation for classes and interfaces that should not be open sourced.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
@ClosedSource(reason = "Not required")
public @interface ClosedSource {
String reason();
}
...@@ -45,6 +45,7 @@ import java.nio.charset.Charset; ...@@ -45,6 +45,7 @@ import java.nio.charset.Charset;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collections; import java.util.Collections;
import java.util.Formatter;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
...@@ -317,6 +318,18 @@ public final class Util { ...@@ -317,6 +318,18 @@ public final class Util {
* @param max The upper bound. * @param max The upper bound.
* @return The constrained value {@code Math.max(min, Math.min(value, max))}. * @return The constrained value {@code Math.max(min, Math.min(value, max))}.
*/ */
public static long constrainValue(long value, long min, long max) {
return Math.max(min, Math.min(value, max));
}
/**
* Constrains a value to the specified bounds.
*
* @param value The value to constrain.
* @param min The lower bound.
* @param max The upper bound.
* @return The constrained value {@code Math.max(min, Math.min(value, max))}.
*/
public static float constrainValue(float value, float min, float max) { public static float constrainValue(float value, float min, float max) {
return Math.max(min, Math.min(value, max)); return Math.max(min, Math.min(value, max));
} }
...@@ -836,6 +849,27 @@ public final class Util { ...@@ -836,6 +849,27 @@ public final class Util {
} }
/** /**
* Returns the specified millisecond time formatted as a string.
*
* @param builder The builder that {@code formatter} will write to.
* @param formatter The formatter.
* @param timeMs The time to format as a string, in milliseconds.
* @return The time formatted as a string.
*/
public static String getStringForTime(StringBuilder builder, Formatter formatter, long timeMs) {
if (timeMs == C.TIME_UNSET) {
timeMs = 0;
}
long totalSeconds = (timeMs + 500) / 1000;
long seconds = totalSeconds % 60;
long minutes = (totalSeconds / 60) % 60;
long hours = totalSeconds / 3600;
builder.setLength(0);
return hours > 0 ? formatter.format("%d:%02d:%02d", hours, minutes, seconds).toString()
: formatter.format("%02d:%02d", minutes, seconds).toString();
}
/**
* Maps a {@link C} {@code TRACK_TYPE_*} constant to the corresponding {@link C} * Maps a {@link C} {@code TRACK_TYPE_*} constant to the corresponding {@link C}
* {@code DEFAULT_*_BUFFER_SIZE} constant. * {@code DEFAULT_*_BUFFER_SIZE} constant.
* *
......
# Accessed via reflection in SubtitleDecoderFactory.DEFAULT
-keepclassmembers class com.google.android.exoplayer2.text.cea.Cea608Decoder {
public <init>(java.lang.String, int);
}
-keepclassmembers class com.google.android.exoplayer2.text.cea.Cea708Decoder {
public <init>(int);
}
...@@ -648,7 +648,7 @@ public final class DashMediaSource implements MediaSource { ...@@ -648,7 +648,7 @@ public final class DashMediaSource implements MediaSource {
+ Assertions.checkIndex(periodIndex, 0, manifest.getPeriodCount()) : null; + Assertions.checkIndex(periodIndex, 0, manifest.getPeriodCount()) : null;
return period.set(id, uid, 0, manifest.getPeriodDurationUs(periodIndex), return period.set(id, uid, 0, manifest.getPeriodDurationUs(periodIndex),
C.msToUs(manifest.getPeriod(periodIndex).startMs - manifest.getPeriod(0).startMs) C.msToUs(manifest.getPeriod(periodIndex).startMs - manifest.getPeriod(0).startMs)
- offsetInFirstPeriodUs); - offsetInFirstPeriodUs, false);
} }
@Override @Override
......
...@@ -528,6 +528,16 @@ public final class SimpleExoPlayerView extends FrameLayout { ...@@ -528,6 +528,16 @@ public final class SimpleExoPlayerView extends FrameLayout {
} }
/** /**
* Sets whether the time bar should show all windows, as opposed to just the current one.
*
* @param showMultiWindowTimeBar Whether to show all windows.
*/
public void setShowMultiWindowTimeBar(boolean showMultiWindowTimeBar) {
Assertions.checkState(controller != null);
controller.setShowMultiWindowTimeBar(showMultiWindowTimeBar);
}
/**
* Gets the view onto which video is rendered. This is either a {@link SurfaceView} (default) * Gets the view onto which video is rendered. This is either a {@link SurfaceView} (default)
* or a {@link TextureView} if the {@code use_texture_view} view attribute has been set to true. * or a {@link TextureView} if the {@code use_texture_view} view attribute has been set to true.
* *
......
/*
* Copyright (C) 2017 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.ui;
import android.support.annotation.Nullable;
import android.view.View;
/**
* Interface for time bar views that can display a playback position, buffered position, duration
* and ad markers, and that have a listener for scrubbing (seeking) events.
*/
public interface TimeBar {
/**
* @see View#isEnabled()
*/
void setEnabled(boolean enabled);
/**
* Sets the listener for the scrubbing events.
*
* @param listener The listener for scrubbing events.
*/
void setListener(OnScrubListener listener);
/**
* Sets the position increment for key presses and accessibility actions, in milliseconds.
* <p>
* Clears any increment specified in a preceding call to {@link #setKeyCountIncrement(int)}.
*
* @param time The time increment, in milliseconds.
*/
void setKeyTimeIncrement(long time);
/**
* Sets the position increment for key presses and accessibility actions, as a number of
* increments that divide the duration of the media. For example, passing 20 will cause key
* presses to increment/decrement the position by 1/20th of the duration (if known).
* <p>
* Clears any increment specified in a preceding call to {@link #setKeyTimeIncrement(long)}.
*
* @param count The number of increments that divide the duration of the media.
*/
void setKeyCountIncrement(int count);
/**
* Sets the current position.
*
* @param position The current position to show, in milliseconds.
*/
void setPosition(long position);
/**
* Sets the buffered position.
*
* @param bufferedPosition The current buffered position to show, in milliseconds.
*/
void setBufferedPosition(long bufferedPosition);
/**
* Sets the duration.
*
* @param duration The duration to show, in milliseconds.
*/
void setDuration(long duration);
/**
* Sets the times of ad breaks.
*
* @param adBreakTimesMs An array where the first {@code adBreakCount} elements are the times of
* ad breaks in milliseconds. May be {@code null} if there are no ad breaks.
* @param adBreakCount The number of ad breaks.
*/
void setAdBreakTimesMs(@Nullable long[] adBreakTimesMs, int adBreakCount);
/**
* Listener for scrubbing events.
*/
interface OnScrubListener {
/**
* Called when the user starts moving the scrubber.
*
* @param timeBar The time bar.
*/
void onScrubStart(TimeBar timeBar);
/**
* Called when the user moves the scrubber.
*
* @param timeBar The time bar.
* @param position The position of the scrubber, in milliseconds.
*/
void onScrubMove(TimeBar timeBar, long position);
/**
* Called when the user stops moving the scrubber.
*
* @param timeBar The time bar.
* @param position The position of the scrubber, in milliseconds.
* @param canceled Whether scrubbing was canceled.
*/
void onScrubStop(TimeBar timeBar, long position, boolean canceled);
}
}
...@@ -65,12 +65,11 @@ ...@@ -65,12 +65,11 @@
android:includeFontPadding="false" android:includeFontPadding="false"
android:textColor="#FFBEBEBE"/> android:textColor="#FFBEBEBE"/>
<SeekBar android:id="@id/exo_progress" <com.google.android.exoplayer2.ui.DefaultTimeBar
android:id="@id/exo_progress"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_weight="1" android:layout_weight="1"
android:layout_height="32dp" android:layout_height="24dp"/>
android:focusable="false"
style="?android:attr/progressBarStyleHorizontal"/>
<TextView android:id="@id/exo_duration" <TextView android:id="@id/exo_duration"
android:layout_width="wrap_content" android:layout_width="wrap_content"
......
...@@ -59,4 +59,16 @@ ...@@ -59,4 +59,16 @@
<attr name="controller_layout_id"/> <attr name="controller_layout_id"/>
</declare-styleable> </declare-styleable>
<declare-styleable name="DefaultTimeBar">
<attr name="bar_height" format="dimension"/>
<attr name="touch_target_height" format="dimension"/>
<attr name="ad_marker_width" format="dimension"/>
<attr name="scrubber_enabled_size" format="dimension"/>
<attr name="scrubber_disabled_size" format="dimension"/>
<attr name="scrubber_dragged_size" format="dimension"/>
<attr name="played_color" format="color"/>
<attr name="buffered_color" format="color"/>
<attr name="ad_marker_color" format="color"/>
</declare-styleable>
</resources> </resources>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment