diff --git a/library/core/src/main/java/com/google/android/exoplayer2/text/Cue.java b/library/core/src/main/java/com/google/android/exoplayer2/text/Cue.java index 8880a76e1e..25b71d9410 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/text/Cue.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/text/Cue.java @@ -17,9 +17,12 @@ package com.google.android.exoplayer2.text; import android.graphics.Bitmap; import android.graphics.Color; +import android.text.Layout; import android.text.Layout.Alignment; +import androidx.annotation.ColorInt; import androidx.annotation.IntDef; import androidx.annotation.Nullable; +import com.google.android.exoplayer2.util.Assertions; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -240,7 +243,9 @@ public final class Cue { * @param height The height of the cue as a fraction of the viewport height, or {@link * #DIMEN_UNSET} if the bitmap should be displayed at its natural height for the specified * {@code width}. + * @deprecated Use {@link Builder}. */ + @Deprecated public Cue( Bitmap bitmap, float horizontalPosition, @@ -271,7 +276,9 @@ public final class Cue { * {@link #TYPE_UNSET} and whose dimension parameters are set to {@link #DIMEN_UNSET}. * * @param text See {@link #text}. + * @deprecated Use {@link Builder}. */ + @Deprecated public Cue(CharSequence text) { this( text, @@ -295,7 +302,9 @@ public final class Cue { * @param position See {@link #position}. * @param positionAnchor See {@link #positionAnchor}. * @param size See {@link #size}. + * @deprecated Use {@link Builder}. */ + @Deprecated public Cue( CharSequence text, @Nullable Alignment textAlignment, @@ -331,7 +340,9 @@ public final class Cue { * @param size See {@link #size}. * @param textSizeType See {@link #textSizeType}. * @param textSize See {@link #textSize}. + * @deprecated Use {@link Builder}. */ + @Deprecated public Cue( CharSequence text, @Nullable Alignment textAlignment, @@ -373,7 +384,9 @@ public final class Cue { * @param size See {@link #size}. * @param windowColorSet See {@link #windowColorSet}. * @param windowColor See {@link #windowColor}. + * @deprecated Use {@link Builder}. */ + @Deprecated public Cue( CharSequence text, @Nullable Alignment textAlignment, @@ -417,6 +430,12 @@ public final class Cue { float bitmapHeight, boolean windowColorSet, int windowColor) { + // Exactly one of text or bitmap should be set. + if (text == null) { + Assertions.checkNotNull(bitmap); + } else { + Assertions.checkArgument(bitmap == null); + } this.text = text; this.textAlignment = textAlignment; this.bitmap = bitmap; @@ -433,4 +452,225 @@ public final class Cue { this.textSize = textSize; } + /** A builder for {@link Cue} objects. */ + public static final class Builder { + @Nullable private CharSequence text; + @Nullable private Bitmap bitmap; + @Nullable private Alignment textAlignment; + private float line; + @LineType private int lineType; + @AnchorType private int lineAnchor; + private float position; + @AnchorType private int positionAnchor; + @TextSizeType private int textSizeType; + private float textSize; + private float size; + private float bitmapHeight; + private boolean windowColorSet; + @ColorInt private int windowColor; + + public Builder() { + text = null; + bitmap = null; + textAlignment = null; + line = DIMEN_UNSET; + lineType = TYPE_UNSET; + lineAnchor = TYPE_UNSET; + position = DIMEN_UNSET; + positionAnchor = TYPE_UNSET; + textSizeType = TYPE_UNSET; + textSize = DIMEN_UNSET; + size = DIMEN_UNSET; + bitmapHeight = DIMEN_UNSET; + windowColorSet = false; + windowColor = Color.BLACK; + } + + /** + * Sets the cue text. + * + *
Note that {@code text} may be decorated with styling spans. + * + * @see Cue#text + */ + public Builder setText(CharSequence text) { + this.text = text; + return this; + } + + /** Sets the cue image. */ + public Builder setBitmap(Bitmap bitmap) { + this.bitmap = bitmap; + return this; + } + + /** + * Sets the alignment of the cue text within the cue box. + * + *
Passing null means the alignment is undefined. + * + * @see Cue#textAlignment + */ + public Builder setTextAlignment(@Nullable Layout.Alignment textAlignment) { + this.textAlignment = textAlignment; + return this; + } + + /** + * Sets the position of the {@code lineAnchor} of the cue box within the viewport in the + * direction orthogonal to the writing direction. + * + *
The interpretation of the {@code line} depends on the value of {@code lineType}. + * + *
Note that it's particularly important to consider the effect of {@link #setLineAnchor(int) + * lineAnchor} when using {@link #LINE_TYPE_NUMBER}. + * + *
For the normal case of horizontal text, {@link #ANCHOR_TYPE_START}, {@link + * #ANCHOR_TYPE_MIDDLE} and {@link #ANCHOR_TYPE_END} correspond to the top, middle and bottom of + * the cue box respectively. + * + * @see Cue#lineAnchor + */ + public Builder setLineAnchor(@AnchorType int lineAnchor) { + this.lineAnchor = lineAnchor; + return this; + } + + /** + * Sets the fractional position of the {@link #setPositionAnchor(int) positionAnchor} of the cue + * box within the viewport in the direction orthogonal to {@link #setLine(float, int) line}. + * + *
For horizontal text, this is the horizontal position relative to the left of the viewport. + * Note that positioning is relative to the left of the viewport even in the case of + * right-to-left text. + * + * @see Cue#position + */ + public Builder setPosition(float position) { + this.position = position; + return this; + } + + /** + * Sets the cue box anchor positioned by {@link #setPosition(float) position}. + * + *
For the normal case of horizontal text, {@link #ANCHOR_TYPE_START}, {@link + * #ANCHOR_TYPE_MIDDLE} and {@link #ANCHOR_TYPE_END} correspond to the left, middle and right of + * the cue box respectively. + * + * @see Cue#positionAnchor + */ + public Builder setPositionAnchor(@AnchorType int positionAnchor) { + this.positionAnchor = positionAnchor; + return this; + } + + /** + * Sets the default text size type for this cue's text. + * + * @see Cue#textSize + * @see Cue#textSizeType + */ + public Builder setTextSize(float textSize, @TextSizeType int textSizeType) { + this.textSize = textSize; + this.textSizeType = textSizeType; + return this; + } + + /** + * Sets the size of the cue box in the writing direction specified as a fraction of the viewport + * size in that direction. + * + * @see Cue#textSize + * @see Cue#textSizeType + * @see Cue#size + */ + public Builder setSize(float size) { + this.size = size; + return this; + } + + /** + * Sets the bitmap height as a fraction of the of the viewport size. + * + * @see Cue#bitmapHeight + */ + public Builder setBitmapHeight(float bitmapHeight) { + this.bitmapHeight = bitmapHeight; + return this; + } + + /** + * Sets the fill color of the window. + * + *
Also sets {@link Cue#windowColorSet} to true. + * + * @see Cue#windowColor + * @see Cue#windowColorSet + */ + public Builder setWindowColor(@ColorInt int windowColor) { + this.windowColor = windowColor; + this.windowColorSet = true; + return this; + } + + /** Build the cue. */ + public Cue build() { + return new Cue( + text, + textAlignment, + bitmap, + line, + lineType, + lineAnchor, + position, + positionAnchor, + textSizeType, + textSize, + size, + bitmapHeight, + windowColorSet, + windowColor); + } + } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/text/CueTest.java b/library/core/src/test/java/com/google/android/exoplayer2/text/CueTest.java new file mode 100644 index 0000000000..bd1acdf02b --- /dev/null +++ b/library/core/src/test/java/com/google/android/exoplayer2/text/CueTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2019 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.text; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.text.Layout; +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Tests for {@link Cue}. */ +@RunWith(AndroidJUnit4.class) +public class CueTest { + + @Test + public void buildSucceeds() { + Cue cue = + new Cue.Builder() + .setText("text") + .setTextAlignment(Layout.Alignment.ALIGN_CENTER) + .setLine(5, Cue.LINE_TYPE_NUMBER) + .setLineAnchor(Cue.ANCHOR_TYPE_END) + .setPosition(0.4f) + .setPositionAnchor(Cue.ANCHOR_TYPE_MIDDLE) + .setTextSize(0.2f, Cue.TEXT_SIZE_TYPE_FRACTIONAL) + .setSize(0.8f) + .setWindowColor(Color.CYAN) + .build(); + + assertThat(cue.text).isEqualTo("text"); + assertThat(cue.textAlignment).isEqualTo(Layout.Alignment.ALIGN_CENTER); + assertThat(cue.line).isEqualTo(5); + assertThat(cue.lineType).isEqualTo(Cue.LINE_TYPE_NUMBER); + assertThat(cue.position).isEqualTo(0.4f); + assertThat(cue.positionAnchor).isEqualTo(Cue.ANCHOR_TYPE_MIDDLE); + assertThat(cue.textSize).isEqualTo(0.2f); + assertThat(cue.textSizeType).isEqualTo(Cue.TEXT_SIZE_TYPE_FRACTIONAL); + assertThat(cue.size).isEqualTo(0.8f); + assertThat(cue.windowColor).isEqualTo(Color.CYAN); + assertThat(cue.windowColorSet).isTrue(); + } + + @Test + public void buildWithNoTextOrBitmapFails() { + assertThrows(RuntimeException.class, () -> new Cue.Builder().build()); + } + + @Test + public void buildWithBothTextAndBitmapFails() { + assertThrows( + RuntimeException.class, + () -> + new Cue.Builder() + .setText("foo") + .setBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)) + .build()); + } +}