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

View File

@ -37,12 +37,6 @@
android:onClick="onClick" android:onClick="onClick"
android:text="@string/download_remove_all"/> 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" <Button android:id="@+id/play_button"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -51,8 +51,6 @@
<string name="download_remove_all">Remove all</string> <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> <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> </resources>

View File

@ -15,6 +15,7 @@
*/ */
package com.google.android.exoplayer2.offline; package com.google.android.exoplayer2.offline;
import android.net.Uri;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
@ -90,21 +91,25 @@ public abstract class DownloadAction {
public final String type; public final String type;
/** The action version. */ /** The action version. */
public final int 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. */ /** Whether this is a remove action. If false, this is a download action. */
public final boolean isRemoveAction; 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; public final String data;
/** /**
* @param type The type of the action. * @param type The type of the action.
* @param version The action version. * @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 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( 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.type = type;
this.version = version; this.version = version;
this.uri = uri;
this.isRemoveAction = isRemoveAction; this.isRemoveAction = isRemoveAction;
this.data = data != null ? data : ""; this.data = data != null ? data : "";
} }
@ -121,12 +126,14 @@ public abstract class DownloadAction {
return output.toByteArray(); 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}. */ /** Serializes itself into the {@code output}. */
protected abstract void writeToStream(DataOutputStream output) throws IOException; 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. */ /** Creates a {@link Downloader} with the given parameters. */
protected abstract Downloader createDownloader( protected abstract Downloader createDownloader(
DownloaderConstructorHelper downloaderConstructorHelper); DownloaderConstructorHelper downloaderConstructorHelper);
@ -137,13 +144,18 @@ public abstract class DownloadAction {
return false; return false;
} }
DownloadAction that = (DownloadAction) o; 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 @Override
public int hashCode() { public int hashCode() {
int result = data.hashCode(); int result = uri.hashCode();
result = 31 * result + (isRemoveAction ? 1 : 0); result = 31 * result + (isRemoveAction ? 1 : 0);
result = 31 * result + data.hashCode();
return result; return result;
} }

View File

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

View File

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

View File

@ -17,7 +17,6 @@ package com.google.android.exoplayer2.offline;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec; 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 manifestUri The {@link Uri} of the manifest to be downloaded.
* @param constructorHelper a {@link DownloaderConstructorHelper} instance. * @param constructorHelper a {@link DownloaderConstructorHelper} instance.
* @param trackKeys Track keys to select when downloading. If null or empty, all tracks are * @param trackKeys Track keys to select when downloading. If empty, all tracks are downloaded.
* downloaded.
*/ */
public SegmentDownloader( public SegmentDownloader(
Uri manifestUri, DownloaderConstructorHelper constructorHelper, @Nullable K[] trackKeys) { Uri manifestUri, DownloaderConstructorHelper constructorHelper, List<K> trackKeys) {
this.manifestUri = manifestUri; this.manifestUri = manifestUri;
this.cache = constructorHelper.getCache(); this.cache = constructorHelper.getCache();
this.dataSource = constructorHelper.buildCacheDataSource(false); this.dataSource = constructorHelper.buildCacheDataSource(false);
this.offlineDataSource = constructorHelper.buildCacheDataSource(true); this.offlineDataSource = constructorHelper.buildCacheDataSource(true);
this.priorityTaskManager = constructorHelper.getPriorityTaskManager(); this.priorityTaskManager = constructorHelper.getPriorityTaskManager();
keys = new ArrayList<>(); keys = new ArrayList<>(trackKeys);
if (trackKeys != null) {
Collections.addAll(this.keys, trackKeys);
}
totalSegments = C.LENGTH_UNSET; 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 static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import com.google.android.exoplayer2.offline.DownloadAction.Deserializer; import com.google.android.exoplayer2.offline.DownloadAction.Deserializer;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.DataInputStream; import java.io.DataInputStream;
@ -236,7 +237,7 @@ public class ActionFileTest {
public static final int VERSION = 0; public static final int VERSION = 0;
private FakeDownloadAction(String type, String data) { private FakeDownloadAction(String type, String data) {
super(type, VERSION, /* isRemoveAction= */ false, data); super(type, VERSION, Uri.parse("http://test.com"), /* isRemoveAction= */ false, data);
} }
@Override @Override
@ -244,37 +245,11 @@ public class ActionFileTest {
output.writeUTF(data); output.writeUTF(data);
} }
@Override
protected boolean isSameMedia(DownloadAction other) {
return false;
}
@Override @Override
protected Downloader createDownloader(DownloaderConstructorHelper downloaderConstructorHelper) { protected Downloader createDownloader(DownloaderConstructorHelper downloaderConstructorHelper) {
return null; 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 com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import android.net.Uri;
import android.os.ConditionVariable; import android.os.ConditionVariable;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.DownloadManager.DownloadListener; import com.google.android.exoplayer2.offline.DownloadManager.DownloadListener;
import com.google.android.exoplayer2.offline.DownloadManager.TaskState; import com.google.android.exoplayer2.offline.DownloadManager.TaskState;
@ -62,14 +62,20 @@ public class DownloadManagerTest {
private static final int MIN_RETRY_COUNT = 3; 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 File actionFile;
private TestDownloadListener testDownloadListener; private TestDownloadListener testDownloadListener;
private DummyMainThread dummyMainThread; private DownloadManager downloadManager;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
MockitoAnnotations.initMocks(this); 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(); dummyMainThread = new DummyMainThread();
actionFile = Util.createTempFile(RuntimeEnvironment.application, "ExoPlayerTest"); actionFile = Util.createTempFile(RuntimeEnvironment.application, "ExoPlayerTest");
testDownloadListener = new TestDownloadListener(); testDownloadListener = new TestDownloadListener();
@ -85,17 +91,17 @@ public class DownloadManagerTest {
@Test @Test
public void testDownloadActionRuns() throws Throwable { public void testDownloadActionRuns() throws Throwable {
doTestActionRuns(createDownloadAction("media 1")); doTestActionRuns(createDownloadAction(uri1));
} }
@Test @Test
public void testRemoveActionRuns() throws Throwable { public void testRemoveActionRuns() throws Throwable {
doTestActionRuns(createRemoveAction("media 1")); doTestActionRuns(createRemoveAction(uri1));
} }
@Test @Test
public void testDownloadRetriesThenFails() throws Throwable { public void testDownloadRetriesThenFails() throws Throwable {
FakeDownloadAction downloadAction = createDownloadAction("media 1"); FakeDownloadAction downloadAction = createDownloadAction(uri1);
downloadAction.post(); downloadAction.post();
FakeDownloader fakeDownloader = downloadAction.getFakeDownloader(); FakeDownloader fakeDownloader = downloadAction.getFakeDownloader();
fakeDownloader.enableDownloadIOException = true; fakeDownloader.enableDownloadIOException = true;
@ -110,11 +116,11 @@ public class DownloadManagerTest {
@Test @Test
public void testDownloadNoRetryWhenCanceled() throws Throwable { public void testDownloadNoRetryWhenCanceled() throws Throwable {
FakeDownloadAction downloadAction = createDownloadAction("media 1").ignoreInterrupts(); FakeDownloadAction downloadAction = createDownloadAction(uri1).ignoreInterrupts();
downloadAction.getFakeDownloader().enableDownloadIOException = true; downloadAction.getFakeDownloader().enableDownloadIOException = true;
downloadAction.post().assertStarted(); downloadAction.post().assertStarted();
FakeDownloadAction removeAction = createRemoveAction("media 1").post(); FakeDownloadAction removeAction = createRemoveAction(uri1).post();
downloadAction.unblock().assertCanceled(); downloadAction.unblock().assertCanceled();
removeAction.unblock(); removeAction.unblock();
@ -124,7 +130,7 @@ public class DownloadManagerTest {
@Test @Test
public void testDownloadRetriesThenContinues() throws Throwable { public void testDownloadRetriesThenContinues() throws Throwable {
FakeDownloadAction downloadAction = createDownloadAction("media 1"); FakeDownloadAction downloadAction = createDownloadAction(uri1);
downloadAction.post(); downloadAction.post();
FakeDownloader fakeDownloader = downloadAction.getFakeDownloader(); FakeDownloader fakeDownloader = downloadAction.getFakeDownloader();
fakeDownloader.enableDownloadIOException = true; fakeDownloader.enableDownloadIOException = true;
@ -143,7 +149,7 @@ public class DownloadManagerTest {
@Test @Test
@SuppressWarnings({"NonAtomicVolatileUpdate", "NonAtomicOperationOnVolatileField"}) @SuppressWarnings({"NonAtomicVolatileUpdate", "NonAtomicOperationOnVolatileField"})
public void testDownloadRetryCountResetsOnProgress() throws Throwable { public void testDownloadRetryCountResetsOnProgress() throws Throwable {
FakeDownloadAction downloadAction = createDownloadAction("media 1"); FakeDownloadAction downloadAction = createDownloadAction(uri1);
downloadAction.post(); downloadAction.post();
FakeDownloader fakeDownloader = downloadAction.getFakeDownloader(); FakeDownloader fakeDownloader = downloadAction.getFakeDownloader();
fakeDownloader.enableDownloadIOException = true; fakeDownloader.enableDownloadIOException = true;
@ -163,41 +169,41 @@ public class DownloadManagerTest {
@Test @Test
public void testDifferentMediaDownloadActionsStartInParallel() throws Throwable { public void testDifferentMediaDownloadActionsStartInParallel() throws Throwable {
doTestActionsRunInParallel(createDownloadAction("media 1"), createDownloadAction("media 2")); doTestActionsRunInParallel(createDownloadAction(uri1), createDownloadAction(uri2));
} }
@Test @Test
public void testDifferentMediaDifferentActionsStartInParallel() throws Throwable { public void testDifferentMediaDifferentActionsStartInParallel() throws Throwable {
doTestActionsRunInParallel(createDownloadAction("media 1"), createRemoveAction("media 2")); doTestActionsRunInParallel(createDownloadAction(uri1), createRemoveAction(uri2));
} }
@Test @Test
public void testSameMediaDownloadActionsStartInParallel() throws Throwable { public void testSameMediaDownloadActionsStartInParallel() throws Throwable {
doTestActionsRunInParallel(createDownloadAction("media 1"), createDownloadAction("media 1")); doTestActionsRunInParallel(createDownloadAction(uri1), createDownloadAction(uri1));
} }
@Test @Test
public void testSameMediaRemoveActionWaitsDownloadAction() throws Throwable { public void testSameMediaRemoveActionWaitsDownloadAction() throws Throwable {
doTestActionsRunSequentially(createDownloadAction("media 1"), createRemoveAction("media 1")); doTestActionsRunSequentially(createDownloadAction(uri1), createRemoveAction(uri1));
} }
@Test @Test
public void testSameMediaDownloadActionWaitsRemoveAction() throws Throwable { public void testSameMediaDownloadActionWaitsRemoveAction() throws Throwable {
doTestActionsRunSequentially(createRemoveAction("media 1"), createDownloadAction("media 1")); doTestActionsRunSequentially(createRemoveAction(uri1), createDownloadAction(uri1));
} }
@Test @Test
public void testSameMediaRemoveActionWaitsRemoveAction() throws Throwable { public void testSameMediaRemoveActionWaitsRemoveAction() throws Throwable {
doTestActionsRunSequentially(createRemoveAction("media 1"), createRemoveAction("media 1")); doTestActionsRunSequentially(createRemoveAction(uri1), createRemoveAction(uri1));
} }
@Test @Test
public void testSameMediaMultipleActions() throws Throwable { public void testSameMediaMultipleActions() throws Throwable {
FakeDownloadAction downloadAction1 = createDownloadAction("media 1").ignoreInterrupts(); FakeDownloadAction downloadAction1 = createDownloadAction(uri1).ignoreInterrupts();
FakeDownloadAction downloadAction2 = createDownloadAction("media 1").ignoreInterrupts(); FakeDownloadAction downloadAction2 = createDownloadAction(uri1).ignoreInterrupts();
FakeDownloadAction removeAction1 = createRemoveAction("media 1"); FakeDownloadAction removeAction1 = createRemoveAction(uri1);
FakeDownloadAction downloadAction3 = createDownloadAction("media 1"); FakeDownloadAction downloadAction3 = createDownloadAction(uri1);
FakeDownloadAction removeAction2 = createRemoveAction("media 1"); FakeDownloadAction removeAction2 = createRemoveAction(uri1);
// Two download actions run in parallel. // Two download actions run in parallel.
downloadAction1.post().assertStarted(); downloadAction1.post().assertStarted();
@ -229,9 +235,9 @@ public class DownloadManagerTest {
@Test @Test
public void testMultipleRemoveActionWaitsLastCancelsAllOther() throws Throwable { public void testMultipleRemoveActionWaitsLastCancelsAllOther() throws Throwable {
FakeDownloadAction removeAction1 = createRemoveAction("media 1").ignoreInterrupts(); FakeDownloadAction removeAction1 = createRemoveAction(uri1).ignoreInterrupts();
FakeDownloadAction removeAction2 = createRemoveAction("media 1"); FakeDownloadAction removeAction2 = createRemoveAction(uri1);
FakeDownloadAction removeAction3 = createRemoveAction("media 1"); FakeDownloadAction removeAction3 = createRemoveAction(uri1);
removeAction1.post().assertStarted(); removeAction1.post().assertStarted();
removeAction2.post().assertDoesNotStart(); removeAction2.post().assertDoesNotStart();
@ -247,9 +253,9 @@ public class DownloadManagerTest {
@Test @Test
public void testGetTasks() throws Throwable { public void testGetTasks() throws Throwable {
FakeDownloadAction removeAction = createRemoveAction("media 1"); FakeDownloadAction removeAction = createRemoveAction(uri1);
FakeDownloadAction downloadAction1 = createDownloadAction("media 1"); FakeDownloadAction downloadAction1 = createDownloadAction(uri1);
FakeDownloadAction downloadAction2 = createDownloadAction("media 1"); FakeDownloadAction downloadAction2 = createDownloadAction(uri1);
removeAction.post().assertStarted(); removeAction.post().assertStarted();
downloadAction1.post().assertDoesNotStart(); downloadAction1.post().assertDoesNotStart();
@ -264,9 +270,9 @@ public class DownloadManagerTest {
@Test @Test
public void testMultipleWaitingDownloadActionStartsInParallel() throws Throwable { public void testMultipleWaitingDownloadActionStartsInParallel() throws Throwable {
FakeDownloadAction removeAction = createRemoveAction("media 1"); FakeDownloadAction removeAction = createRemoveAction(uri1);
FakeDownloadAction downloadAction1 = createDownloadAction("media 1"); FakeDownloadAction downloadAction1 = createDownloadAction(uri1);
FakeDownloadAction downloadAction2 = createDownloadAction("media 1"); FakeDownloadAction downloadAction2 = createDownloadAction(uri1);
removeAction.post().assertStarted(); removeAction.post().assertStarted();
downloadAction1.post().assertDoesNotStart(); downloadAction1.post().assertDoesNotStart();
@ -283,9 +289,9 @@ public class DownloadManagerTest {
@Test @Test
public void testDifferentMediaDownloadActionsPreserveOrder() throws Throwable { public void testDifferentMediaDownloadActionsPreserveOrder() throws Throwable {
FakeDownloadAction removeAction = createRemoveAction("media 1").ignoreInterrupts(); FakeDownloadAction removeAction = createRemoveAction(uri1).ignoreInterrupts();
FakeDownloadAction downloadAction1 = createDownloadAction("media 1"); FakeDownloadAction downloadAction1 = createDownloadAction(uri1);
FakeDownloadAction downloadAction2 = createDownloadAction("media 2"); FakeDownloadAction downloadAction2 = createDownloadAction(uri2);
removeAction.post().assertStarted(); removeAction.post().assertStarted();
downloadAction1.post().assertDoesNotStart(); downloadAction1.post().assertDoesNotStart();
@ -302,9 +308,9 @@ public class DownloadManagerTest {
@Test @Test
public void testDifferentMediaRemoveActionsDoNotPreserveOrder() throws Throwable { public void testDifferentMediaRemoveActionsDoNotPreserveOrder() throws Throwable {
FakeDownloadAction downloadAction = createDownloadAction("media 1").ignoreInterrupts(); FakeDownloadAction downloadAction = createDownloadAction(uri1).ignoreInterrupts();
FakeDownloadAction removeAction1 = createRemoveAction("media 1"); FakeDownloadAction removeAction1 = createRemoveAction(uri1);
FakeDownloadAction removeAction2 = createRemoveAction("media 2"); FakeDownloadAction removeAction2 = createRemoveAction(uri2);
downloadAction.post().assertStarted(); downloadAction.post().assertStarted();
removeAction1.post().assertDoesNotStart(); removeAction1.post().assertDoesNotStart();
@ -321,11 +327,11 @@ public class DownloadManagerTest {
@Test @Test
public void testStopAndResume() throws Throwable { public void testStopAndResume() throws Throwable {
FakeDownloadAction download1Action = createDownloadAction("media 1"); FakeDownloadAction download1Action = createDownloadAction(uri1);
FakeDownloadAction remove2Action = createRemoveAction("media 2"); FakeDownloadAction remove2Action = createRemoveAction(uri2);
FakeDownloadAction download2Action = createDownloadAction("media 2"); FakeDownloadAction download2Action = createDownloadAction(uri2);
FakeDownloadAction remove1Action = createRemoveAction("media 1"); FakeDownloadAction remove1Action = createRemoveAction(uri1);
FakeDownloadAction download3Action = createDownloadAction("media 3"); FakeDownloadAction download3Action = createDownloadAction(uri3);
download1Action.post().assertStarted(); download1Action.post().assertStarted();
remove2Action.post().assertStarted(); remove2Action.post().assertStarted();
@ -371,9 +377,9 @@ public class DownloadManagerTest {
@Test @Test
public void testResumeBeforeTotallyStopped() throws Throwable { public void testResumeBeforeTotallyStopped() throws Throwable {
setUpDownloadManager(2); setUpDownloadManager(2);
FakeDownloadAction download1Action = createDownloadAction("media 1").ignoreInterrupts(); FakeDownloadAction download1Action = createDownloadAction(uri1).ignoreInterrupts();
FakeDownloadAction download2Action = createDownloadAction("media 2"); FakeDownloadAction download2Action = createDownloadAction(uri2);
FakeDownloadAction download3Action = createDownloadAction("media 3"); FakeDownloadAction download3Action = createDownloadAction(uri3);
download1Action.post().assertStarted(); download1Action.post().assertStarted();
download2Action.post().assertStarted(); download2Action.post().assertStarted();
@ -481,12 +487,12 @@ public class DownloadManagerTest {
testDownloadListener.blockUntilTasksCompleteAndThrowAnyDownloadError(); testDownloadListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
} }
private FakeDownloadAction createDownloadAction(String mediaId) { private FakeDownloadAction createDownloadAction(Uri uri) {
return new FakeDownloadAction(/* isRemoveAction= */ false, mediaId); return new FakeDownloadAction(uri, /* isRemoveAction= */ false);
} }
private FakeDownloadAction createRemoveAction(String mediaId) { private FakeDownloadAction createRemoveAction(Uri uri) {
return new FakeDownloadAction(/* isRemoveAction= */ true, mediaId); return new FakeDownloadAction(uri, /* isRemoveAction= */ true);
} }
private void runOnMainThread(final Runnable r) throws Throwable { private void runOnMainThread(final Runnable r) throws Throwable {
@ -530,28 +536,20 @@ public class DownloadManagerTest {
private class FakeDownloadAction extends DownloadAction { private class FakeDownloadAction extends DownloadAction {
private final String mediaId;
private final FakeDownloader downloader; private final FakeDownloader downloader;
private final BlockingQueue<Integer> states; private final BlockingQueue<Integer> states;
private FakeDownloadAction(boolean isRemoveAction, @Nullable String mediaId) { private FakeDownloadAction(Uri uri, boolean isRemoveAction) {
super("FakeDownloadAction", /* version= */ 0, isRemoveAction, mediaId); super("Fake", /* version= */ 0, uri, isRemoveAction, /* data= */ null);
this.mediaId = mediaId;
this.downloader = new FakeDownloader(isRemoveAction); this.downloader = new FakeDownloader(isRemoveAction);
this.states = new ArrayBlockingQueue<>(10); this.states = new ArrayBlockingQueue<>(10);
} }
@Override @Override
protected void writeToStream(DataOutputStream output) throws IOException { protected void writeToStream(DataOutputStream output) {
// do nothing. // do nothing.
} }
@Override
protected boolean isSameMedia(DownloadAction other) {
return other instanceof FakeDownloadAction
&& mediaId.equals(((FakeDownloadAction) other).mediaId);
}
@Override @Override
protected Downloader createDownloader(DownloaderConstructorHelper downloaderConstructorHelper) { protected Downloader createDownloader(DownloaderConstructorHelper downloaderConstructorHelper) {
return downloader; return downloader;

View File

@ -49,20 +49,20 @@ public class ProgressiveDownloadActionTest {
@Test @Test
public void testDownloadActionIsNotRemoveAction() throws Exception { 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(); assertThat(action.isRemoveAction).isFalse();
} }
@Test @Test
public void testRemoveActionisRemoveAction() throws Exception { 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(); assertThat(action2.isRemoveAction).isTrue();
} }
@Test @Test
public void testCreateDownloader() throws Exception { public void testCreateDownloader() throws Exception {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
ProgressiveDownloadAction action = new ProgressiveDownloadAction(false, null, uri1, null); ProgressiveDownloadAction action = new ProgressiveDownloadAction(uri1, false, null, null);
DownloaderConstructorHelper constructorHelper = new DownloaderConstructorHelper( DownloaderConstructorHelper constructorHelper = new DownloaderConstructorHelper(
Mockito.mock(Cache.class), DummyDataSource.FACTORY); Mockito.mock(Cache.class), DummyDataSource.FACTORY);
assertThat(action.createDownloader(constructorHelper)).isNotNull(); assertThat(action.createDownloader(constructorHelper)).isNotNull();
@ -70,75 +70,75 @@ public class ProgressiveDownloadActionTest {
@Test @Test
public void testSameUriCacheKeyDifferentAction_IsSameMedia() throws Exception { public void testSameUriCacheKeyDifferentAction_IsSameMedia() throws Exception {
ProgressiveDownloadAction action1 = new ProgressiveDownloadAction(true, null, uri1, null); ProgressiveDownloadAction action1 = new ProgressiveDownloadAction(uri1, true, null, null);
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(false, null, uri1, null); ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(uri1, false, null, null);
assertSameMedia(action1, action2); assertSameMedia(action1, action2);
} }
@Test @Test
public void testNullCacheKeyDifferentUriAction_IsNotSameMedia() throws Exception { public void testNullCacheKeyDifferentUriAction_IsNotSameMedia() throws Exception {
ProgressiveDownloadAction action3 = new ProgressiveDownloadAction(true, null, uri2, null); ProgressiveDownloadAction action3 = new ProgressiveDownloadAction(uri2, true, null, null);
ProgressiveDownloadAction action4 = new ProgressiveDownloadAction(false, null, uri1, null); ProgressiveDownloadAction action4 = new ProgressiveDownloadAction(uri1, false, null, null);
assertNotSameMedia(action3, action4); assertNotSameMedia(action3, action4);
} }
@Test @Test
public void testSameCacheKeyDifferentUriAction_IsSameMedia() throws Exception { public void testSameCacheKeyDifferentUriAction_IsSameMedia() throws Exception {
ProgressiveDownloadAction action5 = new ProgressiveDownloadAction(true, null, uri2, "key"); ProgressiveDownloadAction action5 = new ProgressiveDownloadAction(uri2, true, null, "key");
ProgressiveDownloadAction action6 = new ProgressiveDownloadAction(false, null, uri1, "key"); ProgressiveDownloadAction action6 = new ProgressiveDownloadAction(uri1, false, null, "key");
assertSameMedia(action5, action6); assertSameMedia(action5, action6);
} }
@Test @Test
public void testSameUriDifferentCacheKeyAction_IsNotSameMedia() throws Exception { public void testSameUriDifferentCacheKeyAction_IsNotSameMedia() throws Exception {
ProgressiveDownloadAction action7 = new ProgressiveDownloadAction(true, null, uri1, "key"); ProgressiveDownloadAction action7 = new ProgressiveDownloadAction(uri1, true, null, "key");
ProgressiveDownloadAction action8 = new ProgressiveDownloadAction(false, null, uri1, "key2"); ProgressiveDownloadAction action8 = new ProgressiveDownloadAction(uri1, false, null, "key2");
assertNotSameMedia(action7, action8); assertNotSameMedia(action7, action8);
} }
@Test @Test
public void testSameUriNullCacheKeyAction_IsNotSameMedia() throws Exception { public void testSameUriNullCacheKeyAction_IsNotSameMedia() throws Exception {
ProgressiveDownloadAction action1 = new ProgressiveDownloadAction(true, null, uri1, "key"); ProgressiveDownloadAction action1 = new ProgressiveDownloadAction(uri1, true, null, "key");
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(false, null, uri1, null); ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(uri1, false, null, null);
assertNotSameMedia(action1, action2); assertNotSameMedia(action1, action2);
} }
@Test @Test
public void testEquals() throws Exception { 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(); assertThat(action1.equals(action1)).isTrue();
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(true, null, uri1, null); ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(uri1, true, null, null);
ProgressiveDownloadAction action3 = new ProgressiveDownloadAction(true, null, uri1, null); ProgressiveDownloadAction action3 = new ProgressiveDownloadAction(uri1, true, null, null);
assertThat(action2.equals(action3)).isTrue(); assertThat(action2.equals(action3)).isTrue();
ProgressiveDownloadAction action4 = new ProgressiveDownloadAction(true, null, uri1, null); ProgressiveDownloadAction action4 = new ProgressiveDownloadAction(uri1, true, null, null);
ProgressiveDownloadAction action5 = new ProgressiveDownloadAction(false, null, uri1, null); ProgressiveDownloadAction action5 = new ProgressiveDownloadAction(uri1, false, null, null);
assertThat(action4.equals(action5)).isFalse(); assertThat(action4.equals(action5)).isFalse();
ProgressiveDownloadAction action6 = new ProgressiveDownloadAction(true, null, uri1, null); ProgressiveDownloadAction action6 = new ProgressiveDownloadAction(uri1, true, null, null);
ProgressiveDownloadAction action7 = new ProgressiveDownloadAction(true, null, uri1, "key"); ProgressiveDownloadAction action7 = new ProgressiveDownloadAction(uri1, true, null, "key");
assertThat(action6.equals(action7)).isFalse(); assertThat(action6.equals(action7)).isFalse();
ProgressiveDownloadAction action8 = new ProgressiveDownloadAction(true, null, uri1, "key2"); ProgressiveDownloadAction action8 = new ProgressiveDownloadAction(uri1, true, null, "key2");
ProgressiveDownloadAction action9 = new ProgressiveDownloadAction(true, null, uri1, "key"); ProgressiveDownloadAction action9 = new ProgressiveDownloadAction(uri1, true, null, "key");
assertThat(action8.equals(action9)).isFalse(); assertThat(action8.equals(action9)).isFalse();
ProgressiveDownloadAction action10 = new ProgressiveDownloadAction(true, null, uri1, null); ProgressiveDownloadAction action10 = new ProgressiveDownloadAction(uri1, true, null, null);
ProgressiveDownloadAction action11 = new ProgressiveDownloadAction(true, null, uri2, null); ProgressiveDownloadAction action11 = new ProgressiveDownloadAction(uri2, true, null, null);
assertThat(action10.equals(action11)).isFalse(); assertThat(action10.equals(action11)).isFalse();
} }
@Test @Test
public void testSerializerGetType() throws Exception { 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(); assertThat(action.type).isNotNull();
} }
@Test @Test
public void testSerializerWriteRead() throws Exception { public void testSerializerWriteRead() throws Exception {
doTestSerializationRoundTrip(new ProgressiveDownloadAction(false, null, uri1, null)); doTestSerializationRoundTrip(new ProgressiveDownloadAction(uri1, false, null, null));
doTestSerializationRoundTrip(new ProgressiveDownloadAction(true, null, uri2, "key")); doTestSerializationRoundTrip(new ProgressiveDownloadAction(uri2, true, null, "key"));
} }
private void assertSameMedia( 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.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List;
/** An action to download or remove downloaded DASH streams. */ /** An action to download or remove downloaded DASH streams. */
public final class DashDownloadAction extends SegmentDownloadAction<RepresentationKey> { 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; private static final int VERSION = 0;
public static final Deserializer DESERIALIZER = 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()); return new RepresentationKey(input.readInt(), input.readInt(), input.readInt());
} }
@Override
protected RepresentationKey[] createKeyArray(int keyCount) {
return new RepresentationKey[keyCount];
}
@Override @Override
protected DownloadAction createDownloadAction( protected DownloadAction createDownloadAction(
boolean isRemoveAction, String data, Uri manifestUri, RepresentationKey[] keys) { Uri uri, boolean isRemoveAction, String data, List<RepresentationKey> keys) {
return new DashDownloadAction(isRemoveAction, data, manifestUri, keys); return new DashDownloadAction(uri, isRemoveAction, data, keys);
} }
}; };
/** /**
* @see SegmentDownloadAction#SegmentDownloadAction(String, int, boolean, String, Uri, * @param uri The DASH manifest URI.
* Comparable[]) * @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( public DashDownloadAction(
boolean isRemoveAction, @Nullable String data, Uri manifestUri, RepresentationKey... keys) { Uri uri, boolean isRemoveAction, @Nullable String data, List<RepresentationKey> keys) {
super(TYPE, VERSION, isRemoveAction, data, manifestUri, keys); super(TYPE, VERSION, uri, isRemoveAction, data, keys);
} }
@Override @Override
protected DashDownloader createDownloader(DownloaderConstructorHelper constructorHelper) { protected DashDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
return new DashDownloader(manifestUri, constructorHelper, keys); return new DashDownloader(uri, constructorHelper, keys);
} }
@Override @Override

View File

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

View File

@ -28,6 +28,8 @@ import java.io.ByteArrayOutputStream;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
@ -51,141 +53,120 @@ public class DashDownloadActionTest {
} }
@Test @Test
public void testDownloadActionIsNotRemoveAction() throws Exception { public void testDownloadActionIsNotRemoveAction() {
DashDownloadAction action = DashDownloadAction action = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
assertThat(action.isRemoveAction).isFalse(); assertThat(action.isRemoveAction).isFalse();
} }
@Test @Test
public void testRemoveActionisRemoveAction() throws Exception { public void testRemoveActionisRemoveAction() {
DashDownloadAction action2 = DashDownloadAction action2 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1);
assertThat(action2.isRemoveAction).isTrue(); assertThat(action2.isRemoveAction).isTrue();
} }
@Test @Test
public void testCreateDownloader() throws Exception { public void testCreateDownloader() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
DashDownloadAction action = DashDownloadAction action = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
DownloaderConstructorHelper constructorHelper = new DownloaderConstructorHelper( DownloaderConstructorHelper constructorHelper = new DownloaderConstructorHelper(
Mockito.mock(Cache.class), DummyDataSource.FACTORY); Mockito.mock(Cache.class), DummyDataSource.FACTORY);
assertThat(action.createDownloader(constructorHelper)).isNotNull(); assertThat(action.createDownloader(constructorHelper)).isNotNull();
} }
@Test @Test
public void testSameUriDifferentAction_IsSameMedia() throws Exception { public void testSameUriDifferentAction_IsSameMedia() {
DashDownloadAction action1 = DashDownloadAction action1 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1); DashDownloadAction action2 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
DashDownloadAction action2 =
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
assertThat(action1.isSameMedia(action2)).isTrue(); assertThat(action1.isSameMedia(action2)).isTrue();
} }
@Test @Test
public void testDifferentUriAndAction_IsNotSameMedia() throws Exception { public void testDifferentUriAndAction_IsNotSameMedia() {
DashDownloadAction action3 = DashDownloadAction action3 = newAction(uri2, /* isRemoveAction= */ true, /* data= */ null);
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri2); DashDownloadAction action4 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
DashDownloadAction action4 =
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
assertThat(action3.isSameMedia(action4)).isFalse(); assertThat(action3.isSameMedia(action4)).isFalse();
} }
@SuppressWarnings("EqualsWithItself") @SuppressWarnings("EqualsWithItself")
@Test @Test
public void testEquals() throws Exception { public void testEquals() {
DashDownloadAction action1 = DashDownloadAction action1 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1);
assertThat(action1.equals(action1)).isTrue(); assertThat(action1.equals(action1)).isTrue();
DashDownloadAction action2 = DashDownloadAction action2 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1); DashDownloadAction action3 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
DashDownloadAction action3 =
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1);
assertEqual(action2, action3); assertEqual(action2, action3);
DashDownloadAction action4 = DashDownloadAction action4 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1); DashDownloadAction action5 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
DashDownloadAction action5 =
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
assertNotEqual(action4, action5); assertNotEqual(action4, action5);
DashDownloadAction action6 = DashDownloadAction action6 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
DashDownloadAction action7 = DashDownloadAction action7 =
new DashDownloadAction( newAction(
/* isRemoveAction= */ false, /* data= */ null, uri1, new RepresentationKey(0, 0, 0)); uri1, /* isRemoveAction= */ false, /* data= */ null, new RepresentationKey(0, 0, 0));
assertNotEqual(action6, action7); assertNotEqual(action6, action7);
DashDownloadAction action8 = DashDownloadAction action8 =
new DashDownloadAction( newAction(
/* isRemoveAction= */ false, /* data= */ null, uri1, new RepresentationKey(1, 1, 1)); uri1, /* isRemoveAction= */ false, /* data= */ null, new RepresentationKey(1, 1, 1));
DashDownloadAction action9 = DashDownloadAction action9 =
new DashDownloadAction( newAction(
/* isRemoveAction= */ false, /* data= */ null, uri1, new RepresentationKey(0, 0, 0)); uri1, /* isRemoveAction= */ false, /* data= */ null, new RepresentationKey(0, 0, 0));
assertNotEqual(action8, action9); assertNotEqual(action8, action9);
DashDownloadAction action10 = DashDownloadAction action10 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1); DashDownloadAction action11 = newAction(uri2, /* isRemoveAction= */ true, /* data= */ null);
DashDownloadAction action11 =
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri2);
assertNotEqual(action10, action11); assertNotEqual(action10, action11);
DashDownloadAction action12 = DashDownloadAction action12 =
new DashDownloadAction( newAction(
uri1,
/* isRemoveAction= */ false, /* isRemoveAction= */ false,
/* data= */ null, /* data= */ null,
uri1,
new RepresentationKey(0, 0, 0), new RepresentationKey(0, 0, 0),
new RepresentationKey(1, 1, 1)); new RepresentationKey(1, 1, 1));
DashDownloadAction action13 = DashDownloadAction action13 =
new DashDownloadAction( newAction(
uri1,
/* isRemoveAction= */ false, /* isRemoveAction= */ false,
/* data= */ null, /* data= */ null,
uri1,
new RepresentationKey(1, 1, 1), new RepresentationKey(1, 1, 1),
new RepresentationKey(0, 0, 0)); new RepresentationKey(0, 0, 0));
assertEqual(action12, action13); assertEqual(action12, action13);
DashDownloadAction action14 = DashDownloadAction action14 =
new DashDownloadAction( newAction(
/* isRemoveAction= */ false, /* data= */ null, uri1, new RepresentationKey(0, 0, 0)); uri1, /* isRemoveAction= */ false, /* data= */ null, new RepresentationKey(0, 0, 0));
DashDownloadAction action15 = DashDownloadAction action15 =
new DashDownloadAction( newAction(
uri1,
/* isRemoveAction= */ false, /* isRemoveAction= */ false,
/* data= */ null, /* data= */ null,
uri1,
new RepresentationKey(1, 1, 1), new RepresentationKey(1, 1, 1),
new RepresentationKey(0, 0, 0)); new RepresentationKey(0, 0, 0));
assertNotEqual(action14, action15); assertNotEqual(action14, action15);
DashDownloadAction action16 = DashDownloadAction action16 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1); DashDownloadAction action17 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
DashDownloadAction action17 =
new DashDownloadAction(
/* isRemoveAction= */ false, /* data= */ null, uri1, new RepresentationKey[0]);
assertEqual(action16, action17); assertEqual(action16, action17);
} }
@Test @Test
public void testSerializerGetType() throws Exception { public void testSerializerGetType() {
DashDownloadAction action = DashDownloadAction action = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1);
assertThat(action.type).isNotNull(); assertThat(action.type).isNotNull();
} }
@Test @Test
public void testSerializerWriteRead() throws Exception { public void testSerializerWriteRead() throws Exception {
doTestSerializationRoundTrip(newAction(uri1, /* isRemoveAction= */ false, /* data= */ null));
doTestSerializationRoundTrip(newAction(uri1, /* isRemoveAction= */ true, /* data= */ null));
doTestSerializationRoundTrip( doTestSerializationRoundTrip(
new DashDownloadAction(/* isRemoveAction= */ false, /* data= */ null, uri1)); newAction(
doTestSerializationRoundTrip( uri2,
new DashDownloadAction(/* isRemoveAction= */ true, /* data= */ null, uri1));
doTestSerializationRoundTrip(
new DashDownloadAction(
/* isRemoveAction= */ false, /* isRemoveAction= */ false,
/* data= */ null, /* data= */ null,
uri2,
new RepresentationKey(0, 0, 0), new RepresentationKey(0, 0, 0),
new RepresentationKey(1, 1, 1))); new RepresentationKey(1, 1, 1)));
} }
@ -214,4 +195,10 @@ public class DashDownloadActionTest {
assertThat(action).isEqualTo(action2); 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 com.google.android.exoplayer2.util.Util;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -302,7 +304,14 @@ public class DashDownloaderTest {
} }
private DashDownloader getDashDownloader(Factory factory, RepresentationKey... keys) { 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 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 com.google.android.exoplayer2.offline.DownloadManager; import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper; 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.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore; import org.junit.Ignore;
@ -244,11 +247,11 @@ public class DownloadManagerDashTest {
} }
private void handleDownloadAction(RepresentationKey... keys) { 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() { private void handleRemoveAction() {
downloadManager.handleAction(new DashDownloadAction(true, null, TEST_MPD_URI)); downloadManager.handleAction(newAction(TEST_MPD_URI, true, null));
} }
private void createDownloadManager() { 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.app.Notification;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.google.android.exoplayer2.offline.DownloadManager; import com.google.android.exoplayer2.offline.DownloadManager;
import com.google.android.exoplayer2.offline.DownloadManager.TaskState; 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 com.google.android.exoplayer2.util.Util;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore; import org.junit.Ignore;
@ -219,11 +222,11 @@ public class DownloadServiceDashTest {
} }
private void removeAll() throws Throwable { 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 { private void downloadKeys(RepresentationKey... keys) {
callDownloadServiceOnStart(new DashDownloadAction(false, null, TEST_MPD_URI, keys)); callDownloadServiceOnStart(newAction(TEST_MPD_URI, false, null, keys));
} }
private void callDownloadServiceOnStart(final DashDownloadAction action) { 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.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List;
/** An action to download or remove downloaded HLS streams. */ /** An action to download or remove downloaded HLS streams. */
public final class HlsDownloadAction extends SegmentDownloadAction<RenditionKey> { 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; private static final int VERSION = 0;
public static final Deserializer DESERIALIZER = public static final Deserializer DESERIALIZER =
@ -41,30 +42,28 @@ public final class HlsDownloadAction extends SegmentDownloadAction<RenditionKey>
return new RenditionKey(renditionGroup, trackIndex); return new RenditionKey(renditionGroup, trackIndex);
} }
@Override
protected RenditionKey[] createKeyArray(int keyCount) {
return new RenditionKey[keyCount];
}
@Override @Override
protected DownloadAction createDownloadAction( protected DownloadAction createDownloadAction(
boolean isRemoveAction, String data, Uri manifestUri, RenditionKey[] keys) { Uri uri, boolean isRemoveAction, String data, List<RenditionKey> keys) {
return new HlsDownloadAction(isRemoveAction, data, manifestUri, keys); return new HlsDownloadAction(uri, isRemoveAction, data, keys);
} }
}; };
/** /**
* @see SegmentDownloadAction#SegmentDownloadAction(String, int, boolean, String, Uri, * @param uri The HLS playlist URI.
* Comparable[]) * @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( public HlsDownloadAction(
boolean isRemoveAction, @Nullable String data, Uri manifestUri, RenditionKey... keys) { Uri uri, boolean isRemoveAction, @Nullable String data, List<RenditionKey> keys) {
super(TYPE, VERSION, isRemoveAction, data, manifestUri, keys); super(TYPE, VERSION, uri, isRemoveAction, data, keys);
} }
@Override @Override
protected HlsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) { protected HlsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
return new HlsDownloader(manifestUri, constructorHelper, keys); return new HlsDownloader(uri, constructorHelper, keys);
} }
@Override @Override

View File

@ -37,9 +37,11 @@ import java.util.List;
/** A downloader for HLS streams. */ /** A downloader for HLS streams. */
public final class HlsDownloader extends SegmentDownloader<HlsMasterPlaylist, RenditionKey> { public final class HlsDownloader extends SegmentDownloader<HlsMasterPlaylist, RenditionKey> {
/** @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper, Object[]) */ /** @see SegmentDownloader#SegmentDownloader(Uri, DownloaderConstructorHelper, List) */
public HlsDownloader( public HlsDownloader(
Uri manifestUri, DownloaderConstructorHelper constructorHelper, RenditionKey[] trackKeys) { Uri manifestUri,
DownloaderConstructorHelper constructorHelper,
List<RenditionKey> trackKeys) {
super(manifestUri, constructorHelper, 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 static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper; import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
import com.google.android.exoplayer2.source.hls.playlist.RenditionKey; import com.google.android.exoplayer2.source.hls.playlist.RenditionKey;
import com.google.android.exoplayer2.testutil.FakeDataSet; 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.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.io.File; import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -78,7 +79,7 @@ public class HlsDownloaderTest {
} }
@After @After
public void tearDown() throws Exception { public void tearDown() {
Util.recursiveDelete(tempFolder); Util.recursiveDelete(tempFolder);
} }
@ -132,7 +133,7 @@ public class HlsDownloaderTest {
.setRandomData(MEDIA_PLAYLIST_3_DIR + "fileSequence1.ts", 14) .setRandomData(MEDIA_PLAYLIST_3_DIR + "fileSequence1.ts", 14)
.setRandomData(MEDIA_PLAYLIST_3_DIR + "fileSequence2.ts", 15); .setRandomData(MEDIA_PLAYLIST_3_DIR + "fileSequence2.ts", 15);
HlsDownloader downloader = getHlsDownloader(MASTER_PLAYLIST_URI, null); HlsDownloader downloader = getHlsDownloader(MASTER_PLAYLIST_URI, getKeys());
downloader.download(); downloader.download();
assertCachedData(cache, fakeDataSet); assertCachedData(cache, fakeDataSet);
@ -152,7 +153,7 @@ public class HlsDownloaderTest {
@Test @Test
public void testDownloadMediaPlaylist() throws Exception { public void testDownloadMediaPlaylist() throws Exception {
HlsDownloader downloader = getHlsDownloader(MEDIA_PLAYLIST_1_URI); HlsDownloader downloader = getHlsDownloader(MEDIA_PLAYLIST_1_URI, getKeys());
downloader.download(); downloader.download();
assertCachedData( assertCachedData(
@ -175,21 +176,21 @@ public class HlsDownloaderTest {
.setRandomData("fileSequence1.ts", 11) .setRandomData("fileSequence1.ts", 11)
.setRandomData("fileSequence2.ts", 12); .setRandomData("fileSequence2.ts", 12);
HlsDownloader downloader = getHlsDownloader(ENC_MEDIA_PLAYLIST_URI); HlsDownloader downloader = getHlsDownloader(ENC_MEDIA_PLAYLIST_URI, getKeys());
downloader.download(); downloader.download();
assertCachedData(cache, fakeDataSet); 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); Factory factory = new Factory(null).setFakeDataSet(fakeDataSet);
return new HlsDownloader( return new HlsDownloader(
Uri.parse(mediaPlaylistUri), new DownloaderConstructorHelper(cache, factory), keys); Uri.parse(mediaPlaylistUri), new DownloaderConstructorHelper(cache, factory), keys);
} }
private static RenditionKey[] getKeys(int... variantIndices) { private static ArrayList<RenditionKey> getKeys(int... variantIndices) {
RenditionKey[] renditionKeys = new RenditionKey[variantIndices.length]; ArrayList<RenditionKey> renditionKeys = new ArrayList<>();
for (int i = 0; i < variantIndices.length; i++) { for (int variantIndex : variantIndices) {
renditionKeys[i] = new RenditionKey(RenditionKey.GROUP_VARIANTS, variantIndices[i]); renditionKeys.add(new RenditionKey(RenditionKey.GROUP_VARIANTS, variantIndex));
} }
return renditionKeys; return renditionKeys;
} }

View File

@ -24,11 +24,12 @@ import com.google.android.exoplayer2.source.smoothstreaming.manifest.TrackKey;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.DataOutputStream; import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.List;
/** An action to download or remove downloaded SmoothStreaming streams. */ /** An action to download or remove downloaded SmoothStreaming streams. */
public final class SsDownloadAction extends SegmentDownloadAction<TrackKey> { 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; private static final int VERSION = 0;
public static final Deserializer DESERIALIZER = public static final Deserializer DESERIALIZER =
@ -39,30 +40,28 @@ public final class SsDownloadAction extends SegmentDownloadAction<TrackKey> {
return new TrackKey(input.readInt(), input.readInt()); return new TrackKey(input.readInt(), input.readInt());
} }
@Override
protected TrackKey[] createKeyArray(int keyCount) {
return new TrackKey[keyCount];
}
@Override @Override
protected DownloadAction createDownloadAction( protected DownloadAction createDownloadAction(
boolean isRemoveAction, String data, Uri manifestUri, TrackKey[] keys) { Uri uri, boolean isRemoveAction, String data, List<TrackKey> keys) {
return new SsDownloadAction(isRemoveAction, data, manifestUri, keys); return new SsDownloadAction(uri, isRemoveAction, data, keys);
} }
}; };
/** /**
* @see SegmentDownloadAction#SegmentDownloadAction(String, int, boolean, String, Uri, * @param uri The SmoothStreaming manifest URI.
* Comparable[]) * @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( public SsDownloadAction(
boolean isRemoveAction, @Nullable String data, Uri manifestUri, TrackKey... keys) { Uri uri, boolean isRemoveAction, @Nullable String data, List<TrackKey> keys) {
super(TYPE, VERSION, isRemoveAction, data, manifestUri, keys); super(TYPE, VERSION, uri, isRemoveAction, data, keys);
} }
@Override @Override
protected SsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) { protected SsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
return new SsDownloader(manifestUri, constructorHelper, keys); return new SsDownloader(uri, constructorHelper, keys);
} }
@Override @Override

View File

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

View File

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