diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/ActionFile.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/ActionFile.java
index 0724755ac7..e37e09a090 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/offline/ActionFile.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/ActionFile.java
@@ -29,6 +29,8 @@ import java.io.InputStream;
*/
public final class ActionFile {
+ /* package */ static final int VERSION = 0;
+
private final AtomicFile atomicFile;
private final File actionFile;
@@ -56,13 +58,13 @@ public final class ActionFile {
inputStream = atomicFile.openRead();
DataInputStream dataInputStream = new DataInputStream(inputStream);
int version = dataInputStream.readInt();
- if (version > DownloadAction.MASTER_VERSION) {
- throw new IOException("Not supported action file version: " + version);
+ if (version > VERSION) {
+ throw new IOException("Unsupported action file version: " + version);
}
int actionCount = dataInputStream.readInt();
DownloadAction[] actions = new DownloadAction[actionCount];
for (int i = 0; i < actionCount; i++) {
- actions[i] = DownloadAction.deserializeFromStream(deserializers, dataInputStream, version);
+ actions[i] = DownloadAction.deserializeFromStream(deserializers, dataInputStream);
}
return actions;
} finally {
@@ -80,7 +82,7 @@ public final class ActionFile {
DataOutputStream output = null;
try {
output = new DataOutputStream(atomicFile.startWrite());
- output.writeInt(DownloadAction.MASTER_VERSION);
+ output.writeInt(VERSION);
output.writeInt(downloadActions.length);
for (DownloadAction action : downloadActions) {
DownloadAction.serializeToStream(action, output);
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadAction.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadAction.java
index 9c00534aeb..126a42cef5 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadAction.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadAction.java
@@ -26,29 +26,23 @@ import java.io.OutputStream;
/** Contains the necessary parameters for a download or remove action. */
public abstract class DownloadAction {
- /**
- * Master version for all {@link DownloadAction} serialization/deserialization implementations. On
- * each change on any {@link DownloadAction} serialization format this version needs to be
- * increased.
- */
- public static final int MASTER_VERSION = 0;
-
/** Used to deserialize {@link DownloadAction}s. */
public abstract static class Deserializer {
- public String type;
+ public final String type;
+ public final int version;
- public Deserializer(String type) {
+ public Deserializer(String type, int version) {
this.type = type;
+ this.version = version;
}
/**
* Deserializes an action from the {@code input}.
*
- * @param version Version of the data.
- * @param input DataInputStream to read data from.
+ * @param version The version of the serialized action.
+ * @param input The stream from which to read the action.
* @see DownloadAction#writeToStream(DataOutputStream)
- * @see DownloadAction#MASTER_VERSION
*/
public abstract DownloadAction readFromStream(int version, DataInputStream input)
throws IOException;
@@ -62,42 +56,23 @@ public abstract class DownloadAction {
*
The caller is responsible for closing the given {@link InputStream}.
*
* @param deserializers {@link Deserializer}s for supported actions.
- * @param input Input stream to read serialized data.
+ * @param input The stream from which to read the action.
* @return The deserialized action.
* @throws IOException If there is an IO error reading from {@code input}, or if the action type
* isn't supported by any of the {@code deserializers}.
*/
public static DownloadAction deserializeFromStream(
Deserializer[] deserializers, InputStream input) throws IOException {
- return deserializeFromStream(deserializers, input, MASTER_VERSION);
- }
-
- /**
- * Deserializes one {@code action} which was serialized by {@link
- * #serializeToStream(DownloadAction, OutputStream)} from the {@code input} using one of the
- * {@link Deserializer}s which supports the type of the action.
- *
- *
The caller is responsible for closing the given {@link InputStream}.
- *
- * @param deserializers {@link Deserializer}s for supported actions.
- * @param input Input stream to read serialized data.
- * @param version Master version of the serialization. See {@link DownloadAction#MASTER_VERSION}.
- * @return The deserialized action.
- * @throws IOException If there is an IO error from {@code input}.
- * @throws DownloadException If the action type isn't supported by any of the {@code
- * deserializers}.
- */
- public static DownloadAction deserializeFromStream(
- Deserializer[] deserializers, InputStream input, int version) throws IOException {
// Don't close the stream as it closes the underlying stream too.
DataInputStream dataInputStream = new DataInputStream(input);
String type = dataInputStream.readUTF();
+ int version = dataInputStream.readInt();
for (Deserializer deserializer : deserializers) {
- if (type.equals(deserializer.type)) {
+ if (type.equals(deserializer.type) && deserializer.version >= version) {
return deserializer.readFromStream(version, dataInputStream);
}
}
- throw new DownloadException("No Deserializer can be found to parse the data.");
+ throw new DownloadException("No deserializer found for:" + type + ", " + version);
}
/** Serializes {@code action} type and data into the {@code output}. */
@@ -106,12 +81,15 @@ public abstract class DownloadAction {
// Don't close the stream as it closes the underlying stream too.
DataOutputStream dataOutputStream = new DataOutputStream(output);
dataOutputStream.writeUTF(action.type);
+ dataOutputStream.writeInt(action.version);
action.writeToStream(dataOutputStream);
dataOutputStream.flush();
}
/** The type of the action. */
public final String type;
+ /** The action version. */
+ public final int version;
/** Whether this is a remove action. If false, this is a download action. */
public final boolean isRemoveAction;
/** Custom data for this action. May be the empty string if no custom data was specified. */
@@ -119,11 +97,14 @@ public abstract class DownloadAction {
/**
* @param type The type of the action.
+ * @param version The action version.
* @param isRemoveAction Whether this is a remove action. If false, this is a download action.
* @param data Optional custom data for this action. If null, an empty string is used.
*/
- protected DownloadAction(String type, boolean isRemoveAction, @Nullable String data) {
+ protected DownloadAction(
+ String type, int version, boolean isRemoveAction, @Nullable String data) {
this.type = type;
+ this.version = version;
this.isRemoveAction = isRemoveAction;
this.data = data != null ? data : "";
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloadAction.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloadAction.java
index 99c21b47cf..4ccca775ef 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloadAction.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/ProgressiveDownloadAction.java
@@ -28,9 +28,10 @@ import java.io.IOException;
public final class ProgressiveDownloadAction extends DownloadAction {
private static final String TYPE = "ProgressiveDownloadAction";
+ private static final int VERSION = 0;
public static final Deserializer DESERIALIZER =
- new Deserializer(TYPE) {
+ new Deserializer(TYPE, VERSION) {
@Override
public ProgressiveDownloadAction readFromStream(int version, DataInputStream input)
throws IOException {
@@ -54,7 +55,7 @@ public final class ProgressiveDownloadAction extends DownloadAction {
*/
public ProgressiveDownloadAction(
boolean isRemoveAction, @Nullable String data, Uri uri, @Nullable String customCacheKey) {
- super(TYPE, isRemoveAction, data);
+ super(TYPE, VERSION, isRemoveAction, data);
this.uri = Assertions.checkNotNull(uri);
this.customCacheKey = customCacheKey;
}
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloadAction.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloadAction.java
index 453a744de6..c51393fc44 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloadAction.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/SegmentDownloadAction.java
@@ -37,8 +37,8 @@ public abstract class SegmentDownloadAction extends Downlo
*/
protected abstract static class SegmentDownloadActionDeserializer extends Deserializer {
- public SegmentDownloadActionDeserializer(String type) {
- super(type);
+ public SegmentDownloadActionDeserializer(String type, int version) {
+ super(type, version);
}
@Override
@@ -71,15 +71,21 @@ public abstract class SegmentDownloadAction extends Downlo
/**
* @param type The type of the action.
- * @param data Optional custom data for this action. If null, an empty string is used.
+ * @param version The action version.
* @param isRemoveAction Whether the data will be removed. If {@code false} it will be downloaded.
+ * @param data Optional custom data for this action. If null, an empty string is used.
* @param manifestUri The {@link Uri} of the manifest to be downloaded.
* @param keys Keys of representations to be downloaded. If empty, all representations are
* downloaded. If {@code removeAction} is true, {@code keys} must be an empty array.
*/
protected SegmentDownloadAction(
- String type, boolean isRemoveAction, @Nullable String data, Uri manifestUri, K[] keys) {
- super(type, isRemoveAction, data);
+ String type,
+ int version,
+ boolean isRemoveAction,
+ @Nullable String data,
+ Uri manifestUri,
+ K[] keys) {
+ super(type, version, isRemoveAction, data);
this.manifestUri = manifestUri;
if (isRemoveAction) {
Assertions.checkArgument(keys.length == 0);
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/ActionFileTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/ActionFileTest.java
index 24fcf487e9..3fd794f16b 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/offline/ActionFileTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/ActionFileTest.java
@@ -63,7 +63,7 @@ public class ActionFileTest {
@Test
public void testLoadIncompleteHeaderThrowsIOException() throws Exception {
try {
- loadActions(new Object[] {DownloadAction.MASTER_VERSION});
+ loadActions(new Object[] {ActionFile.VERSION});
Assert.fail();
} catch (IOException e) {
// Expected exception.
@@ -72,8 +72,7 @@ public class ActionFileTest {
@Test
public void testLoadCompleteHeaderZeroAction() throws Exception {
- DownloadAction[] actions =
- loadActions(new Object[] {DownloadAction.MASTER_VERSION, /*action count*/0});
+ DownloadAction[] actions = loadActions(new Object[] {ActionFile.VERSION, 0});
assertThat(actions).isNotNull();
assertThat(actions).hasLength(0);
}
@@ -83,12 +82,16 @@ public class ActionFileTest {
DownloadAction[] actions =
loadActions(
new Object[] {
- DownloadAction.MASTER_VERSION, /*action count*/ 1, /*action 1*/ "type2", "321"
+ ActionFile.VERSION,
+ 1, // Action count
+ "type2", // Action 1
+ FakeDownloadAction.VERSION,
+ "321"
},
new FakeDeserializer("type2"));
assertThat(actions).isNotNull();
assertThat(actions).hasLength(1);
- assertAction(actions[0], "type2", DownloadAction.MASTER_VERSION, "321");
+ assertAction(actions[0], "type2", FakeDownloadAction.VERSION, "321");
}
@Test
@@ -96,26 +99,53 @@ public class ActionFileTest {
DownloadAction[] actions =
loadActions(
new Object[] {
- DownloadAction.MASTER_VERSION, /*action count*/
- 2, /*action 1*/
- "type1",
+ ActionFile.VERSION,
+ 2, // Action count
+ "type1", // Action 1
+ FakeDownloadAction.VERSION,
"123",
- /*action 2*/ "type2",
+ "type2", // Action 2
+ FakeDownloadAction.VERSION,
"321"
- }, // Action 2
+ },
new FakeDeserializer("type1"),
new FakeDeserializer("type2"));
assertThat(actions).isNotNull();
assertThat(actions).hasLength(2);
- assertAction(actions[0], "type1", DownloadAction.MASTER_VERSION, "123");
- assertAction(actions[1], "type2", DownloadAction.MASTER_VERSION, "321");
+ assertAction(actions[0], "type1", FakeDownloadAction.VERSION, "123");
+ assertAction(actions[1], "type2", FakeDownloadAction.VERSION, "321");
}
@Test
public void testLoadNotSupportedVersion() throws Exception {
try {
- loadActions(new Object[] {DownloadAction.MASTER_VERSION + 1, /*action count*/1,
- /*action 1*/"type2", 321}, new FakeDeserializer("type2"));
+ loadActions(
+ new Object[] {
+ ActionFile.VERSION + 1,
+ 1, // Action count
+ "type2", // Action 1
+ FakeDownloadAction.VERSION,
+ 321
+ },
+ new FakeDeserializer("type2"));
+ Assert.fail();
+ } catch (IOException e) {
+ // Expected exception.
+ }
+ }
+
+ @Test
+ public void testLoadNotSupportedActionVersion() throws Exception {
+ try {
+ loadActions(
+ new Object[] {
+ ActionFile.VERSION,
+ 1, // Action count
+ "type2", // Action 1
+ FakeDownloadAction.VERSION + 1,
+ 321
+ },
+ new FakeDeserializer("type2"));
Assert.fail();
} catch (IOException e) {
// Expected exception.
@@ -125,8 +155,15 @@ public class ActionFileTest {
@Test
public void testLoadNotSupportedType() throws Exception {
try {
- loadActions(new Object[] {DownloadAction.MASTER_VERSION, /*action count*/1,
- /*action 1*/"type2", 321}, new FakeDeserializer("type1"));
+ loadActions(
+ new Object[] {
+ ActionFile.VERSION,
+ 1, // Action count
+ "type2", // Action 1
+ FakeDownloadAction.VERSION,
+ 321
+ },
+ new FakeDeserializer("type1"));
Assert.fail();
} catch (DownloadException e) {
// Expected exception.
@@ -142,8 +179,7 @@ public class ActionFileTest {
public void testStoreAndLoadActions() throws Exception {
doTestSerializationRoundTrip(
new DownloadAction[] {
- new FakeDownloadAction("type1", DownloadAction.MASTER_VERSION, "123"),
- new FakeDownloadAction("type2", DownloadAction.MASTER_VERSION, "321"),
+ new FakeDownloadAction("type1", "123"), new FakeDownloadAction("type2", "321"),
},
new FakeDeserializer("type1"),
new FakeDeserializer("type2"));
@@ -186,22 +222,21 @@ public class ActionFileTest {
private static class FakeDeserializer extends Deserializer {
FakeDeserializer(String type) {
- super(type);
+ super(type, FakeDownloadAction.VERSION);
}
@Override
public DownloadAction readFromStream(int version, DataInputStream input) throws IOException {
- return new FakeDownloadAction(type, version, input.readUTF());
+ return new FakeDownloadAction(type, input.readUTF());
}
}
private static class FakeDownloadAction extends DownloadAction {
- public final int version;
+ public static final int VERSION = 0;
- private FakeDownloadAction(String type, int version, String data) {
- super(type, false, data);
- this.version = version;
+ private FakeDownloadAction(String type, String data) {
+ super(type, VERSION, /* isRemoveAction= */ false, data);
}
@Override
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java
index 6f0af064a0..53cb7e3cdf 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java
@@ -535,7 +535,7 @@ public class DownloadManagerTest {
private final BlockingQueue states;
private FakeDownloadAction(boolean isRemoveAction, @Nullable String mediaId) {
- super("FakeDownloadAction", isRemoveAction, mediaId);
+ super("FakeDownloadAction", /* version= */ 0, isRemoveAction, mediaId);
this.mediaId = mediaId;
this.downloader = new FakeDownloader(isRemoveAction);
this.states = new ArrayBlockingQueue<>(10);
diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/ProgressiveDownloadActionTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/ProgressiveDownloadActionTest.java
index f93c79c0f3..81e061b3df 100644
--- a/library/core/src/test/java/com/google/android/exoplayer2/offline/ProgressiveDownloadActionTest.java
+++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/ProgressiveDownloadActionTest.java
@@ -153,18 +153,19 @@ public class ProgressiveDownloadActionTest {
assertThat(action2.isSameMedia(action1)).isFalse();
}
- private static void doTestSerializationRoundTrip(ProgressiveDownloadAction action1)
+ private static void doTestSerializationRoundTrip(ProgressiveDownloadAction action)
throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(out);
- action1.writeToStream(output);
+ DownloadAction.serializeToStream(action, output);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
DataInputStream input = new DataInputStream(in);
DownloadAction action2 =
- ProgressiveDownloadAction.DESERIALIZER.readFromStream(DownloadAction.MASTER_VERSION, input);
+ DownloadAction.deserializeFromStream(
+ new DownloadAction.Deserializer[] {ProgressiveDownloadAction.DESERIALIZER}, input);
- assertThat(action2).isEqualTo(action1);
+ assertThat(action2).isEqualTo(action);
}
}
diff --git a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloadAction.java b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloadAction.java
index 0c5e5a01af..61e063cf91 100644
--- a/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloadAction.java
+++ b/library/dash/src/main/java/com/google/android/exoplayer2/source/dash/offline/DashDownloadAction.java
@@ -29,9 +29,10 @@ import java.io.IOException;
public final class DashDownloadAction extends SegmentDownloadAction {
private static final String TYPE = "DashDownloadAction";
+ private static final int VERSION = 0;
public static final Deserializer DESERIALIZER =
- new SegmentDownloadActionDeserializer(TYPE) {
+ new SegmentDownloadActionDeserializer(TYPE, VERSION) {
@Override
protected RepresentationKey readKey(DataInputStream input) throws IOException {
@@ -51,11 +52,12 @@ public final class DashDownloadAction extends SegmentDownloadAction {
private static final String TYPE = "HlsDownloadAction";
+ private static final int VERSION = 0;
public static final Deserializer DESERIALIZER =
- new SegmentDownloadActionDeserializer(TYPE) {
+ new SegmentDownloadActionDeserializer(TYPE, VERSION) {
@Override
protected RenditionKey readKey(DataInputStream input) throws IOException {
@@ -51,11 +52,12 @@ public final class HlsDownloadAction extends SegmentDownloadAction
};
/**
- * @see SegmentDownloadAction#SegmentDownloadAction(String, boolean, String, Uri, Comparable[])
+ * @see SegmentDownloadAction#SegmentDownloadAction(String, int, boolean, String, Uri,
+ * Comparable[])
*/
public HlsDownloadAction(
boolean isRemoveAction, @Nullable String data, Uri manifestUri, RenditionKey... keys) {
- super(TYPE, isRemoveAction, data, manifestUri, keys);
+ super(TYPE, VERSION, isRemoveAction, data, manifestUri, keys);
}
@Override
diff --git a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloadAction.java b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloadAction.java
index 9dc3f69767..9c90f92938 100644
--- a/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloadAction.java
+++ b/library/smoothstreaming/src/main/java/com/google/android/exoplayer2/source/smoothstreaming/offline/SsDownloadAction.java
@@ -29,9 +29,10 @@ import java.io.IOException;
public final class SsDownloadAction extends SegmentDownloadAction {
private static final String TYPE = "SsDownloadAction";
+ private static final int VERSION = 0;
public static final Deserializer DESERIALIZER =
- new SegmentDownloadActionDeserializer(TYPE) {
+ new SegmentDownloadActionDeserializer(TYPE, VERSION) {
@Override
protected TrackKey readKey(DataInputStream input) throws IOException {
@@ -51,11 +52,12 @@ public final class SsDownloadAction extends SegmentDownloadAction {
};
/**
- * @see SegmentDownloadAction#SegmentDownloadAction(String, boolean, String, Uri, Comparable[])
+ * @see SegmentDownloadAction#SegmentDownloadAction(String, int, boolean, String, Uri,
+ * Comparable[])
*/
public SsDownloadAction(
boolean isRemoveAction, @Nullable String data, Uri manifestUri, TrackKey... keys) {
- super(TYPE, isRemoveAction, data, manifestUri, keys);
+ super(TYPE, VERSION, isRemoveAction, data, manifestUri, keys);
}
@Override