Commit facd32e6 by eguven Committed by Toni

Remove DownloadAction.createRemoveAction

PiperOrigin-RevId: 240557315
parent d4f5c9c7
...@@ -15,6 +15,7 @@ ...@@ -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; ...@@ -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 { ...@@ -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);
} }
......
...@@ -17,7 +17,6 @@ package com.google.android.exoplayer2.offline; ...@@ -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; ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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,37 +133,26 @@ public final class DownloadAction { ...@@ -152,37 +133,26 @@ 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) { ArrayList<StreamKey> mutableKeys = new ArrayList<>(keys);
Assertions.checkArgument(keys.isEmpty()); Collections.sort(mutableKeys);
Assertions.checkArgument(data == null); this.keys = Collections.unmodifiableList(mutableKeys);
this.keys = Collections.emptyList(); this.data = data != null ? Arrays.copyOf(data, data.length) : Util.EMPTY_BYTE_ARRAY;
this.data = Util.EMPTY_BYTE_ARRAY;
} else {
ArrayList<StreamKey> mutableKeys = new ArrayList<>(keys);
Collections.sort(mutableKeys);
this.keys = Collections.unmodifiableList(mutableKeys);
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. */
...@@ -211,7 +181,6 @@ public final class DownloadAction { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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) {
......
...@@ -342,11 +342,11 @@ public final class DownloadManager { ...@@ -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 { ...@@ -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,15 +543,14 @@ public final class DownloadManager { ...@@ -541,15 +543,14 @@ public final class DownloadManager {
} }
private void processDownloadUpdateQueue() { private void processDownloadUpdateQueue() {
if (loadingDownload || dowloadUpdateQueue.isEmpty()) { while (!loadingDownload && !dowloadUpdateQueue.isEmpty()) {
return; DownloadUpdater downloadUpdater = dowloadUpdateQueue.remove();
} Download download = getDownload(downloadUpdater.id);
DownloadUpdater downloadUpdater = dowloadUpdateQueue.remove(); if (download != null) {
Download download = getDownload(downloadUpdater.id); downloadUpdater.onExisting(download);
if (download != null) { } else {
downloadUpdater.onExisting(download); loadDownload(downloadUpdater);
} else { }
loadDownload(downloadUpdater);
} }
} }
......
...@@ -270,11 +270,14 @@ public abstract class DownloadService extends Service { ...@@ -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 { ...@@ -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 { ...@@ -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;
......
...@@ -166,7 +166,7 @@ public final class DownloadState { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 (currentState == STATE_REMOVING || currentState == STATE_RESTARTING) {
if (remove) { return STATE_RESTARTING;
nextState = STATE_REMOVING; } else if (isStopped) {
return STATE_STOPPED;
} else { } else {
if (currentState == STATE_REMOVING || currentState == STATE_RESTARTING) { return STATE_QUEUED;
nextState = STATE_RESTARTING;
} else if (isStopped) {
nextState = STATE_STOPPED;
} else {
nextState = 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 {
......
...@@ -397,7 +397,6 @@ public class DownloadHelperTest { ...@@ -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(
......
...@@ -127,16 +127,11 @@ public class DownloadIndexUtilTest { ...@@ -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)
......
...@@ -119,20 +119,6 @@ public class DownloadStateTest { ...@@ -119,20 +119,6 @@ public class DownloadStateTest {
} }
@Test @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
public void mergeAction_removingDownloadDownloadAction_stateBecomesRestarting() { public void mergeAction_removingDownloadDownloadAction_stateBecomesRestarting() {
DownloadAction downloadAction = createDownloadAction(); DownloadAction downloadAction = createDownloadAction();
DownloadStateBuilder downloadStateBuilder = DownloadStateBuilder downloadStateBuilder =
...@@ -180,22 +166,6 @@ public class DownloadStateTest { ...@@ -180,22 +166,6 @@ public class DownloadStateTest {
} }
@Test @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
public void mergeAction_manualStopReasonSetButNotInStoppedState_stateBecomesStopped() { public void mergeAction_manualStopReasonSetButNotInStoppedState_stateBecomesStopped() {
DownloadAction downloadAction = createDownloadAction(); DownloadAction downloadAction = createDownloadAction();
DownloadStateBuilder downloadStateBuilder = DownloadStateBuilder downloadStateBuilder =
...@@ -228,20 +198,6 @@ public class DownloadStateTest { ...@@ -228,20 +198,6 @@ public class DownloadStateTest {
} }
@Test @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
public void mergeAction_returnsMergedKeys() { public void mergeAction_returnsMergedKeys() {
StreamKey streamKey1 = new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0); StreamKey streamKey1 = new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0);
StreamKey streamKey2 = new StreamKey(/* groupIndex= */ 1, /* trackIndex= */ 1); StreamKey streamKey2 = new StreamKey(/* groupIndex= */ 1, /* trackIndex= */ 1);
...@@ -340,9 +296,4 @@ public class DownloadStateTest { ...@@ -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);
}
} }
...@@ -22,7 +22,8 @@ import java.nio.charset.Charset; ...@@ -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"
......
...@@ -15,6 +15,7 @@ ...@@ -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 ...@@ -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 { ...@@ -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 { ...@@ -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;
}
} }
...@@ -15,6 +15,7 @@ ...@@ -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 ...@@ -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 { ...@@ -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) { DownloadAction.createDownloadAction(
result = DownloadAction.TYPE_DASH, TEST_MPD_URI, keysList, /* customCacheKey= */ null, null);
DownloadAction.createRemoveAction( dummyMainThread.runOnMainThread(
DownloadAction.TYPE_DASH, uri, /* customCacheKey= */ null); () -> {
} else { Intent startIntent =
result = DownloadService.buildAddActionIntent(
DownloadAction.createDownloadAction( context, DownloadService.class, action, /* foreground= */ false);
DownloadAction.TYPE_DASH, uri, keysList, /* customCacheKey= */ null, data); dashDownloadService.onStartCommand(startIntent, 0, 0);
} });
return result;
} }
} }
...@@ -16,11 +16,15 @@ ...@@ -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 ...@@ -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));
}
}
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment