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.Documented;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
/** Thrown when a non locally recoverable playback failure occurs. */
|
/** Thrown when a non locally recoverable playback failure occurs. */
|
||||||
public class PlaybackException extends Exception implements Bundleable {
|
public class PlaybackException extends Exception implements Bundleable {
|
||||||
@ -340,6 +341,7 @@ public class PlaybackException extends Exception implements Bundleable {
|
|||||||
@IntDef(
|
@IntDef(
|
||||||
open = true,
|
open = true,
|
||||||
value = {
|
value = {
|
||||||
|
FIELD_STRING_CLASS_NAME,
|
||||||
FIELD_INT_ERROR_CODE,
|
FIELD_INT_ERROR_CODE,
|
||||||
FIELD_LONG_TIMESTAMP_MS,
|
FIELD_LONG_TIMESTAMP_MS,
|
||||||
FIELD_STRING_MESSAGE,
|
FIELD_STRING_MESSAGE,
|
||||||
@ -348,11 +350,12 @@ public class PlaybackException extends Exception implements Bundleable {
|
|||||||
})
|
})
|
||||||
protected @interface FieldNumber {}
|
protected @interface FieldNumber {}
|
||||||
|
|
||||||
private static final int FIELD_INT_ERROR_CODE = 0;
|
private static final int FIELD_STRING_CLASS_NAME = 0;
|
||||||
private static final int FIELD_LONG_TIMESTAMP_MS = 1;
|
private static final int FIELD_INT_ERROR_CODE = 1;
|
||||||
private static final int FIELD_STRING_MESSAGE = 2;
|
private static final int FIELD_LONG_TIMESTAMP_MS = 2;
|
||||||
private static final int FIELD_STRING_CAUSE_CLASS_NAME = 3;
|
private static final int FIELD_STRING_MESSAGE = 3;
|
||||||
private static final int FIELD_STRING_CAUSE_MESSAGE = 4;
|
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()}
|
* 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;
|
protected static final int FIELD_CUSTOM_ID_BASE = 1000;
|
||||||
|
|
||||||
/** Object that can create a {@link PlaybackException} from a {@link Bundle}. */
|
/** 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
|
@CallSuper
|
||||||
@Override
|
@Override
|
||||||
public Bundle toBundle() {
|
public Bundle toBundle() {
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putString(keyForField(FIELD_STRING_CLASS_NAME), getClass().getName());
|
||||||
bundle.putInt(keyForField(FIELD_INT_ERROR_CODE), errorCode);
|
bundle.putInt(keyForField(FIELD_INT_ERROR_CODE), errorCode);
|
||||||
bundle.putLong(keyForField(FIELD_LONG_TIMESTAMP_MS), timestampMs);
|
bundle.putLong(keyForField(FIELD_LONG_TIMESTAMP_MS), timestampMs);
|
||||||
bundle.putString(keyForField(FIELD_STRING_MESSAGE), getMessage());
|
bundle.putString(keyForField(FIELD_STRING_MESSAGE), getMessage());
|
||||||
|
@ -34,6 +34,14 @@ public class ExoPlaybackExceptionTest {
|
|||||||
assertThat(areExoPlaybackExceptionsEqual(before, after)).isTrue();
|
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
|
@Test
|
||||||
public void roundTripViaBundle_ofExoPlaybackExceptionTypeRenderer_yieldsEqualInstance() {
|
public void roundTripViaBundle_ofExoPlaybackExceptionTypeRenderer_yieldsEqualInstance() {
|
||||||
ExoPlaybackException before =
|
ExoPlaybackException before =
|
||||||
|
@ -54,11 +54,13 @@ public class PlaybackExceptionTest {
|
|||||||
/* timestampMs= */ 1000);
|
/* timestampMs= */ 1000);
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putInt("0", 5001); // Error code
|
// We purposefully omit the class name to test that PlaybackException fields are deserialized,
|
||||||
bundle.putLong("1", 1000); // Timestamp.
|
// even though it was not possible to create an instance using the class name in the bundle.
|
||||||
bundle.putString("2", "message");
|
bundle.putInt("1", 5001); // Error code
|
||||||
bundle.putString("3", expectedCause.getClass().getName());
|
bundle.putLong("2", 1000); // Timestamp.
|
||||||
bundle.putString("4", "cause message");
|
bundle.putString("3", "message");
|
||||||
|
bundle.putString("4", expectedCause.getClass().getName());
|
||||||
|
bundle.putString("5", "cause message");
|
||||||
|
|
||||||
assertPlaybackExceptionsAreEquivalent(
|
assertPlaybackExceptionsAreEquivalent(
|
||||||
expectedException, PlaybackException.CREATOR.fromBundle(bundle));
|
expectedException, PlaybackException.CREATOR.fromBundle(bundle));
|
||||||
@ -75,11 +77,12 @@ public class PlaybackExceptionTest {
|
|||||||
/* timestampMs= */ 2000);
|
/* timestampMs= */ 2000);
|
||||||
|
|
||||||
Bundle bundle = exception.toBundle();
|
Bundle bundle = exception.toBundle();
|
||||||
assertThat(bundle.getInt("0")).isEqualTo(4002); // Error code.
|
assertThat(bundle.getString("0")).isEqualTo(PlaybackException.class.getName());
|
||||||
assertThat(bundle.getLong("1")).isEqualTo(2000); // Timestamp.
|
assertThat(bundle.getInt("1")).isEqualTo(4002); // Error code.
|
||||||
assertThat(bundle.getString("2")).isEqualTo("message");
|
assertThat(bundle.getLong("2")).isEqualTo(2000); // Timestamp.
|
||||||
assertThat(bundle.getString("3")).isEqualTo(cause.getClass().getName());
|
assertThat(bundle.getString("3")).isEqualTo("message");
|
||||||
assertThat(bundle.getString("4")).isEqualTo("cause message");
|
assertThat(bundle.getString("4")).isEqualTo(cause.getClass().getName());
|
||||||
|
assertThat(bundle.getString("5")).isEqualTo("cause message");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -93,11 +96,11 @@ public class PlaybackExceptionTest {
|
|||||||
/* timestampMs= */ 1000);
|
/* timestampMs= */ 1000);
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
Bundle bundle = new Bundle();
|
||||||
bundle.putInt("0", 5001); // Error code
|
bundle.putInt("1", 5001); // Error code
|
||||||
bundle.putLong("1", 1000); // Timestamp.
|
bundle.putLong("2", 1000); // Timestamp.
|
||||||
bundle.putString("2", "message");
|
bundle.putString("3", "message");
|
||||||
bundle.putString("3", "invalid cause class name");
|
bundle.putString("4", "invalid cause class name");
|
||||||
bundle.putString("4", "cause message");
|
bundle.putString("5", "cause message");
|
||||||
|
|
||||||
assertPlaybackExceptionsAreEquivalent(
|
assertPlaybackExceptionsAreEquivalent(
|
||||||
expectedException, PlaybackException.CREATOR.fromBundle(bundle));
|
expectedException, PlaybackException.CREATOR.fromBundle(bundle));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user