Make PlaybackException be able to de-serialize subclasses
Otherwise, Player clients would not be able to benefit from PlaybackException subclasses, like ExoPlaybackException. PiperOrigin-RevId: 378873767
This commit is contained in:
parent
f5dee4d30c
commit
c62e444c13
@ -27,6 +27,7 @@ import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/** Thrown when a non locally recoverable playback failure occurs. */
|
||||
public class PlaybackException extends Exception implements Bundleable {
|
||||
@ -340,6 +341,7 @@ public class PlaybackException extends Exception implements Bundleable {
|
||||
@IntDef(
|
||||
open = true,
|
||||
value = {
|
||||
FIELD_STRING_CLASS_NAME,
|
||||
FIELD_INT_ERROR_CODE,
|
||||
FIELD_LONG_TIMESTAMP_MS,
|
||||
FIELD_STRING_MESSAGE,
|
||||
@ -348,11 +350,12 @@ public class PlaybackException extends Exception implements Bundleable {
|
||||
})
|
||||
protected @interface FieldNumber {}
|
||||
|
||||
private static final int FIELD_INT_ERROR_CODE = 0;
|
||||
private static final int FIELD_LONG_TIMESTAMP_MS = 1;
|
||||
private static final int FIELD_STRING_MESSAGE = 2;
|
||||
private static final int FIELD_STRING_CAUSE_CLASS_NAME = 3;
|
||||
private static final int FIELD_STRING_CAUSE_MESSAGE = 4;
|
||||
private static final int FIELD_STRING_CLASS_NAME = 0;
|
||||
private static final int FIELD_INT_ERROR_CODE = 1;
|
||||
private static final int FIELD_LONG_TIMESTAMP_MS = 2;
|
||||
private static final int FIELD_STRING_MESSAGE = 3;
|
||||
private static final int FIELD_STRING_CAUSE_CLASS_NAME = 4;
|
||||
private static final int FIELD_STRING_CAUSE_MESSAGE = 5;
|
||||
|
||||
/**
|
||||
* Defines a minimum field id value for subclasses to use when implementing {@link #toBundle()}
|
||||
@ -364,12 +367,33 @@ public class PlaybackException extends Exception implements Bundleable {
|
||||
protected static final int FIELD_CUSTOM_ID_BASE = 1000;
|
||||
|
||||
/** Object that can create a {@link PlaybackException} from a {@link Bundle}. */
|
||||
public static final Creator<PlaybackException> CREATOR = PlaybackException::new;
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public static final Creator<PlaybackException> CREATOR =
|
||||
bundle -> {
|
||||
String className = bundle.getString(keyForField(FIELD_STRING_CLASS_NAME));
|
||||
if (className != null && !PlaybackException.class.getName().equals(className)) {
|
||||
try {
|
||||
Field creatorField = Class.forName(className).getField("CREATOR");
|
||||
// It is ok to pass null to Field.get for static fields.
|
||||
@SuppressWarnings("argument.type.incompatible")
|
||||
Creator<PlaybackException> creator =
|
||||
(Creator<PlaybackException>) creatorField.get(/* obj= */ null);
|
||||
if (creator != null) {
|
||||
return creator.fromBundle(bundle);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
// Failed to create an instance using the creator from the class with the given name.
|
||||
// Fall through and try to deserialize the PlaybackException fields only.
|
||||
}
|
||||
}
|
||||
return new PlaybackException(bundle);
|
||||
};
|
||||
|
||||
@CallSuper
|
||||
@Override
|
||||
public Bundle toBundle() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(keyForField(FIELD_STRING_CLASS_NAME), getClass().getName());
|
||||
bundle.putInt(keyForField(FIELD_INT_ERROR_CODE), errorCode);
|
||||
bundle.putLong(keyForField(FIELD_LONG_TIMESTAMP_MS), timestampMs);
|
||||
bundle.putString(keyForField(FIELD_STRING_MESSAGE), getMessage());
|
||||
|
@ -34,6 +34,14 @@ public class ExoPlaybackExceptionTest {
|
||||
assertThat(areExoPlaybackExceptionsEqual(before, after)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void roundTripViaBundle_usingPlaybackExceptionCreator_yieldsEqualInstance() {
|
||||
ExoPlaybackException before = ExoPlaybackException.createForRemote(/* message= */ "test");
|
||||
ExoPlaybackException after =
|
||||
(ExoPlaybackException) PlaybackException.CREATOR.fromBundle(before.toBundle());
|
||||
assertThat(areExoPlaybackExceptionsEqual(before, after)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void roundTripViaBundle_ofExoPlaybackExceptionTypeRenderer_yieldsEqualInstance() {
|
||||
ExoPlaybackException before =
|
||||
|
@ -54,11 +54,13 @@ public class PlaybackExceptionTest {
|
||||
/* timestampMs= */ 1000);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("0", 5001); // Error code
|
||||
bundle.putLong("1", 1000); // Timestamp.
|
||||
bundle.putString("2", "message");
|
||||
bundle.putString("3", expectedCause.getClass().getName());
|
||||
bundle.putString("4", "cause message");
|
||||
// We purposefully omit the class name to test that PlaybackException fields are deserialized,
|
||||
// even though it was not possible to create an instance using the class name in the bundle.
|
||||
bundle.putInt("1", 5001); // Error code
|
||||
bundle.putLong("2", 1000); // Timestamp.
|
||||
bundle.putString("3", "message");
|
||||
bundle.putString("4", expectedCause.getClass().getName());
|
||||
bundle.putString("5", "cause message");
|
||||
|
||||
assertPlaybackExceptionsAreEquivalent(
|
||||
expectedException, PlaybackException.CREATOR.fromBundle(bundle));
|
||||
@ -75,11 +77,12 @@ public class PlaybackExceptionTest {
|
||||
/* timestampMs= */ 2000);
|
||||
|
||||
Bundle bundle = exception.toBundle();
|
||||
assertThat(bundle.getInt("0")).isEqualTo(4002); // Error code.
|
||||
assertThat(bundle.getLong("1")).isEqualTo(2000); // Timestamp.
|
||||
assertThat(bundle.getString("2")).isEqualTo("message");
|
||||
assertThat(bundle.getString("3")).isEqualTo(cause.getClass().getName());
|
||||
assertThat(bundle.getString("4")).isEqualTo("cause message");
|
||||
assertThat(bundle.getString("0")).isEqualTo(PlaybackException.class.getName());
|
||||
assertThat(bundle.getInt("1")).isEqualTo(4002); // Error code.
|
||||
assertThat(bundle.getLong("2")).isEqualTo(2000); // Timestamp.
|
||||
assertThat(bundle.getString("3")).isEqualTo("message");
|
||||
assertThat(bundle.getString("4")).isEqualTo(cause.getClass().getName());
|
||||
assertThat(bundle.getString("5")).isEqualTo("cause message");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -93,11 +96,11 @@ public class PlaybackExceptionTest {
|
||||
/* timestampMs= */ 1000);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt("0", 5001); // Error code
|
||||
bundle.putLong("1", 1000); // Timestamp.
|
||||
bundle.putString("2", "message");
|
||||
bundle.putString("3", "invalid cause class name");
|
||||
bundle.putString("4", "cause message");
|
||||
bundle.putInt("1", 5001); // Error code
|
||||
bundle.putLong("2", 1000); // Timestamp.
|
||||
bundle.putString("3", "message");
|
||||
bundle.putString("4", "invalid cause class name");
|
||||
bundle.putString("5", "cause message");
|
||||
|
||||
assertPlaybackExceptionsAreEquivalent(
|
||||
expectedException, PlaybackException.CREATOR.fromBundle(bundle));
|
||||
|
Loading…
x
Reference in New Issue
Block a user