Further clean up DownloadActions + DownloadActivity

- Made parts of DownloadActions public that were previously hidden.
  This is necessary so that when an app is listening to the
  DownloadManager, it can tell something about the tasks.
- Simplified DownloadActivity some more. The helpers may migrate
  into their corresponding modules at some point, and also be
  converted to return structured TrackGroupArrays rather than a
  flat list of Formats.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=195269824
This commit is contained in:
olly 2018-05-03 10:13:10 -07:00 committed by Oliver Woodman
parent 5a1431c904
commit c5bf7f4513
22 changed files with 430 additions and 495 deletions

View File

@ -20,15 +20,14 @@ import static com.google.android.exoplayer2.demo.PlayerActivity.EXTENSION_EXTRA;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.SparseBooleanArray;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.offline.DownloadAction;
import com.google.android.exoplayer2.offline.DownloadService;
import com.google.android.exoplayer2.offline.ProgressiveDownloadAction;
@ -70,11 +69,9 @@ public class DownloadActivity extends Activity {
private String sampleName;
private TrackNameProvider trackNameProvider;
private AsyncTask manifestDownloaderTask;
private DownloadUtilMethods downloadUtilMethods;
private DownloadHelper<? extends Parcelable> downloadHelper;
private ListView representationList;
private ArrayAdapter<RepresentationItem> arrayAdapter;
private ArrayAdapter<String> arrayAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -100,37 +97,44 @@ public class DownloadActivity extends Activity {
int type = Util.inferContentType(sampleUri, extension);
switch (type) {
case C.TYPE_DASH:
downloadUtilMethods = new DashDownloadUtilMethods(sampleUri, manifestDataSourceFactory);
downloadHelper = new DashDownloadHelper(sampleUri, manifestDataSourceFactory);
break;
case C.TYPE_SS:
downloadUtilMethods = new SsDownloadUtilMethods(sampleUri, manifestDataSourceFactory);
downloadHelper = new SsDownloadHelper(sampleUri, manifestDataSourceFactory);
break;
case C.TYPE_HLS:
downloadUtilMethods = new HlsDownloadUtilMethods(sampleUri, manifestDataSourceFactory);
downloadHelper = new HlsDownloadHelper(sampleUri, manifestDataSourceFactory);
break;
case C.TYPE_OTHER:
downloadUtilMethods = new ProgressiveDownloadUtilMethods(sampleUri);
downloadHelper = new ProgressiveDownloadHelper(sampleUri);
break;
default:
throw new IllegalStateException("Unsupported type: " + type);
}
updateRepresentationsList();
}
new Thread() {
@Override
protected void onStart() {
super.onStart();
updateRepresentationsList();
}
public void run() {
try {
downloadHelper.init();
runOnUiThread(
new Runnable() {
@Override
protected void onStop() {
if (manifestDownloaderTask != null) {
manifestDownloaderTask.cancel(true);
manifestDownloaderTask = null;
public void run() {
onInitialized();
}
super.onStop();
});
} catch (IOException e) {
runOnUiThread(
new Runnable() {
@Override
public void run() {
onInitializationError();
}
});
}
}
}.start();
}
// This method is referenced in the layout file
@ -141,21 +145,31 @@ public class DownloadActivity extends Activity {
startDownload();
} else if (id == R.id.remove_all_button) {
removeDownload();
} else if (id == R.id.refresh_button) {
updateRepresentationsList();
} else if (id == R.id.play_button) {
playDownload();
}
}
private void onInitialized() {
for (int i = 0; i < downloadHelper.getTrackCount(); i++) {
arrayAdapter.add(trackNameProvider.getTrackName(downloadHelper.getTrackFormat(i)));
}
}
private void onInitializationError() {
Toast.makeText(
getApplicationContext(), R.string.download_manifest_load_error, Toast.LENGTH_LONG)
.show();
}
private void startDownload() {
ArrayList<Object> representationKeys = getSelectedRepresentationKeys();
if (!representationKeys.isEmpty()) {
int[] selectedTrackIndices = getSelectedTrackIndices();
if (selectedTrackIndices.length > 0) {
DownloadService.addDownloadAction(
this,
DemoDownloadService.class,
downloadUtilMethods.getDownloadAction(
/* isRemoveAction= */ false, sampleName, representationKeys));
downloadHelper.getDownloadAction(
/* isRemoveAction= */ false, sampleName, selectedTrackIndices));
}
}
@ -163,123 +177,87 @@ public class DownloadActivity extends Activity {
DownloadService.addDownloadAction(
this,
DemoDownloadService.class,
downloadUtilMethods.getDownloadAction(
/* isRemoveAction= */ true, sampleName, Collections.emptyList()));
downloadHelper.getDownloadAction(/* isRemoveAction= */ true, sampleName));
for (int i = 0; i < representationList.getChildCount(); i++) {
representationList.setItemChecked(i, false);
}
}
@SuppressWarnings("SuspiciousToArrayCall")
private void playDownload() {
ArrayList<Object> selectedRepresentationKeys = getSelectedRepresentationKeys();
if (selectedRepresentationKeys.isEmpty()) {
int[] selectedTrackIndices = getSelectedTrackIndices();
List<? extends Parcelable> keys = downloadHelper.getTrackKeys(selectedTrackIndices);
if (keys.isEmpty()) {
playerIntent.removeExtra(PlayerActivity.MANIFEST_FILTER_EXTRA);
} else {
Parcelable[] parcelables = new Parcelable[selectedRepresentationKeys.size()];
selectedRepresentationKeys.toArray(parcelables);
playerIntent.putExtra(
PlayerActivity.MANIFEST_FILTER_EXTRA, new ParcelableArray<>(parcelables));
Parcelable[] keysArray = keys.toArray(new Parcelable[selectedTrackIndices.length]);
playerIntent.putExtra(PlayerActivity.MANIFEST_FILTER_EXTRA, new ParcelableArray<>(keysArray));
}
startActivity(playerIntent);
}
private void updateRepresentationsList() {
if (manifestDownloaderTask != null) {
manifestDownloaderTask.cancel(true);
private int[] getSelectedTrackIndices() {
ArrayList<Integer> checkedIndices = new ArrayList<>();
for (int i = 0; i < representationList.getChildCount(); i++) {
if (representationList.isItemChecked(i)) {
checkedIndices.add(i);
}
manifestDownloaderTask = new ManifestDownloaderTask().execute();
}
return Util.toArray(checkedIndices);
}
private ArrayList<Object> getSelectedRepresentationKeys() {
SparseBooleanArray checked = representationList.getCheckedItemPositions();
ArrayList<Object> representations = new ArrayList<>(checked.size());
for (int i = 0; i < checked.size(); i++) {
if (checked.valueAt(i)) {
int position = checked.keyAt(i);
RepresentationItem item =
(RepresentationItem) representationList.getItemAtPosition(position);
representations.add(item.key);
}
}
return representations;
private abstract static class DownloadHelper<K extends Parcelable> {
protected static final Format DUMMY_FORMAT =
Format.createContainerFormat(null, null, null, null, Format.NO_VALUE, 0, null);
protected final Uri uri;
protected final DataSource.Factory dataSourceFactory;
protected final List<Format> trackFormats;
protected final List<K> trackKeys;
public DownloadHelper(Uri uri, DataSource.Factory dataSourceFactory) {
this.uri = uri;
this.dataSourceFactory = dataSourceFactory;
trackFormats = new ArrayList<>();
trackKeys = new ArrayList<>();
}
private static final class RepresentationItem {
public abstract void init() throws IOException;
public final Parcelable key;
public final String title;
public RepresentationItem(Parcelable key, String title) {
this.key = key;
this.title = title;
public int getTrackCount() {
return trackFormats.size();
}
@Override
public String toString() {
return title;
}
public Format getTrackFormat(int trackIndex) {
return trackFormats.get(trackIndex);
}
private final class ManifestDownloaderTask
extends AsyncTask<Void, Void, List<RepresentationItem>> {
@Override
protected List<RepresentationItem> doInBackground(Void... ignore) {
try {
return downloadUtilMethods.loadRepresentationItems(trackNameProvider);
} catch (IOException | InterruptedException e) {
return null;
public List<K> getTrackKeys(int... trackIndices) {
if (trackFormats.size() == 1 && trackFormats.get(0) == DUMMY_FORMAT) {
return Collections.emptyList();
}
List<K> keys = new ArrayList<>(trackIndices.length);
for (int trackIndex : trackIndices) {
keys.add(trackKeys.get(trackIndex));
}
@Override
protected void onPostExecute(List<RepresentationItem> items) {
if (items == null) {
Toast.makeText(
getApplicationContext(), R.string.download_manifest_load_error, Toast.LENGTH_LONG)
.show();
return;
return keys;
}
arrayAdapter.clear();
for (RepresentationItem representationItem : items) {
arrayAdapter.add(representationItem);
}
}
}
private abstract static class DownloadUtilMethods {
protected final Uri manifestUri;
public DownloadUtilMethods(Uri manifestUri) {
this.manifestUri = manifestUri;
}
public abstract List<RepresentationItem> loadRepresentationItems(
TrackNameProvider trackNameProvider) throws IOException, InterruptedException;
public abstract DownloadAction getDownloadAction(
boolean isRemoveAction, String sampleName, List<Object> representationKeys);
boolean isRemoveAction, String sampleName, int... trackIndices);
}
private static final class DashDownloadUtilMethods extends DownloadUtilMethods {
private static final class DashDownloadHelper extends DownloadHelper<RepresentationKey> {
private final DataSource.Factory manifestDataSourceFactory;
public DashDownloadUtilMethods(Uri manifestUri, DataSource.Factory manifestDataSourceFactory) {
super(manifestUri);
this.manifestDataSourceFactory = manifestDataSourceFactory;
public DashDownloadHelper(Uri uri, DataSource.Factory dataSourceFactory) {
super(uri, dataSourceFactory);
}
@Override
public List<RepresentationItem> loadRepresentationItems(TrackNameProvider trackNameProvider)
throws IOException, InterruptedException {
DataSource dataSource = manifestDataSourceFactory.createDataSource();
DashManifest manifest =
ParsingLoadable.load(dataSource, new DashManifestParser(), manifestUri);
public void init() throws IOException {
DataSource dataSource = dataSourceFactory.createDataSource();
DashManifest manifest = ParsingLoadable.load(dataSource, new DashManifestParser(), uri);
ArrayList<RepresentationItem> items = new ArrayList<>();
for (int periodIndex = 0; periodIndex < manifest.getPeriodCount(); periodIndex++) {
List<AdaptationSet> adaptationSets = manifest.getPeriod(periodIndex).adaptationSets;
for (int adaptationIndex = 0; adaptationIndex < adaptationSets.size(); adaptationIndex++) {
@ -287,119 +265,98 @@ public class DownloadActivity extends Activity {
adaptationSets.get(adaptationIndex).representations;
int representationsCount = representations.size();
for (int i = 0; i < representationsCount; i++) {
RepresentationKey key = new RepresentationKey(periodIndex, adaptationIndex, i);
String trackName = trackNameProvider.getTrackName(representations.get(i).format);
items.add(new RepresentationItem(key, trackName));
trackFormats.add(representations.get(i).format);
trackKeys.add(new RepresentationKey(periodIndex, adaptationIndex, i));
}
}
}
return items;
}
@Override
public DownloadAction getDownloadAction(
boolean isRemoveAction, String sampleName, List<Object> representationKeys) {
RepresentationKey[] keys =
representationKeys.toArray(new RepresentationKey[representationKeys.size()]);
return new DashDownloadAction(isRemoveAction, sampleName, manifestUri, keys);
boolean isRemoveAction, String sampleName, int... trackIndices) {
return new DashDownloadAction(uri, isRemoveAction, sampleName, getTrackKeys(trackIndices));
}
}
}
private static final class HlsDownloadHelper extends DownloadHelper<RenditionKey> {
private static final class HlsDownloadUtilMethods extends DownloadUtilMethods {
private final DataSource.Factory manifestDataSourceFactory;
public HlsDownloadUtilMethods(Uri manifestUri, DataSource.Factory manifestDataSourceFactory) {
super(manifestUri);
this.manifestDataSourceFactory = manifestDataSourceFactory;
public HlsDownloadHelper(Uri uri, DataSource.Factory dataSourceFactory) {
super(uri, dataSourceFactory);
}
@Override
public List<RepresentationItem> loadRepresentationItems(TrackNameProvider trackNameProvider)
throws IOException, InterruptedException {
DataSource dataSource = manifestDataSourceFactory.createDataSource();
HlsPlaylist<?> playlist =
ParsingLoadable.load(dataSource, new HlsPlaylistParser(), manifestUri);
public void init() throws IOException {
DataSource dataSource = dataSourceFactory.createDataSource();
HlsPlaylist<?> playlist = ParsingLoadable.load(dataSource, new HlsPlaylistParser(), uri);
ArrayList<RepresentationItem> items = new ArrayList<>();
if (playlist instanceof HlsMediaPlaylist) {
items.add(new RepresentationItem(null, "Stream"));
trackFormats.add(DUMMY_FORMAT);
} else {
HlsMasterPlaylist masterPlaylist = (HlsMasterPlaylist) playlist;
addRepresentationItems(masterPlaylist.variants, RenditionKey.GROUP_VARIANTS, items);
addRepresentationItems(masterPlaylist.audios, RenditionKey.GROUP_AUDIOS, items);
addRepresentationItems(masterPlaylist.subtitles, RenditionKey.GROUP_SUBTITLES, items);
addRepresentationItems(masterPlaylist.variants, RenditionKey.GROUP_VARIANTS);
addRepresentationItems(masterPlaylist.audios, RenditionKey.GROUP_AUDIOS);
addRepresentationItems(masterPlaylist.subtitles, RenditionKey.GROUP_SUBTITLES);
}
return items;
}
private void addRepresentationItems(
List<HlsUrl> renditions, int renditionGroup, List<RepresentationItem> out) {
private void addRepresentationItems(List<HlsUrl> renditions, int renditionGroup) {
for (int i = 0; i < renditions.size(); i++) {
out.add(new RepresentationItem(new RenditionKey(renditionGroup, i), renditions.get(i).url));
trackFormats.add(renditions.get(i).format);
trackKeys.add(new RenditionKey(renditionGroup, i));
}
}
@Override
public DownloadAction getDownloadAction(
boolean isRemoveAction, String sampleName, List<Object> representationKeys) {
RenditionKey[] keys = representationKeys.toArray(new RenditionKey[representationKeys.size()]);
return new HlsDownloadAction(isRemoveAction, sampleName, manifestUri, keys);
boolean isRemoveAction, String sampleName, int... trackIndices) {
return new HlsDownloadAction(uri, isRemoveAction, sampleName, getTrackKeys(trackIndices));
}
}
private static final class SsDownloadUtilMethods extends DownloadUtilMethods {
private static final class SsDownloadHelper extends DownloadHelper<TrackKey> {
private final DataSource.Factory manifestDataSourceFactory;
public SsDownloadUtilMethods(Uri manifestUri, DataSource.Factory manifestDataSourceFactory) {
super(manifestUri);
this.manifestDataSourceFactory = manifestDataSourceFactory;
public SsDownloadHelper(Uri uri, DataSource.Factory dataSourceFactory) {
super(uri, dataSourceFactory);
}
@Override
public List<RepresentationItem> loadRepresentationItems(TrackNameProvider trackNameProvider)
throws IOException, InterruptedException {
DataSource dataSource = manifestDataSourceFactory.createDataSource();
SsManifest manifest = ParsingLoadable.load(dataSource, new SsManifestParser(), manifestUri);
public void init() throws IOException {
DataSource dataSource = dataSourceFactory.createDataSource();
SsManifest manifest = ParsingLoadable.load(dataSource, new SsManifestParser(), uri);
ArrayList<RepresentationItem> items = new ArrayList<>();
for (int i = 0; i < manifest.streamElements.length; i++) {
SsManifest.StreamElement streamElement = manifest.streamElements[i];
for (int j = 0; j < streamElement.formats.length; j++) {
TrackKey key = new TrackKey(i, j);
String trackName = trackNameProvider.getTrackName(streamElement.formats[j]);
items.add(new RepresentationItem(key, trackName));
trackFormats.add(streamElement.formats[j]);
trackKeys.add(new TrackKey(i, j));
}
}
return items;
}
@Override
public DownloadAction getDownloadAction(
boolean isRemoveAction, String sampleName, List<Object> representationKeys) {
TrackKey[] keys = representationKeys.toArray(new TrackKey[representationKeys.size()]);
return new SsDownloadAction(isRemoveAction, sampleName, manifestUri, keys);
boolean isRemoveAction, String sampleName, int... trackIndices) {
return new SsDownloadAction(uri, isRemoveAction, sampleName, getTrackKeys(trackIndices));
}
}
private static final class ProgressiveDownloadUtilMethods extends DownloadUtilMethods {
private static final class ProgressiveDownloadHelper extends DownloadHelper<Parcelable> {
public ProgressiveDownloadUtilMethods(Uri manifestUri) {
super(manifestUri);
public ProgressiveDownloadHelper(Uri uri) {
super(uri, null);
}
@Override
public List<RepresentationItem> loadRepresentationItems(TrackNameProvider trackNameProvider) {
return Collections.singletonList(new RepresentationItem(null, "Stream"));
public void init() {
trackFormats.add(DUMMY_FORMAT);
}
@Override
public DownloadAction getDownloadAction(
boolean isRemoveAction, String sampleName, List<Object> representationKeys) {
boolean isRemoveAction, String sampleName, int... trackIndices) {
return new ProgressiveDownloadAction(
isRemoveAction, sampleName, manifestUri, /* customCacheKey= */ null);
uri, isRemoveAction, sampleName, /* customCacheKey= */ null);
}
}
}

View File

@ -37,12 +37,6 @@
android:onClick="onClick"
android:text="@string/download_remove_all"/>
<Button android:id="@+id/refresh_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="@string/download_refresh"/>
<Button android:id="@+id/play_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@ -51,8 +51,6 @@
<string name="download_remove_all">Remove all</string>
<string name="download_refresh">Refresh</string>
<string name="download_only_single_period_non_drm_protected">Currently only downloading of single period non-DRM protected content is demonstrated in this app.</string>
</resources>

View File

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.offline;
import android.net.Uri;
import android.support.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@ -90,21 +91,25 @@ public abstract class DownloadAction {
public final String type;
/** The action version. */
public final int version;
/** The uri being downloaded or removed. */
public final Uri uri;
/** 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. */
/** Custom data for this action, or the empty string if no custom data was specified. */
public final String data;
/**
* @param type The type of the action.
* @param version The action version.
* @param uri The uri being downloaded or removed.
* @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.
* @param data Optional custom data for this action.
*/
protected DownloadAction(
String type, int version, boolean isRemoveAction, @Nullable String data) {
String type, int version, Uri uri, boolean isRemoveAction, @Nullable String data) {
this.type = type;
this.version = version;
this.uri = uri;
this.isRemoveAction = isRemoveAction;
this.data = data != null ? data : "";
}
@ -121,12 +126,14 @@ public abstract class DownloadAction {
return output.toByteArray();
}
/** Returns whether this is an action for the same media as the {@code other}. */
public boolean isSameMedia(DownloadAction other) {
return uri.equals(other.uri);
}
/** Serializes itself into the {@code output}. */
protected abstract void writeToStream(DataOutputStream output) throws IOException;
/** Returns whether this is an action for the same media as the {@code other}. */
protected abstract boolean isSameMedia(DownloadAction other);
/** Creates a {@link Downloader} with the given parameters. */
protected abstract Downloader createDownloader(
DownloaderConstructorHelper downloaderConstructorHelper);
@ -137,13 +144,18 @@ public abstract class DownloadAction {
return false;
}
DownloadAction that = (DownloadAction) o;
return data.equals(that.data) && isRemoveAction == that.isRemoveAction;
return type.equals(that.type)
&& version == that.version
&& uri.equals(that.uri)
&& isRemoveAction == that.isRemoveAction
&& data.equals(that.data);
}
@Override
public int hashCode() {
int result = data.hashCode();
int result = uri.hashCode();
result = 31 * result + (isRemoveAction ? 1 : 0);
result = 31 * result + data.hashCode();
return result;
}

View File

@ -18,7 +18,6 @@ package com.google.android.exoplayer2.offline;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.upstream.cache.CacheUtil;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@ -27,7 +26,7 @@ import java.io.IOException;
/** An action to download or remove downloaded progressive streams. */
public final class ProgressiveDownloadAction extends DownloadAction {
private static final String TYPE = "ProgressiveDownloadAction";
private static final String TYPE = "progressive";
private static final int VERSION = 0;
public static final Deserializer DESERIALIZER =
@ -35,28 +34,26 @@ public final class ProgressiveDownloadAction extends DownloadAction {
@Override
public ProgressiveDownloadAction readFromStream(int version, DataInputStream input)
throws IOException {
Uri uri = Uri.parse(input.readUTF());
boolean isRemoveAction = input.readBoolean();
String data = input.readUTF();
Uri uri = Uri.parse(input.readUTF());
String customCacheKey = input.readBoolean() ? input.readUTF() : null;
return new ProgressiveDownloadAction(isRemoveAction, data, uri, customCacheKey);
return new ProgressiveDownloadAction(uri, isRemoveAction, data, customCacheKey);
}
};
private final Uri uri;
private final @Nullable String customCacheKey;
public final @Nullable String customCacheKey;
/**
* @param uri Uri of the data to be downloaded.
* @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.
* @param uri Uri of the data to be downloaded.
* @param customCacheKey A custom key that uniquely identifies the original stream. If not null it
* is used for cache indexing.
*/
public ProgressiveDownloadAction(
boolean isRemoveAction, @Nullable String data, Uri uri, @Nullable String customCacheKey) {
super(TYPE, VERSION, isRemoveAction, data);
this.uri = Assertions.checkNotNull(uri);
Uri uri, boolean isRemoveAction, @Nullable String data, @Nullable String customCacheKey) {
super(TYPE, VERSION, uri, isRemoveAction, data);
this.customCacheKey = customCacheKey;
}
@ -67,9 +64,9 @@ public final class ProgressiveDownloadAction extends DownloadAction {
@Override
protected void writeToStream(DataOutputStream output) throws IOException {
output.writeUTF(uri.toString());
output.writeBoolean(isRemoveAction);
output.writeUTF(data);
output.writeUTF(uri.toString());
boolean customCacheKeySet = customCacheKey != null;
output.writeBoolean(customCacheKeySet);
if (customCacheKeySet) {
@ -78,11 +75,9 @@ public final class ProgressiveDownloadAction extends DownloadAction {
}
@Override
protected boolean isSameMedia(DownloadAction other) {
if (!(other instanceof ProgressiveDownloadAction)) {
return false;
}
return getCacheKey().equals(((ProgressiveDownloadAction) other).getCacheKey());
public boolean isSameMedia(DownloadAction other) {
return ((other instanceof ProgressiveDownloadAction)
&& getCacheKey().equals(((ProgressiveDownloadAction) other).getCacheKey()));
}
@Override
@ -94,13 +89,12 @@ public final class ProgressiveDownloadAction extends DownloadAction {
return false;
}
ProgressiveDownloadAction that = (ProgressiveDownloadAction) o;
return uri.equals(that.uri) && Util.areEqual(customCacheKey, that.customCacheKey);
return Util.areEqual(customCacheKey, that.customCacheKey);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + uri.hashCode();
result = 31 * result + (customCacheKey != null ? customCacheKey.hashCode() : 0);
return result;
}

View File

@ -21,14 +21,16 @@ import com.google.android.exoplayer2.util.Assertions;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* {@link DownloadAction} for {@link SegmentDownloader}s.
*
* @param <K> The type of the representation key object.
*/
public abstract class SegmentDownloadAction<K extends Comparable> extends DownloadAction {
public abstract class SegmentDownloadAction<K extends Comparable<K>> extends DownloadAction {
/**
* Base class for {@link SegmentDownloadAction} {@link Deserializer}s.
@ -44,78 +46,68 @@ public abstract class SegmentDownloadAction<K extends Comparable> extends Downlo
@Override
public final DownloadAction readFromStream(int version, DataInputStream input)
throws IOException {
Uri uri = Uri.parse(input.readUTF());
boolean isRemoveAction = input.readBoolean();
String data = input.readUTF();
Uri manifestUri = Uri.parse(input.readUTF());
int keyCount = input.readInt();
K[] keys = createKeyArray(keyCount);
List<K> keys = new ArrayList<>();
for (int i = 0; i < keyCount; i++) {
keys[i] = readKey(input);
keys.add(readKey(input));
}
return createDownloadAction(isRemoveAction, data, manifestUri, keys);
return createDownloadAction(uri, isRemoveAction, data, keys);
}
/** Deserializes a key from the {@code input}. */
protected abstract K readKey(DataInputStream input) throws IOException;
/** Returns a key array. */
protected abstract K[] createKeyArray(int keyCount);
/** Returns a {@link DownloadAction}. */
protected abstract DownloadAction createDownloadAction(
boolean isRemoveAction, String data, Uri manifestUri, K[] keys);
Uri manifestUri, boolean isRemoveAction, String data, List<K> keys);
}
protected final Uri manifestUri;
protected final K[] keys;
public final List<K> keys;
/**
* @param type The type of the action.
* @param version The action version.
* @param uri The URI of the media being downloaded.
* @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.
* @param data Optional custom data for this action.
* @param keys Keys of tracks to be downloaded. If empty, all tracks will be downloaded. If {@code
* removeAction} is true, {@code keys} must be empty.
*/
protected SegmentDownloadAction(
String type,
int version,
Uri uri,
boolean isRemoveAction,
@Nullable String data,
Uri manifestUri,
K[] keys) {
super(type, version, isRemoveAction, data);
this.manifestUri = manifestUri;
List<K> keys) {
super(type, version, uri, isRemoveAction, data);
if (isRemoveAction) {
Assertions.checkArgument(keys.length == 0);
this.keys = keys;
Assertions.checkArgument(keys.isEmpty());
this.keys = Collections.emptyList();
} else {
this.keys = keys.clone();
Arrays.sort(this.keys);
ArrayList<K> mutableKeys = new ArrayList<>(keys);
Collections.sort(mutableKeys);
this.keys = Collections.unmodifiableList(mutableKeys);
}
}
@Override
public final void writeToStream(DataOutputStream output) throws IOException {
output.writeUTF(uri.toString());
output.writeBoolean(isRemoveAction);
output.writeUTF(data);
output.writeUTF(manifestUri.toString());
output.writeInt(keys.length);
for (K key : keys) {
writeKey(output, key);
output.writeInt(keys.size());
for (int i = 0; i < keys.size(); i++) {
writeKey(output, keys.get(i));
}
}
/** Serializes the {@code key} into the {@code output}. */
protected abstract void writeKey(DataOutputStream output, K key) throws IOException;
@Override
public boolean isSameMedia(DownloadAction other) {
return other instanceof SegmentDownloadAction
&& manifestUri.equals(((SegmentDownloadAction<?>) other).manifestUri);
}
@Override
public boolean equals(Object o) {
if (this == o) {
@ -125,14 +117,13 @@ public abstract class SegmentDownloadAction<K extends Comparable> extends Downlo
return false;
}
SegmentDownloadAction<?> that = (SegmentDownloadAction<?>) o;
return manifestUri.equals(that.manifestUri) && Arrays.equals(keys, that.keys);
return keys.equals(that.keys);
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + manifestUri.hashCode();
result = 31 * result + Arrays.hashCode(keys);
result = 31 * result + keys.hashCode();
return result;
}

View File

@ -17,7 +17,6 @@ package com.google.android.exoplayer2.offline;
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
@ -77,20 +76,16 @@ public abstract class SegmentDownloader<M extends FilterableManifest<M, K>, K>
/**
* @param manifestUri The {@link Uri} of the manifest to be downloaded.
* @param constructorHelper a {@link DownloaderConstructorHelper} instance.
* @param trackKeys Track keys to select when downloading. If null or empty, all tracks are
* downloaded.
* @param trackKeys Track keys to select when downloading. If empty, all tracks are downloaded.
*/
public SegmentDownloader(
Uri manifestUri, DownloaderConstructorHelper constructorHelper, @Nullable K[] trackKeys) {
Uri manifestUri, DownloaderConstructorHelper constructorHelper, List<K> trackKeys) {
this.manifestUri = manifestUri;
this.cache = constructorHelper.getCache();
this.dataSource = constructorHelper.buildCacheDataSource(false);
this.offlineDataSource = constructorHelper.buildCacheDataSource(true);
this.priorityTaskManager = constructorHelper.getPriorityTaskManager();
keys = new ArrayList<>();
if (trackKeys != null) {
Collections.addAll(this.keys, trackKeys);
}
keys = new ArrayList<>(trackKeys);
totalSegments = C.LENGTH_UNSET;
}

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.offline;
import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import com.google.android.exoplayer2.offline.DownloadAction.Deserializer;
import com.google.android.exoplayer2.util.Util;
import java.io.DataInputStream;
@ -236,7 +237,7 @@ public class ActionFileTest {
public static final int VERSION = 0;
private FakeDownloadAction(String type, String data) {
super(type, VERSION, /* isRemoveAction= */ false, data);
super(type, VERSION, Uri.parse("http://test.com"), /* isRemoveAction= */ false, data);
}
@Override
@ -244,37 +245,11 @@ public class ActionFileTest {
output.writeUTF(data);
}
@Override
protected boolean isSameMedia(DownloadAction other) {
return false;
}
@Override
protected Downloader createDownloader(DownloaderConstructorHelper downloaderConstructorHelper) {
return null;
}
// auto generated code
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
FakeDownloadAction that = (FakeDownloadAction) o;
return version == that.version && data.equals(that.data) && type.equals(that.type);
}
@Override
public int hashCode() {
int result = type.hashCode();
result = 31 * result + version;
result = 31 * result + data.hashCode();
return result;
}
}
}

View File

@ -18,8 +18,8 @@ package com.google.android.exoplayer2.offline;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import android.net.Uri;
import android.os.ConditionVariable;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadListener;
import com.google.android.exoplayer2.offline.DownloadManager.TaskState;
@ -62,14 +62,20 @@ public class DownloadManagerTest {
private static final int MIN_RETRY_COUNT = 3;
private DownloadManager downloadManager;
private Uri uri1;
private Uri uri2;
private Uri uri3;
private DummyMainThread dummyMainThread;
private File actionFile;
private TestDownloadListener testDownloadListener;
private DummyMainThread dummyMainThread;
private DownloadManager downloadManager;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
uri1 = Uri.parse("http://abc.com/media1");
uri2 = Uri.parse("http://abc.com/media2");
uri3 = Uri.parse("http://abc.com/media3");
dummyMainThread = new DummyMainThread();
actionFile = Util.createTempFile(RuntimeEnvironment.application, "ExoPlayerTest");
testDownloadListener = new TestDownloadListener();
@ -85,17 +91,17 @@ public class DownloadManagerTest {
@Test
public void testDownloadActionRuns() throws Throwable {
doTestActionRuns(createDownloadAction("media 1"));
doTestActionRuns(createDownloadAction(uri1));
}
@Test
public void testRemoveActionRuns() throws Throwable {
doTestActionRuns(createRemoveAction("media 1"));
doTestActionRuns(createRemoveAction(uri1));
}
@Test
public void testDownloadRetriesThenFails() throws Throwable {
FakeDownloadAction downloadAction = createDownloadAction("media 1");
FakeDownloadAction downloadAction = createDownloadAction(uri1);
downloadAction.post();
FakeDownloader fakeDownloader = downloadAction.getFakeDownloader();
fakeDownloader.enableDownloadIOException = true;
@ -110,11 +116,11 @@ public class DownloadManagerTest {
@Test
public void testDownloadNoRetryWhenCanceled() throws Throwable {
FakeDownloadAction downloadAction = createDownloadAction("media 1").ignoreInterrupts();
FakeDownloadAction downloadAction = createDownloadAction(uri1).ignoreInterrupts();
downloadAction.getFakeDownloader().enableDownloadIOException = true;
downloadAction.post().assertStarted();
FakeDownloadAction removeAction = createRemoveAction("media 1").post();
FakeDownloadAction removeAction = createRemoveAction(uri1).post();
downloadAction.unblock().assertCanceled();
removeAction.unblock();
@ -124,7 +130,7 @@ public class DownloadManagerTest {
@Test
public void testDownloadRetriesThenContinues() throws Throwable {
FakeDownloadAction downloadAction = createDownloadAction("media 1");
FakeDownloadAction downloadAction = createDownloadAction(uri1);
downloadAction.post();
FakeDownloader fakeDownloader = downloadAction.getFakeDownloader();
fakeDownloader.enableDownloadIOException = true;
@ -143,7 +149,7 @@ public class DownloadManagerTest {
@Test
@SuppressWarnings({"NonAtomicVolatileUpdate", "NonAtomicOperationOnVolatileField"})
public void testDownloadRetryCountResetsOnProgress() throws Throwable {
FakeDownloadAction downloadAction = createDownloadAction("media 1");
FakeDownloadAction downloadAction = createDownloadAction(uri1);
downloadAction.post();
FakeDownloader fakeDownloader = downloadAction.getFakeDownloader();
fakeDownloader.enableDownloadIOException = true;
@ -163,41 +169,41 @@ public class DownloadManagerTest {
@Test
public void testDifferentMediaDownloadActionsStartInParallel() throws Throwable {
doTestActionsRunInParallel(createDownloadAction("media 1"), createDownloadAction("media 2"));
doTestActionsRunInParallel(createDownloadAction(uri1), createDownloadAction(uri2));
}
@Test
public void testDifferentMediaDifferentActionsStartInParallel() throws Throwable {
doTestActionsRunInParallel(createDownloadAction("media 1"), createRemoveAction("media 2"));
doTestActionsRunInParallel(createDownloadAction(uri1), createRemoveAction(uri2));
}
@Test
public void testSameMediaDownloadActionsStartInParallel() throws Throwable {
doTestActionsRunInParallel(createDownloadAction("media 1"), createDownloadAction("media 1"));
doTestActionsRunInParallel(createDownloadAction(uri1), createDownloadAction(uri1));
}
@Test
public void testSameMediaRemoveActionWaitsDownloadAction() throws Throwable {
doTestActionsRunSequentially(createDownloadAction("media 1"), createRemoveAction("media 1"));
doTestActionsRunSequentially(createDownloadAction(uri1), createRemoveAction(uri1));
}
@Test
public void testSameMediaDownloadActionWaitsRemoveAction() throws Throwable {
doTestActionsRunSequentially(createRemoveAction("media 1"), createDownloadAction("media 1"));
doTestActionsRunSequentially(createRemoveAction(uri1), createDownloadAction(uri1));
}
@Test
public void testSameMediaRemoveActionWaitsRemoveAction() throws Throwable {
doTestActionsRunSequentially(createRemoveAction("media 1"), createRemoveAction("media 1"));
doTestActionsRunSequentially(createRemoveAction(uri1), createRemoveAction(uri1));
}
@Test
public void testSameMediaMultipleActions() throws Throwable {
FakeDownloadAction downloadAction1 = createDownloadAction("media 1").ignoreInterrupts();
FakeDownloadAction downloadAction2 = createDownloadAction("media 1").ignoreInterrupts();
FakeDownloadAction removeAction1 = createRemoveAction("media 1");
FakeDownloadAction downloadAction3 = createDownloadAction("media 1");
FakeDownloadAction removeAction2 = createRemoveAction("media 1");
FakeDownloadAction downloadAction1 = createDownloadAction(uri1).ignoreInterrupts();
FakeDownloadAction downloadAction2 = createDownloadAction(uri1).ignoreInterrupts();
FakeDownloadAction removeAction1 = createRemoveAction(uri1);
FakeDownloadAction downloadAction3 = createDownloadAction(uri1);
FakeDownloadAction removeAction2 = createRemoveAction(uri1);
// Two download actions run in parallel.
downloadAction1.post().assertStarted();
@ -229,9 +235,9 @@ public class DownloadManagerTest {
@Test
public void testMultipleRemoveActionWaitsLastCancelsAllOther() throws Throwable {
FakeDownloadAction removeAction1 = createRemoveAction("media 1").ignoreInterrupts();
FakeDownloadAction removeAction2 = createRemoveAction("media 1");
FakeDownloadAction removeAction3 = createRemoveAction("media 1");
FakeDownloadAction removeAction1 = createRemoveAction(uri1).ignoreInterrupts();
FakeDownloadAction removeAction2 = createRemoveAction(uri1);
FakeDownloadAction removeAction3 = createRemoveAction(uri1);
removeAction1.post().assertStarted();
removeAction2.post().assertDoesNotStart();
@ -247,9 +253,9 @@ public class DownloadManagerTest {
@Test
public void testGetTasks() throws Throwable {
FakeDownloadAction removeAction = createRemoveAction("media 1");
FakeDownloadAction downloadAction1 = createDownloadAction("media 1");
FakeDownloadAction downloadAction2 = createDownloadAction("media 1");
FakeDownloadAction removeAction = createRemoveAction(uri1);
FakeDownloadAction downloadAction1 = createDownloadAction(uri1);
FakeDownloadAction downloadAction2 = createDownloadAction(uri1);
removeAction.post().assertStarted();
downloadAction1.post().assertDoesNotStart();
@ -264,9 +270,9 @@ public class DownloadManagerTest {
@Test
public void testMultipleWaitingDownloadActionStartsInParallel() throws Throwable {
FakeDownloadAction removeAction = createRemoveAction("media 1");
FakeDownloadAction downloadAction1 = createDownloadAction("media 1");
FakeDownloadAction downloadAction2 = createDownloadAction("media 1");
FakeDownloadAction removeAction = createRemoveAction(uri1);
FakeDownloadAction downloadAction1 = createDownloadAction(uri1);
FakeDownloadAction downloadAction2 = createDownloadAction(uri1);
removeAction.post().assertStarted();
downloadAction1.post().assertDoesNotStart();
@ -283,9 +289,9 @@ public class DownloadManagerTest {
@Test
public void testDifferentMediaDownloadActionsPreserveOrder() throws Throwable {
FakeDownloadAction removeAction = createRemoveAction("media 1").ignoreInterrupts();
FakeDownloadAction downloadAction1 = createDownloadAction("media 1");
FakeDownloadAction downloadAction2 = createDownloadAction("media 2");
FakeDownloadAction removeAction = createRemoveAction(uri1).ignoreInterrupts();
FakeDownloadAction downloadAction1 = createDownloadAction(uri1);
FakeDownloadAction downloadAction2 = createDownloadAction(uri2);
removeAction.post().assertStarted();
downloadAction1.post().assertDoesNotStart();
@ -302,9 +308,9 @@ public class DownloadManagerTest {
@Test
public void testDifferentMediaRemoveActionsDoNotPreserveOrder() throws Throwable {
FakeDownloadAction downloadAction = createDownloadAction("media 1").ignoreInterrupts();
FakeDownloadAction removeAction1 = createRemoveAction("media 1");
FakeDownloadAction removeAction2 = createRemoveAction("media 2");
FakeDownloadAction downloadAction = createDownloadAction(uri1).ignoreInterrupts();
FakeDownloadAction removeAction1 = createRemoveAction(uri1);
FakeDownloadAction removeAction2 = createRemoveAction(uri2);
downloadAction.post().assertStarted();
removeAction1.post().assertDoesNotStart();
@ -321,11 +327,11 @@ public class DownloadManagerTest {
@Test
public void testStopAndResume() throws Throwable {
FakeDownloadAction download1Action = createDownloadAction("media 1");
FakeDownloadAction remove2Action = createRemoveAction("media 2");
FakeDownloadAction download2Action = createDownloadAction("media 2");
FakeDownloadAction remove1Action = createRemoveAction("media 1");
FakeDownloadAction download3Action = createDownloadAction("media 3");
FakeDownloadAction download1Action = createDownloadAction(uri1);
FakeDownloadAction remove2Action = createRemoveAction(uri2);
FakeDownloadAction download2Action = createDownloadAction(uri2);
FakeDownloadAction remove1Action = createRemoveAction(uri1);
FakeDownloadAction download3Action = createDownloadAction(uri3);
download1Action.post().assertStarted();
remove2Action.post().assertStarted();
@ -371,9 +377,9 @@ public class DownloadManagerTest {
@Test
public void testResumeBeforeTotallyStopped() throws Throwable {
setUpDownloadManager(2);
FakeDownloadAction download1Action = createDownloadAction("media 1").ignoreInterrupts();
FakeDownloadAction download2Action = createDownloadAction("media 2");
FakeDownloadAction download3Action = createDownloadAction("media 3");
FakeDownloadAction download1Action = createDownloadAction(uri1).ignoreInterrupts();
FakeDownloadAction download2Action = createDownloadAction(uri2);
FakeDownloadAction download3Action = createDownloadAction(uri3);
download1Action.post().assertStarted();
download2Action.post().assertStarted();
@ -481,12 +487,12 @@ public class DownloadManagerTest {
testDownloadListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
}
private FakeDownloadAction createDownloadAction(String mediaId) {
return new FakeDownloadAction(/* isRemoveAction= */ false, mediaId);
private FakeDownloadAction createDownloadAction(Uri uri) {
return new FakeDownloadAction(uri, /* isRemoveAction= */ false);
}
private FakeDownloadAction createRemoveAction(String mediaId) {
return new FakeDownloadAction(/* isRemoveAction= */ true, mediaId);
private FakeDownloadAction createRemoveAction(Uri uri) {
return new FakeDownloadAction(uri, /* isRemoveAction= */ true);
}
private void runOnMainThread(final Runnable r) throws Throwable {
@ -530,28 +536,20 @@ public class DownloadManagerTest {
private class FakeDownloadAction extends DownloadAction {
private final String mediaId;
private final FakeDownloader downloader;
private final BlockingQueue<Integer> states;
private FakeDownloadAction(boolean isRemoveAction, @Nullable String mediaId) {
super("FakeDownloadAction", /* version= */ 0, isRemoveAction, mediaId);
this.mediaId = mediaId;
private FakeDownloadAction(Uri uri, boolean isRemoveAction) {
super("Fake", /* version= */ 0, uri, isRemoveAction, /* data= */ null);
this.downloader = new FakeDownloader(isRemoveAction);
this.states = new ArrayBlockingQueue<>(10);
}
@Override
protected void writeToStream(DataOutputStream output) throws IOException {
protected void writeToStream(DataOutputStream output) {
// do nothing.
}
@Override
protected boolean isSameMedia(DownloadAction other) {
return other instanceof FakeDownloadAction
&& mediaId.equals(((FakeDownloadAction) other).mediaId);
}
@Override
protected Downloader createDownloader(DownloaderConstructorHelper downloaderConstructorHelper) {
return downloader;

View File

@ -49,20 +49,20 @@ public class ProgressiveDownloadActionTest {
@Test
public void testDownloadActionIsNotRemoveAction() throws Exception {
ProgressiveDownloadAction action = new ProgressiveDownloadAction(false, null, uri1, null);
ProgressiveDownloadAction action = new ProgressiveDownloadAction(uri1, false, null, null);
assertThat(action.isRemoveAction).isFalse();
}
@Test
public void testRemoveActionisRemoveAction() throws Exception {
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(true, null, uri1, null);
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(uri1, true, null, null);
assertThat(action2.isRemoveAction).isTrue();
}
@Test
public void testCreateDownloader() throws Exception {
MockitoAnnotations.initMocks(this);
ProgressiveDownloadAction action = new ProgressiveDownloadAction(false, null, uri1, null);
ProgressiveDownloadAction action = new ProgressiveDownloadAction(uri1, false, null, null);
DownloaderConstructorHelper constructorHelper = new DownloaderConstructorHelper(
Mockito.mock(Cache.class), DummyDataSource.FACTORY);
assertThat(action.createDownloader(constructorHelper)).isNotNull();
@ -70,75 +70,75 @@ public class ProgressiveDownloadActionTest {
@Test
public void testSameUriCacheKeyDifferentAction_IsSameMedia() throws Exception {
ProgressiveDownloadAction action1 = new ProgressiveDownloadAction(true, null, uri1, null);
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(false, null, uri1, null);
ProgressiveDownloadAction action1 = new ProgressiveDownloadAction(uri1, true, null, null);
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(uri1, false, null, null);
assertSameMedia(action1, action2);
}
@Test
public void testNullCacheKeyDifferentUriAction_IsNotSameMedia() throws Exception {
ProgressiveDownloadAction action3 = new ProgressiveDownloadAction(true, null, uri2, null);
ProgressiveDownloadAction action4 = new ProgressiveDownloadAction(false, null, uri1, null);
ProgressiveDownloadAction action3 = new ProgressiveDownloadAction(uri2, true, null, null);
ProgressiveDownloadAction action4 = new ProgressiveDownloadAction(uri1, false, null, null);
assertNotSameMedia(action3, action4);
}
@Test
public void testSameCacheKeyDifferentUriAction_IsSameMedia() throws Exception {
ProgressiveDownloadAction action5 = new ProgressiveDownloadAction(true, null, uri2, "key");
ProgressiveDownloadAction action6 = new ProgressiveDownloadAction(false, null, uri1, "key");
ProgressiveDownloadAction action5 = new ProgressiveDownloadAction(uri2, true, null, "key");
ProgressiveDownloadAction action6 = new ProgressiveDownloadAction(uri1, false, null, "key");
assertSameMedia(action5, action6);
}
@Test
public void testSameUriDifferentCacheKeyAction_IsNotSameMedia() throws Exception {
ProgressiveDownloadAction action7 = new ProgressiveDownloadAction(true, null, uri1, "key");
ProgressiveDownloadAction action8 = new ProgressiveDownloadAction(false, null, uri1, "key2");
ProgressiveDownloadAction action7 = new ProgressiveDownloadAction(uri1, true, null, "key");
ProgressiveDownloadAction action8 = new ProgressiveDownloadAction(uri1, false, null, "key2");
assertNotSameMedia(action7, action8);
}
@Test
public void testSameUriNullCacheKeyAction_IsNotSameMedia() throws Exception {
ProgressiveDownloadAction action1 = new ProgressiveDownloadAction(true, null, uri1, "key");
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(false, null, uri1, null);
ProgressiveDownloadAction action1 = new ProgressiveDownloadAction(uri1, true, null, "key");
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(uri1, false, null, null);
assertNotSameMedia(action1, action2);
}
@Test
public void testEquals() throws Exception {
ProgressiveDownloadAction action1 = new ProgressiveDownloadAction(true, null, uri1, null);
ProgressiveDownloadAction action1 = new ProgressiveDownloadAction(uri1, true, null, null);
assertThat(action1.equals(action1)).isTrue();
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(true, null, uri1, null);
ProgressiveDownloadAction action3 = new ProgressiveDownloadAction(true, null, uri1, null);
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(uri1, true, null, null);
ProgressiveDownloadAction action3 = new ProgressiveDownloadAction(uri1, true, null, null);
assertThat(action2.equals(action3)).isTrue();
ProgressiveDownloadAction action4 = new ProgressiveDownloadAction(true, null, uri1, null);
ProgressiveDownloadAction action5 = new ProgressiveDownloadAction(false, null, uri1, null);
ProgressiveDownloadAction action4 = new ProgressiveDownloadAction(uri1, true, null, null);
ProgressiveDownloadAction action5 = new ProgressiveDownloadAction(uri1, false, null, null);
assertThat(action4.equals(action5)).isFalse();
ProgressiveDownloadAction action6 = new ProgressiveDownloadAction(true, null, uri1, null);
ProgressiveDownloadAction action7 = new ProgressiveDownloadAction(true, null, uri1, "key");
ProgressiveDownloadAction action6 = new ProgressiveDownloadAction(uri1, true, null, null);
ProgressiveDownloadAction action7 = new ProgressiveDownloadAction(uri1, true, null, "key");
assertThat(action6.equals(action7)).isFalse();
ProgressiveDownloadAction action8 = new ProgressiveDownloadAction(true, null, uri1, "key2");
ProgressiveDownloadAction action9 = new ProgressiveDownloadAction(true, null, uri1, "key");
ProgressiveDownloadAction action8 = new ProgressiveDownloadAction(uri1, true, null, "key2");
ProgressiveDownloadAction action9 = new ProgressiveDownloadAction(uri1, true, null, "key");
assertThat(action8.equals(action9)).isFalse();
ProgressiveDownloadAction action10 = new ProgressiveDownloadAction(true, null, uri1, null);
ProgressiveDownloadAction action11 = new ProgressiveDownloadAction(true, null, uri2, null);
ProgressiveDownloadAction action10 = new ProgressiveDownloadAction(uri1, true, null, null);
ProgressiveDownloadAction action11 = new ProgressiveDownloadAction(uri2, true, null, null);
assertThat(action10.equals(action11)).isFalse();
}
@Test
public void testSerializerGetType() throws Exception {
ProgressiveDownloadAction action = new ProgressiveDownloadAction(false, null, uri1, null);
ProgressiveDownloadAction action = new ProgressiveDownloadAction(uri1, false, null, null);
assertThat(action.type).isNotNull();
}
@Test
public void testSerializerWriteRead() throws Exception {
doTestSerializationRoundTrip(new ProgressiveDownloadAction(false, null, uri1, null));
doTestSerializationRoundTrip(new ProgressiveDownloadAction(true, null, uri2, "key"));
doTestSerializationRoundTrip(new ProgressiveDownloadAction(uri1, false, null, null));
doTestSerializationRoundTrip(new ProgressiveDownloadAction(uri2, true, null, "key"));
}
private void assertSameMedia(

View File

@ -24,11 +24,12 @@ import com.google.android.exoplayer2.source.dash.manifest.RepresentationKey;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
/** An action to download or remove downloaded DASH streams. */
public final class DashDownloadAction extends SegmentDownloadAction<RepresentationKey> {
private static final String TYPE = "DashDownloadAction";
private static final String TYPE = "dash";
private static final int VERSION = 0;
public static final Deserializer DESERIALIZER =
@ -39,30 +40,28 @@ public final class DashDownloadAction extends SegmentDownloadAction<Representati
return new RepresentationKey(input.readInt(), input.readInt(), input.readInt());
}
@Override
protected RepresentationKey[] createKeyArray(int keyCount) {
return new RepresentationKey[keyCount];
}
@Override
protected DownloadAction createDownloadAction(
boolean isRemoveAction, String data, Uri manifestUri, RepresentationKey[] keys) {
return new DashDownloadAction(isRemoveAction, data, manifestUri, keys);
Uri uri, boolean isRemoveAction, String data, List<RepresentationKey> keys) {
return new DashDownloadAction(uri, isRemoveAction, data, keys);
}
};
/**
* @see SegmentDownloadAction#SegmentDownloadAction(String, int, boolean, String, Uri,
* Comparable[])
* @param uri The DASH manifest URI.
* @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 keys Keys of representations to be downloaded. If empty, all representations are
* downloaded. If {@code removeAction} is true, {@code keys} must be empty.
*/
public DashDownloadAction(
boolean isRemoveAction, @Nullable String data, Uri manifestUri, RepresentationKey... keys) {
super(TYPE, VERSION, isRemoveAction, data, manifestUri, keys);
Uri uri, boolean isRemoveAction, @Nullable String data, List<RepresentationKey> keys) {
super(TYPE, VERSION, uri, isRemoveAction, data, keys);
}
@Override
protected DashDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
return new DashDownloader(manifestUri, constructorHelper, keys);
return new DashDownloader(uri, constructorHelper, keys);
}
@Override

View File

@ -49,8 +49,11 @@ import java.util.List;
* new DownloaderConstructorHelper(cache, factory);
* // Create a downloader for the first representation of the first adaptation set of the first
* // period.
* DashDownloader dashDownloader = new DashDownloader(
* manifestUrl, constructorHelper, new RepresentationKey[] {new RepresentationKey(0, 0, 0)});
* DashDownloader dashDownloader =
* new DashDownloader(
* manifestUrl,
* constructorHelper,
* Collections.singletonList(new RepresentationKey(0, 0, 0)));
* // Perform the download.
* dashDownloader.download();
* // Access downloaded data using CacheDataSource
@ -60,11 +63,11 @@ import java.util.List;
*/
public final class DashDownloader extends SegmentDownloader<DashManifest, RepresentationKey> {
/** @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper, Object[]) */
/** @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper, List) */
public DashDownloader(
Uri manifestUri,
DownloaderConstructorHelper constructorHelper,
@Nullable RepresentationKey[] trackKeys) {
List<RepresentationKey> trackKeys) {
super(manifestUri, constructorHelper, trackKeys);
}

View File

@ -28,6 +28,8 @@ import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -51,141 +53,120 @@ public class DashDownloadActionTest {
}
@Test
public void testDownloadActionIsNotRemoveAction() throws Exception {
DashDownloadAction action =
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
public void testDownloadActionIsNotRemoveAction() {
DashDownloadAction action = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
assertThat(action.isRemoveAction).isFalse();
}
@Test
public void testRemoveActionisRemoveAction() throws Exception {
DashDownloadAction action2 =
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1);
public void testRemoveActionisRemoveAction() {
DashDownloadAction action2 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
assertThat(action2.isRemoveAction).isTrue();
}
@Test
public void testCreateDownloader() throws Exception {
public void testCreateDownloader() {
MockitoAnnotations.initMocks(this);
DashDownloadAction action =
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
DashDownloadAction action = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
DownloaderConstructorHelper constructorHelper = new DownloaderConstructorHelper(
Mockito.mock(Cache.class), DummyDataSource.FACTORY);
assertThat(action.createDownloader(constructorHelper)).isNotNull();
}
@Test
public void testSameUriDifferentAction_IsSameMedia() throws Exception {
DashDownloadAction action1 =
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1);
DashDownloadAction action2 =
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
public void testSameUriDifferentAction_IsSameMedia() {
DashDownloadAction action1 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
DashDownloadAction action2 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
assertThat(action1.isSameMedia(action2)).isTrue();
}
@Test
public void testDifferentUriAndAction_IsNotSameMedia() throws Exception {
DashDownloadAction action3 =
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri2);
DashDownloadAction action4 =
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
public void testDifferentUriAndAction_IsNotSameMedia() {
DashDownloadAction action3 = newAction(uri2, /* isRemoveAction= */ true, /* data= */ null);
DashDownloadAction action4 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
assertThat(action3.isSameMedia(action4)).isFalse();
}
@SuppressWarnings("EqualsWithItself")
@Test
public void testEquals() throws Exception {
DashDownloadAction action1 =
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1);
public void testEquals() {
DashDownloadAction action1 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
assertThat(action1.equals(action1)).isTrue();
DashDownloadAction action2 =
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1);
DashDownloadAction action3 =
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1);
DashDownloadAction action2 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
DashDownloadAction action3 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
assertEqual(action2, action3);
DashDownloadAction action4 =
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1);
DashDownloadAction action5 =
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
DashDownloadAction action4 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
DashDownloadAction action5 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
assertNotEqual(action4, action5);
DashDownloadAction action6 =
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
DashDownloadAction action6 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
DashDownloadAction action7 =
new DashDownloadAction(
/* isRemoveAction= */ false, /* data= */ null, uri1, new RepresentationKey(0, 0, 0));
newAction(
uri1, /* isRemoveAction= */ false, /* data= */ null, new RepresentationKey(0, 0, 0));
assertNotEqual(action6, action7);
DashDownloadAction action8 =
new DashDownloadAction(
/* isRemoveAction= */ false, /* data= */ null, uri1, new RepresentationKey(1, 1, 1));
newAction(
uri1, /* isRemoveAction= */ false, /* data= */ null, new RepresentationKey(1, 1, 1));
DashDownloadAction action9 =
new DashDownloadAction(
/* isRemoveAction= */ false, /* data= */ null, uri1, new RepresentationKey(0, 0, 0));
newAction(
uri1, /* isRemoveAction= */ false, /* data= */ null, new RepresentationKey(0, 0, 0));
assertNotEqual(action8, action9);
DashDownloadAction action10 =
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1);
DashDownloadAction action11 =
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri2);
DashDownloadAction action10 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
DashDownloadAction action11 = newAction(uri2, /* isRemoveAction= */ true, /* data= */ null);
assertNotEqual(action10, action11);
DashDownloadAction action12 =
new DashDownloadAction(
newAction(
uri1,
/* isRemoveAction= */ false,
/* data= */ null,
uri1,
new RepresentationKey(0, 0, 0),
new RepresentationKey(1, 1, 1));
DashDownloadAction action13 =
new DashDownloadAction(
newAction(
uri1,
/* isRemoveAction= */ false,
/* data= */ null,
uri1,
new RepresentationKey(1, 1, 1),
new RepresentationKey(0, 0, 0));
assertEqual(action12, action13);
DashDownloadAction action14 =
new DashDownloadAction(
/* isRemoveAction= */ false, /* data= */ null, uri1, new RepresentationKey(0, 0, 0));
newAction(
uri1, /* isRemoveAction= */ false, /* data= */ null, new RepresentationKey(0, 0, 0));
DashDownloadAction action15 =
new DashDownloadAction(
newAction(
uri1,
/* isRemoveAction= */ false,
/* data= */ null,
uri1,
new RepresentationKey(1, 1, 1),
new RepresentationKey(0, 0, 0));
assertNotEqual(action14, action15);
DashDownloadAction action16 =
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
DashDownloadAction action17 =
new DashDownloadAction(
/* isRemoveAction= */ false, /* data= */ null, uri1, new RepresentationKey[0]);
DashDownloadAction action16 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
DashDownloadAction action17 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
assertEqual(action16, action17);
}
@Test
public void testSerializerGetType() throws Exception {
DashDownloadAction action =
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
public void testSerializerGetType() {
DashDownloadAction action = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
assertThat(action.type).isNotNull();
}
@Test
public void testSerializerWriteRead() throws Exception {
doTestSerializationRoundTrip(newAction(uri1, /* isRemoveAction= */ false, /* data= */ null));
doTestSerializationRoundTrip(newAction(uri1, /* isRemoveAction= */ true, /* data= */ null));
doTestSerializationRoundTrip(
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1));
doTestSerializationRoundTrip(
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1));
doTestSerializationRoundTrip(
new DashDownloadAction(
newAction(
uri2,
/* isRemoveAction= */ false,
/* data= */ null,
uri2,
new RepresentationKey(0, 0, 0),
new RepresentationKey(1, 1, 1)));
}
@ -214,4 +195,10 @@ public class DashDownloadActionTest {
assertThat(action).isEqualTo(action2);
}
private static DashDownloadAction newAction(
Uri uri, boolean isRemoveAction, String data, RepresentationKey... keys) {
ArrayList<RepresentationKey> keysList = new ArrayList<>();
Collections.addAll(keysList, keys);
return new DashDownloadAction(uri, isRemoveAction, data, keysList);
}
}

View File

@ -38,6 +38,8 @@ import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -302,7 +304,14 @@ public class DashDownloaderTest {
}
private DashDownloader getDashDownloader(Factory factory, RepresentationKey... keys) {
return new DashDownloader(TEST_MPD_URI, new DownloaderConstructorHelper(cache, factory), keys);
return new DashDownloader(
TEST_MPD_URI, new DownloaderConstructorHelper(cache, factory), keysList(keys));
}
private static ArrayList<RepresentationKey> keysList(RepresentationKey... keys) {
ArrayList<RepresentationKey> keysList = new ArrayList<>();
Collections.addAll(keysList, keys);
return keysList;
}
}

View File

@ -22,6 +22,7 @@ import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedDa
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.net.Uri;
import android.os.ConditionVariable;
import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
@ -36,6 +37,8 @@ import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
@ -244,11 +247,11 @@ public class DownloadManagerDashTest {
}
private void handleDownloadAction(RepresentationKey... keys) {
downloadManager.handleAction(new DashDownloadAction(false, null, TEST_MPD_URI, keys));
downloadManager.handleAction(newAction(TEST_MPD_URI, false, null, keys));
}
private void handleRemoveAction() {
downloadManager.handleAction(new DashDownloadAction(true, null, TEST_MPD_URI));
downloadManager.handleAction(newAction(TEST_MPD_URI, true, null));
}
private void createDownloadManager() {
@ -272,4 +275,11 @@ public class DownloadManagerDashTest {
}
});
}
private static DashDownloadAction newAction(
Uri uri, boolean isRemoveAction, String data, RepresentationKey... keys) {
ArrayList<RepresentationKey> keysList = new ArrayList<>();
Collections.addAll(keysList, keys);
return new DashDownloadAction(uri, isRemoveAction, data, keysList);
}
}

View File

@ -23,6 +23,7 @@ import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedDa
import android.app.Notification;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadManager.TaskState;
@ -43,6 +44,8 @@ import com.google.android.exoplayer2.util.ConditionVariable;
import com.google.android.exoplayer2.util.Util;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
@ -219,11 +222,11 @@ public class DownloadServiceDashTest {
}
private void removeAll() throws Throwable {
callDownloadServiceOnStart(new DashDownloadAction(true, null, TEST_MPD_URI));
callDownloadServiceOnStart(newAction(TEST_MPD_URI, true, null));
}
private void downloadKeys(RepresentationKey... keys) throws Throwable {
callDownloadServiceOnStart(new DashDownloadAction(false, null, TEST_MPD_URI, keys));
private void downloadKeys(RepresentationKey... keys) {
callDownloadServiceOnStart(newAction(TEST_MPD_URI, false, null, keys));
}
private void callDownloadServiceOnStart(final DashDownloadAction action) {
@ -238,4 +241,11 @@ public class DownloadServiceDashTest {
}
});
}
private static DashDownloadAction newAction(
Uri uri, boolean isRemoveAction, String data, RepresentationKey... keys) {
ArrayList<RepresentationKey> keysList = new ArrayList<>();
Collections.addAll(keysList, keys);
return new DashDownloadAction(uri, isRemoveAction, data, keysList);
}
}

View File

@ -24,11 +24,12 @@ import com.google.android.exoplayer2.source.hls.playlist.RenditionKey;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
/** An action to download or remove downloaded HLS streams. */
public final class HlsDownloadAction extends SegmentDownloadAction<RenditionKey> {
private static final String TYPE = "HlsDownloadAction";
private static final String TYPE = "hls";
private static final int VERSION = 0;
public static final Deserializer DESERIALIZER =
@ -41,30 +42,28 @@ public final class HlsDownloadAction extends SegmentDownloadAction<RenditionKey>
return new RenditionKey(renditionGroup, trackIndex);
}
@Override
protected RenditionKey[] createKeyArray(int keyCount) {
return new RenditionKey[keyCount];
}
@Override
protected DownloadAction createDownloadAction(
boolean isRemoveAction, String data, Uri manifestUri, RenditionKey[] keys) {
return new HlsDownloadAction(isRemoveAction, data, manifestUri, keys);
Uri uri, boolean isRemoveAction, String data, List<RenditionKey> keys) {
return new HlsDownloadAction(uri, isRemoveAction, data, keys);
}
};
/**
* @see SegmentDownloadAction#SegmentDownloadAction(String, int, boolean, String, Uri,
* Comparable[])
* @param uri The HLS playlist URI.
* @param isRemoveAction Whether the data will be removed. If {@code false} it will be downloaded.
* @param data Optional custom data for this action.
* @param keys Keys of renditions to be downloaded. If empty, all renditions are downloaded. If
* {@code removeAction} is true, {@code keys} must empty.
*/
public HlsDownloadAction(
boolean isRemoveAction, @Nullable String data, Uri manifestUri, RenditionKey... keys) {
super(TYPE, VERSION, isRemoveAction, data, manifestUri, keys);
Uri uri, boolean isRemoveAction, @Nullable String data, List<RenditionKey> keys) {
super(TYPE, VERSION, uri, isRemoveAction, data, keys);
}
@Override
protected HlsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
return new HlsDownloader(manifestUri, constructorHelper, keys);
return new HlsDownloader(uri, constructorHelper, keys);
}
@Override

View File

@ -37,9 +37,11 @@ import java.util.List;
/** A downloader for HLS streams. */
public final class HlsDownloader extends SegmentDownloader<HlsMasterPlaylist, RenditionKey> {
/** @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper, Object[]) */
/** @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper, List) */
public HlsDownloader(
Uri manifestUri, DownloaderConstructorHelper constructorHelper, RenditionKey[] trackKeys) {
Uri manifestUri,
DownloaderConstructorHelper constructorHelper,
List<RenditionKey> trackKeys) {
super(manifestUri, constructorHelper, trackKeys);
}

View File

@ -35,7 +35,6 @@ import static com.google.android.exoplayer2.testutil.CacheAsserts.assertCachedDa
import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.source.hls.playlist.RenditionKey;
import com.google.android.exoplayer2.testutil.FakeDataSet;
@ -44,6 +43,8 @@ import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -78,7 +79,7 @@ public class HlsDownloaderTest {
}
@After
public void tearDown() throws Exception {
public void tearDown() {
Util.recursiveDelete(tempFolder);
}
@ -132,7 +133,7 @@ public class HlsDownloaderTest {
.setRandomData(MEDIA_PLAYLIST_3_DIR + "fileSequence1.ts", 14)
.setRandomData(MEDIA_PLAYLIST_3_DIR + "fileSequence2.ts", 15);
HlsDownloader downloader = getHlsDownloader(MASTER_PLAYLIST_URI, null);
HlsDownloader downloader = getHlsDownloader(MASTER_PLAYLIST_URI, getKeys());
downloader.download();
assertCachedData(cache, fakeDataSet);
@ -152,7 +153,7 @@ public class HlsDownloaderTest {
@Test
public void testDownloadMediaPlaylist() throws Exception {
HlsDownloader downloader = getHlsDownloader(MEDIA_PLAYLIST_1_URI);
HlsDownloader downloader = getHlsDownloader(MEDIA_PLAYLIST_1_URI, getKeys());
downloader.download();
assertCachedData(
@ -175,21 +176,21 @@ public class HlsDownloaderTest {
.setRandomData("fileSequence1.ts", 11)
.setRandomData("fileSequence2.ts", 12);
HlsDownloader downloader = getHlsDownloader(ENC_MEDIA_PLAYLIST_URI);
HlsDownloader downloader = getHlsDownloader(ENC_MEDIA_PLAYLIST_URI, getKeys());
downloader.download();
assertCachedData(cache, fakeDataSet);
}
private HlsDownloader getHlsDownloader(String mediaPlaylistUri, @Nullable RenditionKey... keys) {
private HlsDownloader getHlsDownloader(String mediaPlaylistUri, List<RenditionKey> keys) {
Factory factory = new Factory(null).setFakeDataSet(fakeDataSet);
return new HlsDownloader(
Uri.parse(mediaPlaylistUri), new DownloaderConstructorHelper(cache, factory), keys);
}
private static RenditionKey[] getKeys(int... variantIndices) {
RenditionKey[] renditionKeys = new RenditionKey[variantIndices.length];
for (int i = 0; i < variantIndices.length; i++) {
renditionKeys[i] = new RenditionKey(RenditionKey.GROUP_VARIANTS, variantIndices[i]);
private static ArrayList<RenditionKey> getKeys(int... variantIndices) {
ArrayList<RenditionKey> renditionKeys = new ArrayList<>();
for (int variantIndex : variantIndices) {
renditionKeys.add(new RenditionKey(RenditionKey.GROUP_VARIANTS, variantIndex));
}
return renditionKeys;
}

View File

@ -24,11 +24,12 @@ import com.google.android.exoplayer2.source.smoothstreaming.manifest.TrackKey;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.List;
/** An action to download or remove downloaded SmoothStreaming streams. */
public final class SsDownloadAction extends SegmentDownloadAction<TrackKey> {
private static final String TYPE = "SsDownloadAction";
private static final String TYPE = "ss";
private static final int VERSION = 0;
public static final Deserializer DESERIALIZER =
@ -39,30 +40,28 @@ public final class SsDownloadAction extends SegmentDownloadAction<TrackKey> {
return new TrackKey(input.readInt(), input.readInt());
}
@Override
protected TrackKey[] createKeyArray(int keyCount) {
return new TrackKey[keyCount];
}
@Override
protected DownloadAction createDownloadAction(
boolean isRemoveAction, String data, Uri manifestUri, TrackKey[] keys) {
return new SsDownloadAction(isRemoveAction, data, manifestUri, keys);
Uri uri, boolean isRemoveAction, String data, List<TrackKey> keys) {
return new SsDownloadAction(uri, isRemoveAction, data, keys);
}
};
/**
* @see SegmentDownloadAction#SegmentDownloadAction(String, int, boolean, String, Uri,
* Comparable[])
* @param uri The SmoothStreaming manifest URI.
* @param isRemoveAction Whether the data will be removed. If {@code false} it will be downloaded.
* @param data Optional custom data for this action.
* @param keys Keys of tracks to be downloaded. If empty, all tracks are downloaded. If {@code
* removeAction} is true, {@code keys} must be empty.
*/
public SsDownloadAction(
boolean isRemoveAction, @Nullable String data, Uri manifestUri, TrackKey... keys) {
super(TYPE, VERSION, isRemoveAction, data, manifestUri, keys);
Uri uri, boolean isRemoveAction, @Nullable String data, List<TrackKey> keys) {
super(TYPE, VERSION, uri, isRemoveAction, data, keys);
}
@Override
protected SsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
return new SsDownloader(manifestUri, constructorHelper, keys);
return new SsDownloader(uri, constructorHelper, keys);
}
@Override

View File

@ -42,8 +42,11 @@ import java.util.List;
* DownloaderConstructorHelper constructorHelper =
* new DownloaderConstructorHelper(cache, factory);
* // Create a downloader for the first track of the first stream element.
* SsDownloader ssDownloader = new SsDownloader(
* manifestUrl, constructorHelper, new TrackKey[] {new TrackKey(0, 0)});
* SsDownloader ssDownloader =
* new SsDownloader(
* manifestUrl,
* constructorHelper,
* Collections.singletonList(new TrackKey(0, 0)));
* // Perform the download.
* ssDownloader.download();
* // Access downloaded data using CacheDataSource
@ -53,9 +56,9 @@ import java.util.List;
*/
public final class SsDownloader extends SegmentDownloader<SsManifest, TrackKey> {
/** @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper, Object[]) */
/** @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper, List) */
public SsDownloader(
Uri manifestUri, DownloaderConstructorHelper constructorHelper, TrackKey[] trackKeys) {
Uri manifestUri, DownloaderConstructorHelper constructorHelper, List<TrackKey> trackKeys) {
super(SsUtil.fixManifestUri(manifestUri), constructorHelper, trackKeys);
}
@ -69,7 +72,7 @@ public final class SsDownloader extends SegmentDownloader<SsManifest, TrackKey>
@Override
protected List<Segment> getSegments(
DataSource dataSource, SsManifest manifest, boolean allowIncompleteList) throws IOException {
DataSource dataSource, SsManifest manifest, boolean allowIncompleteList) {
ArrayList<Segment> segments = new ArrayList<>();
for (StreamElement streamElement : manifest.streamElements) {
for (int i = 0; i < streamElement.formats.length; i++) {

View File

@ -123,8 +123,7 @@ public final class DashDownloadTest extends ActivityInstrumentationTestCase2<Hos
}
DownloaderConstructorHelper constructorHelper =
new DownloaderConstructorHelper(cache, httpDataSourceFactory);
return new DashDownloader(
MANIFEST_URI, constructorHelper, keys.toArray(new RepresentationKey[keys.size()]));
return new DashDownloader(MANIFEST_URI, constructorHelper, keys);
}
}