Remove DownloadAction.createRemoveAction

PiperOrigin-RevId: 240557315
This commit is contained in:
eguven 2019-03-27 14:53:14 +00:00 committed by Toni
parent d4f5c9c721
commit facd32e65e
14 changed files with 215 additions and 354 deletions

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.offline; package com.google.android.exoplayer2.offline;
import com.google.android.exoplayer2.offline.DownloadAction.UnsupportedActionException;
import com.google.android.exoplayer2.util.AtomicFile; import com.google.android.exoplayer2.util.AtomicFile;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.DataInputStream; import java.io.DataInputStream;
@ -22,12 +23,14 @@ import java.io.DataOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList;
/** /**
* Stores and loads {@link DownloadAction}s to/from a file. * Stores and loads {@link DownloadAction}s to/from a file.
*/ */
public final class ActionFile { public final class ActionFile {
private static final String TAG = "ActionFile";
/* package */ static final int VERSION = 0; /* package */ static final int VERSION = 0;
private final AtomicFile atomicFile; private final AtomicFile atomicFile;
@ -58,11 +61,15 @@ public final class ActionFile {
throw new IOException("Unsupported action file version: " + version); throw new IOException("Unsupported action file version: " + version);
} }
int actionCount = dataInputStream.readInt(); int actionCount = dataInputStream.readInt();
DownloadAction[] actions = new DownloadAction[actionCount]; ArrayList<DownloadAction> actions = new ArrayList<>();
for (int i = 0; i < actionCount; i++) { for (int i = 0; i < actionCount; i++) {
actions[i] = DownloadAction.deserializeFromStream(dataInputStream); try {
actions.add(DownloadAction.deserializeFromStream(dataInputStream));
} catch (UnsupportedActionException e) {
// remove DownloadAction is not supported. Ignore the exception and continue loading rest.
} }
return actions; }
return actions.toArray(new DownloadAction[0]);
} finally { } finally {
Util.closeQuietly(inputStream); Util.closeQuietly(inputStream);
} }

View File

@ -17,7 +17,6 @@ package com.google.android.exoplayer2.offline;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -31,9 +30,12 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
/** Contains the necessary parameters for a download or remove action. */ /** Contains the necessary parameters for a download action. */
public final class DownloadAction { public final class DownloadAction {
/** Thrown when the encoded action data belongs to an unsupported DownloadAction type. */
public static class UnsupportedActionException extends IOException {}
/** Type for progressive downloads. */ /** Type for progressive downloads. */
public static final String TYPE_PROGRESSIVE = "progressive"; public static final String TYPE_PROGRESSIVE = "progressive";
/** Type for DASH downloads. */ /** Type for DASH downloads. */
@ -51,6 +53,8 @@ public final class DownloadAction {
* @param data The action data to deserialize. * @param data The action data to deserialize.
* @return The deserialized action. * @return The deserialized action.
* @throws IOException If the data could not be deserialized. * @throws IOException If the data could not be deserialized.
* @throws UnsupportedActionException If the data belongs to an unsupported {@link DownloadAction}
* type. Input read position is set to the end of the data.
*/ */
public static DownloadAction fromByteArray(byte[] data) throws IOException { public static DownloadAction fromByteArray(byte[] data) throws IOException {
ByteArrayInputStream input = new ByteArrayInputStream(data); ByteArrayInputStream input = new ByteArrayInputStream(data);
@ -67,6 +71,8 @@ public final class DownloadAction {
* @return The deserialized action. * @return The deserialized action.
* @throws IOException If there is an IO error reading from {@code input}, or if the data could * @throws IOException If there is an IO error reading from {@code input}, or if the data could
* not be deserialized. * not be deserialized.
* @throws UnsupportedActionException If the data belongs to an unsupported {@link DownloadAction}
* type. Input read position is set to the end of the data.
*/ */
public static DownloadAction deserializeFromStream(InputStream input) throws IOException { public static DownloadAction deserializeFromStream(InputStream input) throws IOException {
return readFromStream(new DataInputStream(input)); return readFromStream(new DataInputStream(input));
@ -108,41 +114,16 @@ public final class DownloadAction {
List<StreamKey> keys, List<StreamKey> keys,
@Nullable String customCacheKey, @Nullable String customCacheKey,
@Nullable byte[] data) { @Nullable byte[] data) {
return new DownloadAction( return new DownloadAction(id, type, uri, keys, customCacheKey, data);
id, type, uri, /* isRemoveAction= */ false, keys, customCacheKey, data);
}
/**
* Creates a DASH remove action.
*
* @param type The type of the action.
* @param uri The URI of the media to be removed.
* @param customCacheKey A custom key for cache indexing, or null.
*/
public static DownloadAction createRemoveAction(
String type, Uri uri, @Nullable String customCacheKey) {
return new DownloadAction(
generateId(uri, customCacheKey),
type,
uri,
/* isRemoveAction= */ true,
Collections.emptyList(),
customCacheKey,
/* data= */ null);
} }
/** The unique content id. */ /** The unique content id. */
public final String id; public final String id;
/** The type of the action. */ /** The type of the action. */
public final String type; public final String type;
/** The uri being downloaded or removed. */ /** The uri being downloaded. */
public final Uri uri; public final Uri uri;
/** Whether this is a remove action. If false, this is a download action. */ /** Keys of streams to be downloaded. If empty, all streams will be downloaded. */
public final boolean isRemoveAction;
/**
* Keys of streams to be downloaded. If empty, all streams will be downloaded. Empty if this
* action is a remove action.
*/
public final List<StreamKey> keys; public final List<StreamKey> keys;
/** A custom key for cache indexing, or null. */ /** A custom key for cache indexing, or null. */
@Nullable public final String customCacheKey; @Nullable public final String customCacheKey;
@ -152,38 +133,27 @@ public final class DownloadAction {
/** /**
* @param id The content id. * @param id The content id.
* @param type The type of the action. * @param type The type of the action.
* @param uri The uri being downloaded or removed. * @param uri The uri being downloaded.
* @param isRemoveAction Whether this is a remove action. If false, this is a download action. * @param keys Keys of streams to be downloaded. If empty, all streams will be downloaded.
* @param keys Keys of streams to be downloaded. If empty, all streams will be downloaded. Empty
* if this action is a remove action.
* @param customCacheKey A custom key for cache indexing, or null. * @param customCacheKey A custom key for cache indexing, or null.
* @param data Custom data for this action. Null if this action is a remove action. * @param data Custom data for this action.
*/ */
private DownloadAction( private DownloadAction(
String id, String id,
String type, String type,
Uri uri, Uri uri,
boolean isRemoveAction,
List<StreamKey> keys, List<StreamKey> keys,
@Nullable String customCacheKey, @Nullable String customCacheKey,
@Nullable byte[] data) { @Nullable byte[] data) {
this.id = id; this.id = id;
this.type = type; this.type = type;
this.uri = uri; this.uri = uri;
this.isRemoveAction = isRemoveAction;
this.customCacheKey = customCacheKey; this.customCacheKey = customCacheKey;
if (isRemoveAction) {
Assertions.checkArgument(keys.isEmpty());
Assertions.checkArgument(data == null);
this.keys = Collections.emptyList();
this.data = Util.EMPTY_BYTE_ARRAY;
} else {
ArrayList<StreamKey> mutableKeys = new ArrayList<>(keys); ArrayList<StreamKey> mutableKeys = new ArrayList<>(keys);
Collections.sort(mutableKeys); Collections.sort(mutableKeys);
this.keys = Collections.unmodifiableList(mutableKeys); this.keys = Collections.unmodifiableList(mutableKeys);
this.data = data != null ? Arrays.copyOf(data, data.length) : Util.EMPTY_BYTE_ARRAY; this.data = data != null ? Arrays.copyOf(data, data.length) : Util.EMPTY_BYTE_ARRAY;
} }
}
/** Serializes itself into a byte array. */ /** Serializes itself into a byte array. */
public byte[] toByteArray() { public byte[] toByteArray() {
@ -211,7 +181,6 @@ public final class DownloadAction {
return id.equals(that.id) return id.equals(that.id)
&& type.equals(that.type) && type.equals(that.type)
&& uri.equals(that.uri) && uri.equals(that.uri)
&& isRemoveAction == that.isRemoveAction
&& keys.equals(that.keys) && keys.equals(that.keys)
&& Util.areEqual(customCacheKey, that.customCacheKey) && Util.areEqual(customCacheKey, that.customCacheKey)
&& Arrays.equals(data, that.data); && Arrays.equals(data, that.data);
@ -222,7 +191,6 @@ public final class DownloadAction {
int result = type.hashCode(); int result = type.hashCode();
result = 31 * result + id.hashCode(); result = 31 * result + id.hashCode();
result = 31 * result + uri.hashCode(); result = 31 * result + uri.hashCode();
result = 31 * result + (isRemoveAction ? 1 : 0);
result = 31 * result + keys.hashCode(); result = 31 * result + keys.hashCode();
result = 31 * result + (customCacheKey != null ? customCacheKey.hashCode() : 0); result = 31 * result + (customCacheKey != null ? customCacheKey.hashCode() : 0);
result = 31 * result + Arrays.hashCode(data); result = 31 * result + Arrays.hashCode(data);
@ -242,7 +210,7 @@ public final class DownloadAction {
dataOutputStream.writeUTF(type); dataOutputStream.writeUTF(type);
dataOutputStream.writeInt(VERSION); dataOutputStream.writeInt(VERSION);
dataOutputStream.writeUTF(uri.toString()); dataOutputStream.writeUTF(uri.toString());
dataOutputStream.writeBoolean(isRemoveAction); dataOutputStream.writeBoolean(false);
dataOutputStream.writeInt(data.length); dataOutputStream.writeInt(data.length);
dataOutputStream.write(data); dataOutputStream.write(data);
dataOutputStream.writeInt(keys.size()); dataOutputStream.writeInt(keys.size());
@ -271,10 +239,6 @@ public final class DownloadAction {
if (dataLength != 0) { if (dataLength != 0) {
data = new byte[dataLength]; data = new byte[dataLength];
input.readFully(data); input.readFully(data);
if (isRemoveAction) {
// Remove actions are no longer permitted to have data.
data = null;
}
} else { } else {
data = null; data = null;
} }
@ -297,8 +261,12 @@ public final class DownloadAction {
customCacheKey = input.readBoolean() ? input.readUTF() : null; customCacheKey = input.readBoolean() ? input.readUTF() : null;
} }
if (isRemoveAction) {
// Remove actions are not supported anymore.
throw new UnsupportedActionException();
}
return new DownloadAction( return new DownloadAction(
generateId(uri, customCacheKey), type, uri, isRemoveAction, keys, customCacheKey, data); generateId(uri, customCacheKey), type, uri, keys, customCacheKey, data);
} }
private static String generateId(Uri uri, @Nullable String customCacheKey) { private static String generateId(Uri uri, @Nullable String customCacheKey) {

View File

@ -342,11 +342,11 @@ public final class DownloadManager {
} }
/** /**
* Handles the given action. * Adds a download defined by the given action.
* *
* @param action The action to be executed. * @param action The download action.
*/ */
public void handleAction(DownloadAction action) { public void addDownload(DownloadAction action) {
Assertions.checkState(!released); Assertions.checkState(!released);
dowloadUpdateQueue.add( dowloadUpdateQueue.add(
new DownloadUpdater(action.id) { new DownloadUpdater(action.id) {
@ -392,6 +392,8 @@ public final class DownloadManager {
DownloadState onLoad(@Nullable DownloadState downloadState) { DownloadState onLoad(@Nullable DownloadState downloadState) {
if (downloadState != null) { if (downloadState != null) {
downloadState = downloadState.setRemoveState(); downloadState = downloadState.setRemoveState();
} else {
logd("Can't remove download. No download with id: " + id);
} }
return downloadState; return downloadState;
} }
@ -541,9 +543,7 @@ public final class DownloadManager {
} }
private void processDownloadUpdateQueue() { private void processDownloadUpdateQueue() {
if (loadingDownload || dowloadUpdateQueue.isEmpty()) { while (!loadingDownload && !dowloadUpdateQueue.isEmpty()) {
return;
}
DownloadUpdater downloadUpdater = dowloadUpdateQueue.remove(); DownloadUpdater downloadUpdater = dowloadUpdateQueue.remove();
Download download = getDownload(downloadUpdater.id); Download download = getDownload(downloadUpdater.id);
if (download != null) { if (download != null) {
@ -552,6 +552,7 @@ public final class DownloadManager {
loadDownload(downloadUpdater); loadDownload(downloadUpdater);
} }
} }
}
private void loadDownload(DownloadUpdater callback) { private void loadDownload(DownloadUpdater callback) {
loadingDownload = true; loadingDownload = true;

View File

@ -270,11 +270,14 @@ public abstract class DownloadService extends Service {
* @param context A {@link Context}. * @param context A {@link Context}.
* @param clazz The concrete download service being targeted by the intent. * @param clazz The concrete download service being targeted by the intent.
* @param id The content id. * @param id The content id.
* @param foreground Whether this intent will be used to start the service in the foreground.
* @return Created Intent. * @return Created Intent.
*/ */
public static Intent buildRemoveDownloadIntent( public static Intent buildRemoveDownloadIntent(
Context context, Class<? extends DownloadService> clazz, String id) { Context context, Class<? extends DownloadService> clazz, String id, boolean foreground) {
return getIntent(context, clazz, ACTION_REMOVE).putExtra(KEY_CONTENT_ID, id); return getIntent(context, clazz, ACTION_REMOVE)
.putExtra(KEY_CONTENT_ID, id)
.putExtra(KEY_FOREGROUND, foreground);
} }
/** /**
@ -308,7 +311,7 @@ public abstract class DownloadService extends Service {
*/ */
public static void startWithRemoveDownload( public static void startWithRemoveDownload(
Context context, Class<? extends DownloadService> clazz, String id, boolean foreground) { Context context, Class<? extends DownloadService> clazz, String id, boolean foreground) {
Intent intent = buildRemoveDownloadIntent(context, clazz, id); Intent intent = buildRemoveDownloadIntent(context, clazz, id, foreground);
if (foreground) { if (foreground) {
Util.startForegroundService(context, intent); Util.startForegroundService(context, intent);
} else { } else {
@ -393,7 +396,7 @@ public abstract class DownloadService extends Service {
Log.e(TAG, "Ignored ADD action: Failed to deserialize download_action extra", e); Log.e(TAG, "Ignored ADD action: Failed to deserialize download_action extra", e);
} }
if (downloadAction != null) { if (downloadAction != null) {
downloadManager.handleAction(downloadAction); downloadManager.addDownload(downloadAction);
} }
} }
break; break;

View File

@ -166,7 +166,7 @@ public final class DownloadState {
action.type, action.type,
action.uri, action.uri,
action.customCacheKey, action.customCacheKey,
/* state= */ action.isRemoveAction ? STATE_REMOVING : STATE_QUEUED, /* state= */ STATE_QUEUED,
/* downloadPercentage= */ C.PERCENTAGE_UNSET, /* downloadPercentage= */ C.PERCENTAGE_UNSET,
/* downloadedBytes= */ 0, /* downloadedBytes= */ 0,
/* totalBytes= */ C.LENGTH_UNSET, /* totalBytes= */ C.LENGTH_UNSET,
@ -231,8 +231,7 @@ public final class DownloadState {
type, type,
action.uri, action.uri,
action.customCacheKey, action.customCacheKey,
getNextState( getNextState(state, manualStopReason != 0 || notMetRequirements != 0),
state, manualStopReason != 0 || notMetRequirements != 0, action.isRemoveAction),
/* downloadPercentage= */ C.PERCENTAGE_UNSET, /* downloadPercentage= */ C.PERCENTAGE_UNSET,
downloadedBytes, downloadedBytes,
/* totalBytes= */ C.LENGTH_UNSET, /* totalBytes= */ C.LENGTH_UNSET,
@ -252,7 +251,7 @@ public final class DownloadState {
type, type,
uri, uri,
cacheKey, cacheKey,
getNextState(state, manualStopReason != 0 || notMetRequirements != 0, true), STATE_REMOVING,
/* downloadPercentage= */ C.PERCENTAGE_UNSET, /* downloadPercentage= */ C.PERCENTAGE_UNSET,
downloadedBytes, downloadedBytes,
/* totalBytes= */ C.LENGTH_UNSET, /* totalBytes= */ C.LENGTH_UNSET,
@ -265,25 +264,19 @@ public final class DownloadState {
customMetadata); customMetadata);
} }
private static int getNextState(int currentState, boolean isStopped, boolean remove) { private static int getNextState(int currentState, boolean isStopped) {
int nextState;
if (remove) {
nextState = STATE_REMOVING;
} else {
if (currentState == STATE_REMOVING || currentState == STATE_RESTARTING) { if (currentState == STATE_REMOVING || currentState == STATE_RESTARTING) {
nextState = STATE_RESTARTING; return STATE_RESTARTING;
} else if (isStopped) { } else if (isStopped) {
nextState = STATE_STOPPED; return STATE_STOPPED;
} else { } else {
nextState = STATE_QUEUED; return STATE_QUEUED;
} }
} }
return nextState;
}
private static StreamKey[] mergeStreamKeys(DownloadState downloadState, DownloadAction action) { private static StreamKey[] mergeStreamKeys(DownloadState downloadState, DownloadAction action) {
StreamKey[] streamKeys = downloadState.streamKeys; StreamKey[] streamKeys = downloadState.streamKeys;
if (!action.isRemoveAction && streamKeys.length > 0) { if (streamKeys.length > 0) {
if (action.keys.isEmpty()) { if (action.keys.isEmpty()) {
streamKeys = new StreamKey[0]; streamKeys = new StreamKey[0];
} else { } else {

View File

@ -20,10 +20,13 @@ import static com.google.android.exoplayer2.offline.DownloadAction.TYPE_HLS;
import static com.google.android.exoplayer2.offline.DownloadAction.TYPE_PROGRESSIVE; import static com.google.android.exoplayer2.offline.DownloadAction.TYPE_PROGRESSIVE;
import static com.google.android.exoplayer2.offline.DownloadAction.TYPE_SS; import static com.google.android.exoplayer2.offline.DownloadAction.TYPE_SS;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.offline.DownloadAction.UnsupportedActionException;
import com.google.android.exoplayer2.testutil.TestUtil; import com.google.android.exoplayer2.testutil.TestUtil;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -53,92 +56,73 @@ public class DownloadActionTest {
data = TestUtil.buildTestData(32); data = TestUtil.buildTestData(32);
} }
@Test
public void testDownloadActionIsNotRemoveAction() {
DownloadAction action = createDownloadAction(uri1);
assertThat(action.isRemoveAction).isFalse();
}
@Test
public void testRemoveActionIsRemoveAction() {
DownloadAction action2 = createRemoveAction(uri1);
assertThat(action2.isRemoveAction).isTrue();
}
@Test @Test
public void testSameUri_hasSameId() { public void testSameUri_hasSameId() {
DownloadAction action1 = createDownloadAction(uri1); DownloadAction action1 = createAction(uri1);
DownloadAction action2 = createDownloadAction(uri1); DownloadAction action2 = createAction(uri1);
assertThat(action1.id.equals(action2.id)).isTrue(); assertThat(action1.id.equals(action2.id)).isTrue();
} }
@Test @Test
public void testSameUriDifferentAction_hasSameId() { public void testSameUriDifferentAction_hasSameId() {
DownloadAction action1 = createDownloadAction(uri1); DownloadAction action1 = createAction(uri1);
DownloadAction action2 = createRemoveAction(uri1); DownloadAction action2 = createAction(uri1);
assertThat(action1.id.equals(action2.id)).isTrue(); assertThat(action1.id.equals(action2.id)).isTrue();
} }
@Test @Test
public void testDifferentUri_IsNotSameMedia() { public void testDifferentUri_IsNotSameMedia() {
DownloadAction action1 = createDownloadAction(uri1); DownloadAction action1 = createAction(uri1);
DownloadAction action2 = createDownloadAction(uri2); DownloadAction action2 = createAction(uri2);
assertThat(action1.id.equals(action2.id)).isFalse(); assertThat(action1.id.equals(action2.id)).isFalse();
} }
@Test @Test
public void testSameCacheKeyDifferentUri_hasSameId() { public void testSameCacheKeyDifferentUri_hasSameId() {
DownloadAction action1 = DownloadAction.createRemoveAction(TYPE_DASH, uri1, "key123"); DownloadAction action1 = createAction(uri1, "key123");
DownloadAction action2 = DownloadAction.createRemoveAction(TYPE_DASH, uri2, "key123"); DownloadAction action2 = createAction(uri2, "key123");
assertThat(action1.id.equals(action2.id)).isTrue(); assertThat(action1.id.equals(action2.id)).isTrue();
} }
@Test @Test
public void testDifferentCacheKeyDifferentUri_hasDifferentId() { public void testDifferentCacheKeyDifferentUri_hasDifferentId() {
DownloadAction action1 = DownloadAction.createRemoveAction(TYPE_DASH, uri1, "key123"); DownloadAction action1 = createAction(uri1, "key123");
DownloadAction action2 = DownloadAction.createRemoveAction(TYPE_DASH, uri2, "key456"); DownloadAction action2 = createAction(uri2, "key456");
assertThat(action1.id.equals(action2.id)).isFalse(); assertThat(action1.id.equals(action2.id)).isFalse();
} }
@SuppressWarnings("EqualsWithItself") @SuppressWarnings("EqualsWithItself")
@Test @Test
public void testEquals() { public void testEquals() {
DownloadAction action1 = createRemoveAction(uri1); DownloadAction action1 = createAction(uri1);
assertThat(action1.equals(action1)).isTrue(); assertThat(action1.equals(action1)).isTrue();
DownloadAction action2 = createRemoveAction(uri1); DownloadAction action2 = createAction(uri1);
DownloadAction action3 = createRemoveAction(uri1); DownloadAction action3 = createAction(uri1);
assertEqual(action2, action3); assertEqual(action2, action3);
DownloadAction action4 = createRemoveAction(uri1); DownloadAction action6 = createAction(uri1);
DownloadAction action5 = createDownloadAction(uri1); DownloadAction action7 = createAction(uri1, new StreamKey(0, 0, 0));
assertNotEqual(action4, action5);
DownloadAction action6 = createDownloadAction(uri1);
DownloadAction action7 = createDownloadAction(uri1, new StreamKey(0, 0, 0));
assertNotEqual(action6, action7); assertNotEqual(action6, action7);
DownloadAction action8 = createDownloadAction(uri1, new StreamKey(0, 1, 1)); DownloadAction action8 = createAction(uri1, new StreamKey(0, 1, 1));
DownloadAction action9 = createDownloadAction(uri1, new StreamKey(0, 0, 0)); DownloadAction action9 = createAction(uri1, new StreamKey(0, 0, 0));
assertNotEqual(action8, action9); assertNotEqual(action8, action9);
DownloadAction action10 = createRemoveAction(uri1); DownloadAction action10 = createAction(uri1);
DownloadAction action11 = createRemoveAction(uri2); DownloadAction action11 = createAction(uri2);
assertNotEqual(action10, action11); assertNotEqual(action10, action11);
DownloadAction action12 = DownloadAction action12 = createAction(uri1, new StreamKey(0, 0, 0), new StreamKey(0, 1, 1));
createDownloadAction(uri1, new StreamKey(0, 0, 0), new StreamKey(0, 1, 1)); DownloadAction action13 = createAction(uri1, new StreamKey(0, 1, 1), new StreamKey(0, 0, 0));
DownloadAction action13 =
createDownloadAction(uri1, new StreamKey(0, 1, 1), new StreamKey(0, 0, 0));
assertEqual(action12, action13); assertEqual(action12, action13);
DownloadAction action14 = createDownloadAction(uri1, new StreamKey(0, 0, 0)); DownloadAction action14 = createAction(uri1, new StreamKey(0, 0, 0));
DownloadAction action15 = DownloadAction action15 = createAction(uri1, new StreamKey(0, 1, 1), new StreamKey(0, 0, 0));
createDownloadAction(uri1, new StreamKey(0, 1, 1), new StreamKey(0, 0, 0));
assertNotEqual(action14, action15); assertNotEqual(action14, action15);
DownloadAction action16 = createDownloadAction(uri1); DownloadAction action16 = createAction(uri1);
DownloadAction action17 = createDownloadAction(uri1); DownloadAction action17 = createAction(uri1);
assertEqual(action16, action17); assertEqual(action16, action17);
} }
@ -151,8 +135,7 @@ public class DownloadActionTest {
toList(new StreamKey(0, 1, 2), new StreamKey(3, 4, 5)), toList(new StreamKey(0, 1, 2), new StreamKey(3, 4, 5)),
"key123", "key123",
data)); data));
assertStreamSerializationRoundTrip( assertStreamSerializationRoundTrip(createAction(uri1, "key123"));
DownloadAction.createRemoveAction(TYPE_DASH, uri1, "key123"));
} }
@Test @Test
@ -164,7 +147,7 @@ public class DownloadActionTest {
toList(new StreamKey(0, 1, 2), new StreamKey(3, 4, 5)), toList(new StreamKey(0, 1, 2), new StreamKey(3, 4, 5)),
"key123", "key123",
data)); data));
assertArraySerializationRoundTrip(DownloadAction.createRemoveAction(TYPE_DASH, uri1, "key123")); assertArraySerializationRoundTrip(createAction(uri1, "key123"));
} }
@Test @Test
@ -173,9 +156,7 @@ public class DownloadActionTest {
"progressive-download-v0", "progressive-download-v0",
DownloadAction.createDownloadAction( DownloadAction.createDownloadAction(
TYPE_PROGRESSIVE, uri1, Collections.emptyList(), "key123", data)); TYPE_PROGRESSIVE, uri1, Collections.emptyList(), "key123", data));
assertDeserialization( assertUnsupportedAction("progressive-remove-v0");
"progressive-remove-v0",
DownloadAction.createRemoveAction(TYPE_PROGRESSIVE, uri1, "key123"));
} }
@Test @Test
@ -188,9 +169,7 @@ public class DownloadActionTest {
toList(new StreamKey(0, 1, 2), new StreamKey(3, 4, 5)), toList(new StreamKey(0, 1, 2), new StreamKey(3, 4, 5)),
/* customCacheKey= */ null, /* customCacheKey= */ null,
data)); data));
assertDeserialization( assertUnsupportedAction("dash-remove-v0");
"dash-remove-v0",
DownloadAction.createRemoveAction(TYPE_DASH, uri1, /* customCacheKey= */ null));
} }
@Test @Test
@ -203,9 +182,7 @@ public class DownloadActionTest {
toList(new StreamKey(0, 1), new StreamKey(2, 3)), toList(new StreamKey(0, 1), new StreamKey(2, 3)),
/* customCacheKey= */ null, /* customCacheKey= */ null,
data)); data));
assertDeserialization( assertUnsupportedAction("hls-remove-v0");
"hls-remove-v0",
DownloadAction.createRemoveAction(TYPE_HLS, uri1, /* customCacheKey= */ null));
} }
@Test @Test
@ -218,9 +195,7 @@ public class DownloadActionTest {
toList(new StreamKey(0, 1, 2), new StreamKey(3, 4, 5)), toList(new StreamKey(0, 1, 2), new StreamKey(3, 4, 5)),
/* customCacheKey= */ null, /* customCacheKey= */ null,
data)); data));
assertDeserialization( assertUnsupportedAction("hls-remove-v1");
"hls-remove-v1",
DownloadAction.createRemoveAction(TYPE_HLS, uri1, /* customCacheKey= */ null));
} }
@Test @Test
@ -233,9 +208,7 @@ public class DownloadActionTest {
toList(new StreamKey(0, 1), new StreamKey(2, 3)), toList(new StreamKey(0, 1), new StreamKey(2, 3)),
/* customCacheKey= */ null, /* customCacheKey= */ null,
data)); data));
assertDeserialization( assertUnsupportedAction("ss-remove-v0");
"ss-remove-v0",
DownloadAction.createRemoveAction(TYPE_SS, uri1, /* customCacheKey= */ null));
} }
@Test @Test
@ -248,18 +221,17 @@ public class DownloadActionTest {
toList(new StreamKey(0, 1, 2), new StreamKey(3, 4, 5)), toList(new StreamKey(0, 1, 2), new StreamKey(3, 4, 5)),
/* customCacheKey= */ null, /* customCacheKey= */ null,
data)); data));
assertDeserialization( assertUnsupportedAction("ss-remove-v1");
"ss-remove-v1",
DownloadAction.createRemoveAction(TYPE_SS, uri1, /* customCacheKey= */ null));
} }
private DownloadAction createDownloadAction(Uri uri, StreamKey... keys) { private DownloadAction createAction(Uri uri, StreamKey... keys) {
return DownloadAction.createDownloadAction( return DownloadAction.createDownloadAction(
TYPE_DASH, uri, toList(keys), /* customCacheKey= */ null, data); TYPE_DASH, uri, toList(keys), /* customCacheKey= */ null, data);
} }
private DownloadAction createRemoveAction(Uri uri) { private DownloadAction createAction(Uri uri, @Nullable String customCacheKey) {
return DownloadAction.createRemoveAction(TYPE_DASH, uri, /* customCacheKey= */ null); return DownloadAction.createDownloadAction(
DownloadAction.TYPE_DASH, uri, Collections.emptyList(), customCacheKey, /* data= */ null);
} }
private static void assertNotEqual(DownloadAction action1, DownloadAction action2) { private static void assertNotEqual(DownloadAction action1, DownloadAction action2) {
@ -298,6 +270,18 @@ public class DownloadActionTest {
assertEqual(deserializedAction, expectedAction); assertEqual(deserializedAction, expectedAction);
} }
private static void assertUnsupportedAction(String fileName) throws IOException {
InputStream input =
TestUtil.getInputStream(
ApplicationProvider.getApplicationContext(), "download-actions/" + fileName);
try {
DownloadAction.deserializeFromStream(input);
fail();
} catch (UnsupportedActionException e) {
// Expected exception.
}
}
private static List<StreamKey> toList(StreamKey... keys) { private static List<StreamKey> toList(StreamKey... keys) {
ArrayList<StreamKey> keysList = new ArrayList<>(); ArrayList<StreamKey> keysList = new ArrayList<>();
Collections.addAll(keysList, keys); Collections.addAll(keysList, keys);

View File

@ -397,7 +397,6 @@ public class DownloadHelperTest {
assertThat(downloadAction.type).isEqualTo(TEST_DOWNLOAD_TYPE); assertThat(downloadAction.type).isEqualTo(TEST_DOWNLOAD_TYPE);
assertThat(downloadAction.uri).isEqualTo(testUri); assertThat(downloadAction.uri).isEqualTo(testUri);
assertThat(downloadAction.customCacheKey).isEqualTo(TEST_CACHE_KEY); assertThat(downloadAction.customCacheKey).isEqualTo(TEST_CACHE_KEY);
assertThat(downloadAction.isRemoveAction).isFalse();
assertThat(downloadAction.data).isEqualTo(data); assertThat(downloadAction.data).isEqualTo(data);
assertThat(downloadAction.keys) assertThat(downloadAction.keys)
.containsExactly( .containsExactly(

View File

@ -127,16 +127,11 @@ public class DownloadIndexUtilTest {
/* customCacheKey= */ "key234", /* customCacheKey= */ "key234",
new byte[] {5, 4, 3, 2, 1}); new byte[] {5, 4, 3, 2, 1});
actionFile.store(action1, action2); actionFile.store(action1, action2);
DownloadAction action3 =
DownloadAction.createRemoveAction(
TYPE_DASH, Uri.parse("https://www.test.com/download3"), /* customCacheKey= */ "key345");
actionFile.store(action1, action2, action3);
DownloadIndexUtil.upgradeActionFile(actionFile, downloadIndex, /* downloadIdProvider= */ null); DownloadIndexUtil.upgradeActionFile(actionFile, downloadIndex, /* downloadIdProvider= */ null);
assertDownloadIndexContainsAction(action1, DownloadState.STATE_QUEUED); assertDownloadIndexContainsAction(action1, DownloadState.STATE_QUEUED);
assertDownloadIndexContainsAction(action2, DownloadState.STATE_QUEUED); assertDownloadIndexContainsAction(action2, DownloadState.STATE_QUEUED);
assertDownloadIndexContainsAction(action3, DownloadState.STATE_REMOVING);
} }
private void assertDownloadIndexContainsAction(DownloadAction action, int state) private void assertDownloadIndexContainsAction(DownloadAction action, int state)

View File

@ -16,7 +16,6 @@
package com.google.android.exoplayer2.offline; package com.google.android.exoplayer2.offline;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import android.net.Uri; import android.net.Uri;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
@ -33,7 +32,6 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.junit.After; import org.junit.After;
@ -101,21 +99,6 @@ public class DownloadManagerTest {
assertThat(exceptionThrown).isTrue(); assertThat(exceptionThrown).isTrue();
} }
@Test
public void downloadRunner_handleActionReturnsDifferentTaskId_throwsException() {
DownloadRunner runner = new DownloadRunner(uri1).postDownloadAction();
TaskWrapper task = runner.getTask();
runner.setTask(new TaskWrapper(task.taskId + 10000));
boolean exceptionThrown = false;
try {
runner.postDownloadAction();
// can't put fail() here as it would be caught in the catch below.
} catch (Throwable e) {
exceptionThrown = true;
}
assertThat(exceptionThrown).isTrue();
}
@Test @Test
public void multipleActionsForTheSameContent_executedOnTheSameTask() { public void multipleActionsForTheSameContent_executedOnTheSameTask() {
// Two download actions on first task // Two download actions on first task
@ -150,11 +133,11 @@ public class DownloadManagerTest {
@Test @Test
public void postRemoveAction_removes() throws Throwable { public void postRemoveAction_removes() throws Throwable {
DownloadRunner runner = new DownloadRunner(uri1); DownloadRunner runner = new DownloadRunner(uri1);
TaskWrapper task = runner.postRemoveAction().getTask(); TaskWrapper task = runner.postDownloadAction().postRemoveAction().getTask();
task.assertRemoving(); task.assertRemoving();
runner.getDownloader(0).unblock().assertReleased().assertStartCount(1); runner.getDownloader(1).unblock().assertReleased().assertStartCount(1);
task.assertRemoved(); task.assertRemoved();
runner.assertCreatedDownloaderCount(1); runner.assertCreatedDownloaderCount(2);
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError(); downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
} }
@ -224,29 +207,29 @@ public class DownloadManagerTest {
@Test @Test
public void downloadNotCancelRemove() throws Throwable { public void downloadNotCancelRemove() throws Throwable {
DownloadRunner runner = new DownloadRunner(uri1); DownloadRunner runner = new DownloadRunner(uri1);
FakeDownloader downloader1 = runner.getDownloader(0); FakeDownloader downloader1 = runner.getDownloader(1);
runner.postRemoveAction(); runner.postDownloadAction().postRemoveAction();
downloader1.assertStarted(); downloader1.assertStarted();
runner.postDownloadAction(); runner.postDownloadAction();
downloader1.unblock().assertNotCanceled(); downloader1.unblock().assertNotCanceled();
runner.getDownloader(1).unblock().assertNotCanceled(); runner.getDownloader(2).unblock().assertNotCanceled();
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError(); downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
} }
@Test @Test
public void secondSameRemoveActionIgnored() throws Throwable { public void secondSameRemoveActionIgnored() throws Throwable {
DownloadRunner runner = new DownloadRunner(uri1); DownloadRunner runner = new DownloadRunner(uri1);
FakeDownloader downloader1 = runner.getDownloader(0); FakeDownloader downloader1 = runner.getDownloader(1);
runner.postRemoveAction(); runner.postDownloadAction().postRemoveAction();
downloader1.assertStarted(); downloader1.assertStarted();
runner.postRemoveAction(); runner.postRemoveAction();
downloader1.unblock().assertNotCanceled(); downloader1.unblock().assertNotCanceled();
runner.getTask().assertRemoved(); runner.getTask().assertRemoved();
runner.assertCreatedDownloaderCount(1); runner.assertCreatedDownloaderCount(2);
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError(); downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
} }
@ -316,7 +299,7 @@ public class DownloadManagerTest {
throws Throwable { throws Throwable {
setUpDownloadManager(1); setUpDownloadManager(1);
DownloadRunner runner1 = new DownloadRunner(uri1).postDownloadAction(); DownloadRunner runner1 = new DownloadRunner(uri1).postDownloadAction();
DownloadRunner runner2 = new DownloadRunner(uri2).postRemoveAction(); DownloadRunner runner2 = new DownloadRunner(uri2).postDownloadAction().postRemoveAction();
FakeDownloader downloader1 = runner1.getDownloader(0); FakeDownloader downloader1 = runner1.getDownloader(0);
FakeDownloader downloader2 = runner2.getDownloader(0); FakeDownloader downloader2 = runner2.getDownloader(0);
@ -334,7 +317,8 @@ public class DownloadManagerTest {
public void downloadActionFollowingRemove_ifMaxDownloadIs1_isNotStarted() throws Throwable { public void downloadActionFollowingRemove_ifMaxDownloadIs1_isNotStarted() throws Throwable {
setUpDownloadManager(1); setUpDownloadManager(1);
DownloadRunner runner1 = new DownloadRunner(uri1).postDownloadAction(); DownloadRunner runner1 = new DownloadRunner(uri1).postDownloadAction();
DownloadRunner runner2 = new DownloadRunner(uri2).postRemoveAction().postDownloadAction(); DownloadRunner runner2 = new DownloadRunner(uri2).postDownloadAction().postRemoveAction();
runner2.postDownloadAction();
FakeDownloader downloader1 = runner1.getDownloader(0); FakeDownloader downloader1 = runner1.getDownloader(0);
FakeDownloader downloader2 = runner2.getDownloader(0); FakeDownloader downloader2 = runner2.getDownloader(0);
FakeDownloader downloader3 = runner2.getDownloader(1); FakeDownloader downloader3 = runner2.getDownloader(1);
@ -356,7 +340,7 @@ public class DownloadManagerTest {
public void getTasks_returnTasks() { public void getTasks_returnTasks() {
TaskWrapper task1 = new DownloadRunner(uri1).postDownloadAction().getTask(); TaskWrapper task1 = new DownloadRunner(uri1).postDownloadAction().getTask();
TaskWrapper task2 = new DownloadRunner(uri2).postDownloadAction().getTask(); TaskWrapper task2 = new DownloadRunner(uri2).postDownloadAction().getTask();
TaskWrapper task3 = new DownloadRunner(uri3).postRemoveAction().getTask(); TaskWrapper task3 = new DownloadRunner(uri3).postDownloadAction().postRemoveAction().getTask();
task3.assertRemoving(); task3.assertRemoving();
DownloadState[] states = downloadManager.getAllDownloadStates(); DownloadState[] states = downloadManager.getAllDownloadStates();
@ -374,7 +358,7 @@ public class DownloadManagerTest {
DownloadRunner runner3 = new DownloadRunner(uri3); DownloadRunner runner3 = new DownloadRunner(uri3);
runner1.postDownloadAction().getTask().assertDownloading(); runner1.postDownloadAction().getTask().assertDownloading();
runner2.postRemoveAction().getTask().assertRemoving(); runner2.postDownloadAction().postRemoveAction().getTask().assertRemoving();
runner2.postDownloadAction(); runner2.postDownloadAction();
runOnMainThread(() -> downloadManager.stopDownloads()); runOnMainThread(() -> downloadManager.stopDownloads());
@ -382,10 +366,10 @@ public class DownloadManagerTest {
runner1.getTask().assertStopped(); runner1.getTask().assertStopped();
// remove actions aren't stopped. // remove actions aren't stopped.
runner2.getDownloader(0).unblock().assertReleased(); runner2.getDownloader(1).unblock().assertReleased();
runner2.getTask().assertStopped(); runner2.getTask().assertStopped();
// Although remove2 is finished, download2 doesn't start. // Although remove2 is finished, download2 doesn't start.
runner2.getDownloader(1).assertDoesNotStart(); runner2.getDownloader(2).assertDoesNotStart();
// When a new remove action is added, it cancels stopped download actions with the same media. // When a new remove action is added, it cancels stopped download actions with the same media.
runner1.postRemoveAction(); runner1.postRemoveAction();
@ -397,7 +381,7 @@ public class DownloadManagerTest {
runOnMainThread(() -> downloadManager.startDownloads()); runOnMainThread(() -> downloadManager.startDownloads());
runner2.getDownloader(1).assertStarted().unblock(); runner2.getDownloader(2).assertStarted().unblock();
runner3.getDownloader(0).assertStarted().unblock(); runner3.getDownloader(0).assertStarted().unblock();
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError(); downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
@ -446,14 +430,14 @@ public class DownloadManagerTest {
DownloadRunner runner3 = new DownloadRunner(uri3); DownloadRunner runner3 = new DownloadRunner(uri3);
runner1.postDownloadAction().getTask().assertDownloading(); runner1.postDownloadAction().getTask().assertDownloading();
runner2.postRemoveAction().getTask().assertRemoving(); runner2.postDownloadAction().postRemoveAction().getTask().assertRemoving();
runOnMainThread(() -> downloadManager.stopDownload(runner1.getTask().taskId)); runOnMainThread(() -> downloadManager.stopDownload(runner1.getTask().taskId));
runner1.getTask().assertStopped(); runner1.getTask().assertStopped();
// Other downloads aren't affected. // Other downloads aren't affected.
runner2.getDownloader(0).unblock().assertReleased(); runner2.getDownloader(1).unblock().assertReleased();
// New download actions can be added and they start. // New download actions can be added and they start.
runner3.postDownloadAction().getDownloader(0).assertStarted().unblock(); runner3.postDownloadAction().getDownloader(0).assertStarted().unblock();
@ -501,33 +485,36 @@ public class DownloadManagerTest {
private final class DownloadRunner { private final class DownloadRunner {
private final Uri uri; private final Uri uri;
private final String id;
private final ArrayList<FakeDownloader> downloaders; private final ArrayList<FakeDownloader> downloaders;
private int createdDownloaderCount = 0; private int createdDownloaderCount = 0;
private FakeDownloader downloader; private FakeDownloader downloader;
private TaskWrapper taskWrapper; private final TaskWrapper taskWrapper;
private DownloadRunner(Uri uri) { private DownloadRunner(Uri uri) {
this.uri = uri; this.uri = uri;
id = uri.toString();
downloaders = new ArrayList<>(); downloaders = new ArrayList<>();
downloader = addDownloader(); downloader = addDownloader();
downloaderFactory.registerDownloadRunner(this); downloaderFactory.registerDownloadRunner(this);
taskWrapper = new TaskWrapper(id);
} }
private DownloadRunner postRemoveAction() { private DownloadRunner postRemoveAction() {
return postAction(createRemoveAction(uri)); runOnMainThread(() -> downloadManager.removeDownload(id));
return this;
} }
private DownloadRunner postDownloadAction(StreamKey... keys) { private DownloadRunner postDownloadAction(StreamKey... keys) {
return postAction(createDownloadAction(uri, keys)); DownloadAction downloadAction =
} DownloadAction.createDownloadAction(
id,
private DownloadRunner postAction(DownloadAction action) { DownloadAction.TYPE_PROGRESSIVE,
runOnMainThread(() -> downloadManager.handleAction(action)); uri,
if (taskWrapper == null) { Arrays.asList(keys),
taskWrapper = new TaskWrapper(action.id); /* customCacheKey= */ null,
} else { /* data= */ null);
assertThat(action.id).isEqualTo(taskWrapper.taskId); runOnMainThread(() -> downloadManager.addDownload(downloadAction));
}
return this; return this;
} }
@ -554,10 +541,6 @@ public class DownloadManagerTest {
return taskWrapper; return taskWrapper;
} }
public void setTask(TaskWrapper taskWrapper) {
this.taskWrapper = taskWrapper;
}
private void assertCreatedDownloaderCount(int count) { private void assertCreatedDownloaderCount(int count) {
assertThat(createdDownloaderCount).isEqualTo(count); assertThat(createdDownloaderCount).isEqualTo(count);
} }
@ -599,36 +582,9 @@ public class DownloadManagerTest {
} }
private TaskWrapper assertState(@State int expectedState) { private TaskWrapper assertState(@State int expectedState) {
ArrayList<Integer> receivedStates = new ArrayList<>(); downloadManagerListener.assertState(taskId, expectedState, ASSERT_TRUE_TIMEOUT);
while (true) {
Integer state = null;
try {
state = downloadManagerListener.pollStateChange(taskId, ASSERT_TRUE_TIMEOUT);
} catch (InterruptedException e) {
fail(e.getMessage());
}
if (state != null) {
if (expectedState == state) {
return this; return this;
} }
receivedStates.add(state);
} else {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < receivedStates.size(); i++) {
if (i > 0) {
sb.append(',');
}
sb.append(DownloadState.getStateString(receivedStates.get(i)));
}
fail(
String.format(
Locale.US,
"expected:<%s> but was:<%s>",
DownloadState.getStateString(expectedState),
sb));
}
}
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
@ -647,20 +603,6 @@ public class DownloadManagerTest {
} }
} }
private static DownloadAction createDownloadAction(Uri uri, StreamKey... keys) {
return DownloadAction.createDownloadAction(
DownloadAction.TYPE_PROGRESSIVE,
uri,
Arrays.asList(keys),
/* customCacheKey= */ null,
/* data= */ null);
}
private static DownloadAction createRemoveAction(Uri uri) {
return DownloadAction.createRemoveAction(
DownloadAction.TYPE_PROGRESSIVE, uri, /* customCacheKey= */ null);
}
private static final class FakeDownloaderFactory implements DownloaderFactory { private static final class FakeDownloaderFactory implements DownloaderFactory {
private final HashMap<Uri, DownloadRunner> downloaders; private final HashMap<Uri, DownloadRunner> downloaders;

View File

@ -118,20 +118,6 @@ public class DownloadStateTest {
assertEqual(mergedDownloadState, expectedDownloadState); assertEqual(mergedDownloadState, expectedDownloadState);
} }
@Test
public void mergeAction_queuedDownloadRemoveAction_stateBecomesRemoving() {
DownloadAction downloadAction = createRemoveAction();
DownloadStateBuilder downloadStateBuilder =
new DownloadStateBuilder(downloadAction).setState(DownloadState.STATE_QUEUED);
DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.mergeAction(downloadAction);
DownloadState expectedDownloadState =
downloadStateBuilder.setState(DownloadState.STATE_REMOVING).build();
assertEqual(mergedDownloadState, expectedDownloadState);
}
@Test @Test
public void mergeAction_removingDownloadDownloadAction_stateBecomesRestarting() { public void mergeAction_removingDownloadDownloadAction_stateBecomesRestarting() {
DownloadAction downloadAction = createDownloadAction(); DownloadAction downloadAction = createDownloadAction();
@ -179,22 +165,6 @@ public class DownloadStateTest {
assertEqual(mergedDownloadState, downloadState); assertEqual(mergedDownloadState, downloadState);
} }
@Test
public void mergeAction_stoppedDownloadRemoveAction_stateBecomesRemoving() {
DownloadAction downloadAction = createRemoveAction();
DownloadStateBuilder downloadStateBuilder =
new DownloadStateBuilder(downloadAction)
.setState(DownloadState.STATE_STOPPED)
.setManualStopReason(DownloadState.MANUAL_STOP_REASON_UNDEFINED);
DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.mergeAction(downloadAction);
DownloadState expectedDownloadState =
downloadStateBuilder.setState(DownloadState.STATE_REMOVING).build();
assertEqual(mergedDownloadState, expectedDownloadState);
}
@Test @Test
public void mergeAction_manualStopReasonSetButNotInStoppedState_stateBecomesStopped() { public void mergeAction_manualStopReasonSetButNotInStoppedState_stateBecomesStopped() {
DownloadAction downloadAction = createDownloadAction(); DownloadAction downloadAction = createDownloadAction();
@ -227,20 +197,6 @@ public class DownloadStateTest {
assertEqual(mergedDownloadState, expectedDownloadState); assertEqual(mergedDownloadState, expectedDownloadState);
} }
@Test
public void mergeAction_restartingDownloadRemoveAction_stateBecomesRemoving() {
DownloadAction downloadAction = createRemoveAction();
DownloadStateBuilder downloadStateBuilder =
new DownloadStateBuilder(downloadAction).setState(DownloadState.STATE_RESTARTING);
DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.mergeAction(downloadAction);
DownloadState expectedDownloadState =
downloadStateBuilder.setState(DownloadState.STATE_REMOVING).build();
assertEqual(mergedDownloadState, expectedDownloadState);
}
@Test @Test
public void mergeAction_returnsMergedKeys() { public void mergeAction_returnsMergedKeys() {
StreamKey streamKey1 = new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0); StreamKey streamKey1 = new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0);
@ -340,9 +296,4 @@ public class DownloadStateTest {
/* customCacheKey= */ null, /* customCacheKey= */ null,
/* data= */ null); /* data= */ null);
} }
private DownloadAction createRemoveAction() {
return DownloadAction.createRemoveAction(
DownloadAction.TYPE_DASH, testUri, /* customCacheKey= */ null);
}
} }

View File

@ -22,7 +22,8 @@ import java.nio.charset.Charset;
/** Data for DASH downloading tests. */ /** Data for DASH downloading tests. */
/* package */ interface DashDownloadTestData { /* package */ interface DashDownloadTestData {
Uri TEST_MPD_URI = Uri.parse("test.mpd"); String TEST_ID = "test.mpd";
Uri TEST_MPD_URI = Uri.parse(TEST_ID);
byte[] TEST_MPD = byte[] TEST_MPD =
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.source.dash.offline; package com.google.android.exoplayer2.source.dash.offline;
import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_ID;
import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_MPD; import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_MPD;
import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_MPD_URI; import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_MPD_URI;
import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCacheEmpty; import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCacheEmpty;
@ -22,9 +23,7 @@ import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedDa
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.content.Context; import android.content.Context;
import android.net.Uri;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.offline.DefaultDownloadIndex; import com.google.android.exoplayer2.offline.DefaultDownloadIndex;
@ -230,11 +229,16 @@ public class DownloadManagerDashTest {
} }
private void handleDownloadAction(StreamKey... keys) { private void handleDownloadAction(StreamKey... keys) {
downloadManager.handleAction(newAction(TEST_MPD_URI, false, null, keys)); ArrayList<StreamKey> keysList = new ArrayList<>();
Collections.addAll(keysList, keys);
DownloadAction action =
DownloadAction.createDownloadAction(
DownloadAction.TYPE_DASH, TEST_MPD_URI, keysList, /* customCacheKey= */ null, null);
downloadManager.addDownload(action);
} }
private void handleRemoveAction() { private void handleRemoveAction() {
downloadManager.handleAction(newAction(TEST_MPD_URI, true, null)); downloadManager.removeDownload(TEST_ID);
} }
private void createDownloadManager() { private void createDownloadManager() {
@ -257,20 +261,4 @@ public class DownloadManagerDashTest {
}); });
} }
private static DownloadAction newAction(
Uri uri, boolean isRemoveAction, @Nullable byte[] data, StreamKey... keys) {
ArrayList<StreamKey> keysList = new ArrayList<>();
Collections.addAll(keysList, keys);
DownloadAction result;
if (isRemoveAction) {
result =
DownloadAction.createRemoveAction(
DownloadAction.TYPE_DASH, uri, /* customCacheKey= */ null);
} else {
result =
DownloadAction.createDownloadAction(
DownloadAction.TYPE_DASH, uri, keysList, /* customCacheKey= */ null, data);
}
return result;
}
} }

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.source.dash.offline; package com.google.android.exoplayer2.source.dash.offline;
import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_ID;
import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_MPD; import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_MPD;
import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_MPD_URI; import static com.google.android.exoplayer2.source.dash.offline.DashDownloadTestData.TEST_MPD_URI;
import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCacheEmpty; import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCacheEmpty;
@ -22,7 +23,6 @@ import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedDa
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
@ -187,37 +187,29 @@ public class DownloadServiceDashTest {
assertCacheEmpty(cache); assertCacheEmpty(cache);
} }
private void removeAll() throws Throwable { private void removeAll() {
callDownloadServiceOnStart(newAction(TEST_MPD_URI, true, null));
}
private void downloadKeys(StreamKey... keys) {
callDownloadServiceOnStart(newAction(TEST_MPD_URI, false, null, keys));
}
private void callDownloadServiceOnStart(final DownloadAction action) {
dummyMainThread.runOnMainThread( dummyMainThread.runOnMainThread(
() -> { () -> {
Intent startIntent = Intent startIntent =
DownloadService.buildAddActionIntent(context, DownloadService.class, action, false); DownloadService.buildRemoveDownloadIntent(
context, DownloadService.class, TEST_ID, /* foreground= */ false);
dashDownloadService.onStartCommand(startIntent, 0, 0); dashDownloadService.onStartCommand(startIntent, 0, 0);
}); });
} }
private static DownloadAction newAction( private void downloadKeys(StreamKey... keys) {
Uri uri, boolean isRemoveAction, @Nullable byte[] data, StreamKey... keys) {
ArrayList<StreamKey> keysList = new ArrayList<>(); ArrayList<StreamKey> keysList = new ArrayList<>();
Collections.addAll(keysList, keys); Collections.addAll(keysList, keys);
DownloadAction result; DownloadAction action =
if (isRemoveAction) {
result =
DownloadAction.createRemoveAction(
DownloadAction.TYPE_DASH, uri, /* customCacheKey= */ null);
} else {
result =
DownloadAction.createDownloadAction( DownloadAction.createDownloadAction(
DownloadAction.TYPE_DASH, uri, keysList, /* customCacheKey= */ null, data); DownloadAction.TYPE_DASH, TEST_MPD_URI, keysList, /* customCacheKey= */ null, null);
} dummyMainThread.runOnMainThread(
return result; () -> {
Intent startIntent =
DownloadService.buildAddActionIntent(
context, DownloadService.class, action, /* foreground= */ false);
dashDownloadService.onStartCommand(startIntent, 0, 0);
});
} }
} }

View File

@ -16,11 +16,15 @@
package com.google.android.exoplayer2.testutil; package com.google.android.exoplayer2.testutil;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import com.google.android.exoplayer2.offline.DownloadManager; import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadState; import com.google.android.exoplayer2.offline.DownloadState;
import com.google.android.exoplayer2.offline.DownloadState.State;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -115,4 +119,37 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
return actionStates.get(taskId); return actionStates.get(taskId);
} }
} }
public void assertState(String taskId, @State int expectedState, int timeoutMs) {
ArrayList<Integer> receivedStates = new ArrayList<>();
while (true) {
Integer state = null;
try {
state = pollStateChange(taskId, timeoutMs);
} catch (InterruptedException e) {
fail(e.getMessage());
}
if (state != null) {
if (expectedState == state) {
return;
}
receivedStates.add(state);
} else {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < receivedStates.size(); i++) {
if (i > 0) {
sb.append(',');
}
sb.append(DownloadState.getStateString(receivedStates.get(i)));
}
fail(
String.format(
Locale.US,
"for download (%s) expected:<%s> but was:<%s>",
taskId,
DownloadState.getStateString(expectedState),
sb));
}
}
}
} }