Make Cue implement Bundleable

In order to deliver Cue objects between different processes
(e.g. in Player#getCurrentCues), this CL makes it Bundleable.

PiperOrigin-RevId: 373524501
This commit is contained in:
klhyun 2021-05-13 07:36:53 +01:00 committed by Oliver Woodman
parent 5ff2d24fab
commit bec7b0041e
2 changed files with 201 additions and 1 deletions

View file

@ -17,11 +17,13 @@ package com.google.android.exoplayer2.text;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
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.Bundleable;
import com.google.android.exoplayer2.util.Assertions;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@ -31,7 +33,7 @@ import java.lang.annotation.RetentionPolicy;
// This class shouldn't be sub-classed. If a subtitle format needs additional fields, either they
// should be generic enough to be added here, or the format-specific decoder should pass the
// information around in a sidecar object.
public final class Cue {
public final class Cue implements Bundleable {
/** The empty cue. */
public static final Cue EMPTY = new Cue.Builder().setText("").build();
@ -859,4 +861,139 @@ public final class Cue {
shearDegrees);
}
}
// Bundleable implementation.
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({
FIELD_TEXT,
FIELD_TEXT_ALIGNMENT,
FIELD_MULTI_ROW_ALIGNMENT,
FIELD_BITMAP,
FIELD_LINE,
FIELD_LINE_TYPE,
FIELD_LINE_ANCHOR,
FIELD_POSITION,
FIELD_POSITION_ANCHOR,
FIELD_TEXT_SIZE_TYPE,
FIELD_TEXT_SIZE,
FIELD_SIZE,
FIELD_BITMAP_HEIGHT,
FIELD_WINDOW_COLOR,
FIELD_WINDOW_COLOR_SET,
FIELD_VERTICAL_TYPE,
FIELD_SHEAR_DEGREES
})
private @interface FieldNumber {}
private static final int FIELD_TEXT = 0;
private static final int FIELD_TEXT_ALIGNMENT = 1;
private static final int FIELD_MULTI_ROW_ALIGNMENT = 2;
private static final int FIELD_BITMAP = 3;
private static final int FIELD_LINE = 4;
private static final int FIELD_LINE_TYPE = 5;
private static final int FIELD_LINE_ANCHOR = 6;
private static final int FIELD_POSITION = 7;
private static final int FIELD_POSITION_ANCHOR = 8;
private static final int FIELD_TEXT_SIZE_TYPE = 9;
private static final int FIELD_TEXT_SIZE = 10;
private static final int FIELD_SIZE = 11;
private static final int FIELD_BITMAP_HEIGHT = 12;
private static final int FIELD_WINDOW_COLOR = 13;
private static final int FIELD_WINDOW_COLOR_SET = 14;
private static final int FIELD_VERTICAL_TYPE = 15;
private static final int FIELD_SHEAR_DEGREES = 16;
@Override
public Bundle toBundle() {
Bundle bundle = new Bundle();
bundle.putCharSequence(keyForField(FIELD_TEXT), text);
bundle.putSerializable(keyForField(FIELD_TEXT_ALIGNMENT), textAlignment);
bundle.putSerializable(keyForField(FIELD_MULTI_ROW_ALIGNMENT), multiRowAlignment);
// TODO(b/187804381): Use Util.scaleDownBitmap when it's added
bundle.putParcelable(keyForField(FIELD_BITMAP), bitmap);
bundle.putFloat(keyForField(FIELD_LINE), line);
bundle.putInt(keyForField(FIELD_LINE_TYPE), lineType);
bundle.putInt(keyForField(FIELD_LINE_ANCHOR), lineAnchor);
bundle.putFloat(keyForField(FIELD_POSITION), position);
bundle.putInt(keyForField(FIELD_POSITION_ANCHOR), positionAnchor);
bundle.putInt(keyForField(FIELD_TEXT_SIZE_TYPE), textSizeType);
bundle.putFloat(keyForField(FIELD_TEXT_SIZE), textSize);
bundle.putFloat(keyForField(FIELD_SIZE), size);
bundle.putFloat(keyForField(FIELD_BITMAP_HEIGHT), bitmapHeight);
bundle.putBoolean(keyForField(FIELD_WINDOW_COLOR_SET), windowColorSet);
bundle.putInt(keyForField(FIELD_WINDOW_COLOR), windowColor);
bundle.putInt(keyForField(FIELD_VERTICAL_TYPE), verticalType);
bundle.putFloat(keyForField(FIELD_SHEAR_DEGREES), shearDegrees);
return bundle;
}
public static final Creator<Cue> CREATOR = Cue::fromBundle;
private static final Cue fromBundle(Bundle bundle) {
Builder builder = new Builder();
@Nullable CharSequence text = bundle.getCharSequence(keyForField(FIELD_TEXT));
if (text != null) {
builder.setText(text);
}
@Nullable
Alignment textAlignment = (Alignment) bundle.getSerializable(keyForField(FIELD_TEXT_ALIGNMENT));
if (textAlignment != null) {
builder.setTextAlignment(textAlignment);
}
@Nullable
Alignment multiRowAlignment =
(Alignment) bundle.getSerializable(keyForField(FIELD_MULTI_ROW_ALIGNMENT));
if (multiRowAlignment != null) {
builder.setMultiRowAlignment(multiRowAlignment);
}
@Nullable Bitmap bitmap = bundle.getParcelable(keyForField(FIELD_BITMAP));
if (bitmap != null) {
builder.setBitmap(bitmap);
}
if (bundle.containsKey(keyForField(FIELD_LINE))
&& bundle.containsKey(keyForField(FIELD_LINE_TYPE))) {
builder.setLine(
bundle.getFloat(keyForField(FIELD_LINE)), bundle.getInt(keyForField(FIELD_LINE_TYPE)));
}
if (bundle.containsKey(keyForField(FIELD_LINE_ANCHOR))) {
builder.setLineAnchor(bundle.getInt(keyForField(FIELD_LINE_ANCHOR)));
}
if (bundle.containsKey(keyForField(FIELD_POSITION))) {
builder.setPosition(bundle.getFloat(keyForField(FIELD_POSITION)));
}
if (bundle.containsKey(keyForField(FIELD_POSITION_ANCHOR))) {
builder.setPositionAnchor(bundle.getInt(keyForField(FIELD_POSITION_ANCHOR)));
}
if (bundle.containsKey(keyForField(FIELD_TEXT_SIZE))
&& bundle.containsKey(keyForField(FIELD_TEXT_SIZE_TYPE))) {
builder.setTextSize(
bundle.getFloat(keyForField(FIELD_TEXT_SIZE)),
bundle.getInt(keyForField(FIELD_TEXT_SIZE_TYPE)));
}
if (bundle.containsKey(keyForField(FIELD_SIZE))) {
builder.setSize(bundle.getFloat(keyForField(FIELD_SIZE)));
}
if (bundle.containsKey(keyForField(FIELD_BITMAP_HEIGHT))) {
builder.setBitmapHeight(bundle.getFloat(keyForField(FIELD_BITMAP_HEIGHT)));
}
if (bundle.containsKey(keyForField(FIELD_WINDOW_COLOR))) {
builder.setWindowColor(bundle.getInt(keyForField(FIELD_WINDOW_COLOR)));
}
if (!bundle.getBoolean(keyForField(FIELD_WINDOW_COLOR_SET), /* defaultValue= */ false)) {
builder.clearWindowColor();
}
if (bundle.containsKey(keyForField(FIELD_VERTICAL_TYPE))) {
builder.setVerticalType(bundle.getInt(keyForField(FIELD_VERTICAL_TYPE)));
}
if (bundle.containsKey(keyForField(FIELD_SHEAR_DEGREES))) {
builder.setShearDegrees(bundle.getFloat(keyForField(FIELD_SHEAR_DEGREES)));
}
return builder.build();
}
private static String keyForField(@FieldNumber int field) {
return Integer.toString(field, Character.MAX_RADIX);
}
}

View file

@ -21,8 +21,11 @@ import static org.junit.Assert.assertThrows;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Parcel;
import android.text.Layout;
import android.text.SpannedString;
import android.text.TextUtils;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -105,4 +108,64 @@ public class CueTest {
.setBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888))
.build());
}
@Test
public void roundTripViaBundle_yieldsEqualInstance() {
Cue cue =
new Cue.Builder()
.setText(SpannedString.valueOf("text"))
.setTextAlignment(Layout.Alignment.ALIGN_CENTER)
.setMultiRowAlignment(Layout.Alignment.ALIGN_NORMAL)
.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)
.setVerticalType(Cue.VERTICAL_TYPE_RL)
.setShearDegrees(-15f)
.build();
Cue modifiedCue = parcelAndUnParcelCue(cue);
assertThat(TextUtils.equals(modifiedCue.text, cue.text)).isTrue();
assertThat(modifiedCue.textAlignment).isEqualTo(cue.textAlignment);
assertThat(modifiedCue.multiRowAlignment).isEqualTo(cue.multiRowAlignment);
assertThat(modifiedCue.bitmap).isNull();
assertThat(modifiedCue.bitmapHeight).isEqualTo(Cue.DIMEN_UNSET);
assertThat(modifiedCue.line).isEqualTo(cue.line);
assertThat(modifiedCue.lineType).isEqualTo(cue.lineType);
assertThat(modifiedCue.position).isEqualTo(cue.position);
assertThat(modifiedCue.positionAnchor).isEqualTo(cue.positionAnchor);
assertThat(modifiedCue.textSize).isEqualTo(cue.textSize);
assertThat(modifiedCue.textSizeType).isEqualTo(cue.textSizeType);
assertThat(modifiedCue.size).isEqualTo(cue.size);
assertThat(modifiedCue.windowColor).isEqualTo(cue.windowColor);
assertThat(modifiedCue.windowColorSet).isEqualTo(cue.windowColorSet);
assertThat(modifiedCue.verticalType).isEqualTo(cue.verticalType);
assertThat(modifiedCue.shearDegrees).isEqualTo(cue.shearDegrees);
}
@Test
public void roundTripViaBundle_withBitmap_yieldsEqualInstance() {
Cue cue =
new Cue.Builder().setBitmap(Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)).build();
Cue modifiedCue = parcelAndUnParcelCue(cue);
assertThat(modifiedCue.bitmap.sameAs(cue.bitmap)).isTrue();
assertThat(modifiedCue.bitmapHeight).isEqualTo(cue.bitmapHeight);
}
private static Cue parcelAndUnParcelCue(Cue cue) {
Parcel parcel = Parcel.obtain();
try {
parcel.writeBundle(cue.toBundle());
parcel.setDataPosition(0);
Bundle bundle = parcel.readBundle();
return Cue.CREATOR.fromBundle(bundle);
} finally {
parcel.recycle();
}
}
}