Use default Deserializers if non given to DownloadManager
Also moved shared code to SegmentDownloadAction between its subclasses. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=202294880
This commit is contained in:
parent
f2ce0d8981
commit
93cbae5bff
@ -37,6 +37,7 @@
|
|||||||
CommentFrame to InternalFrame for frames with gapless metadata in MP4.
|
CommentFrame to InternalFrame for frames with gapless metadata in MP4.
|
||||||
* Allow setting the `Looper`, which is used to access the player, in
|
* Allow setting the `Looper`, which is used to access the player, in
|
||||||
`ExoPlayerFactory` ([#4278](https://github.com/google/ExoPlayer/issues/4278)).
|
`ExoPlayerFactory` ([#4278](https://github.com/google/ExoPlayer/issues/4278)).
|
||||||
|
* Use default Deserializers if non given to DownloadManager.
|
||||||
* Deprecate `Player.DefaultEventListener` as selective listener overrides can
|
* Deprecate `Player.DefaultEventListener` as selective listener overrides can
|
||||||
be directly made with the `Player.EventListener` interface.
|
be directly made with the `Player.EventListener` interface.
|
||||||
* Deprecate `DefaultAnalyticsListener` as selective listener overrides can be
|
* Deprecate `DefaultAnalyticsListener` as selective listener overrides can be
|
||||||
|
@ -16,13 +16,8 @@
|
|||||||
package com.google.android.exoplayer2.demo;
|
package com.google.android.exoplayer2.demo;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
import com.google.android.exoplayer2.offline.DownloadAction.Deserializer;
|
|
||||||
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;
|
||||||
import com.google.android.exoplayer2.offline.ProgressiveDownloadAction;
|
|
||||||
import com.google.android.exoplayer2.source.dash.offline.DashDownloadAction;
|
|
||||||
import com.google.android.exoplayer2.source.hls.offline.HlsDownloadAction;
|
|
||||||
import com.google.android.exoplayer2.source.smoothstreaming.offline.SsDownloadAction;
|
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
||||||
@ -46,13 +41,6 @@ public class DemoApplication extends Application {
|
|||||||
private static final String DOWNLOAD_TRACKER_ACTION_FILE = "tracked_actions";
|
private static final String DOWNLOAD_TRACKER_ACTION_FILE = "tracked_actions";
|
||||||
private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads";
|
private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads";
|
||||||
private static final int MAX_SIMULTANEOUS_DOWNLOADS = 2;
|
private static final int MAX_SIMULTANEOUS_DOWNLOADS = 2;
|
||||||
private static final Deserializer[] DOWNLOAD_DESERIALIZERS =
|
|
||||||
new Deserializer[] {
|
|
||||||
DashDownloadAction.DESERIALIZER,
|
|
||||||
HlsDownloadAction.DESERIALIZER,
|
|
||||||
SsDownloadAction.DESERIALIZER,
|
|
||||||
ProgressiveDownloadAction.DESERIALIZER
|
|
||||||
};
|
|
||||||
|
|
||||||
protected String userAgent;
|
protected String userAgent;
|
||||||
|
|
||||||
@ -105,14 +93,12 @@ public class DemoApplication extends Application {
|
|||||||
downloaderConstructorHelper,
|
downloaderConstructorHelper,
|
||||||
MAX_SIMULTANEOUS_DOWNLOADS,
|
MAX_SIMULTANEOUS_DOWNLOADS,
|
||||||
DownloadManager.DEFAULT_MIN_RETRY_COUNT,
|
DownloadManager.DEFAULT_MIN_RETRY_COUNT,
|
||||||
new File(getDownloadDirectory(), DOWNLOAD_ACTION_FILE),
|
new File(getDownloadDirectory(), DOWNLOAD_ACTION_FILE));
|
||||||
DOWNLOAD_DESERIALIZERS);
|
|
||||||
downloadTracker =
|
downloadTracker =
|
||||||
new DownloadTracker(
|
new DownloadTracker(
|
||||||
/* context= */ this,
|
/* context= */ this,
|
||||||
buildDataSourceFactory(/* listener= */ null),
|
buildDataSourceFactory(/* listener= */ null),
|
||||||
new File(getDownloadDirectory(), DOWNLOAD_TRACKER_ACTION_FILE),
|
new File(getDownloadDirectory(), DOWNLOAD_TRACKER_ACTION_FILE));
|
||||||
DOWNLOAD_DESERIALIZERS);
|
|
||||||
downloadManager.addListener(downloadTracker);
|
downloadManager.addListener(downloadTracker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,6 @@ import com.google.android.exoplayer2.offline.DownloadManager;
|
|||||||
import com.google.android.exoplayer2.offline.DownloadManager.TaskState;
|
import com.google.android.exoplayer2.offline.DownloadManager.TaskState;
|
||||||
import com.google.android.exoplayer2.offline.DownloadService;
|
import com.google.android.exoplayer2.offline.DownloadService;
|
||||||
import com.google.android.exoplayer2.offline.ProgressiveDownloadHelper;
|
import com.google.android.exoplayer2.offline.ProgressiveDownloadHelper;
|
||||||
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
|
|
||||||
import com.google.android.exoplayer2.offline.StreamKey;
|
import com.google.android.exoplayer2.offline.StreamKey;
|
||||||
import com.google.android.exoplayer2.offline.TrackKey;
|
import com.google.android.exoplayer2.offline.TrackKey;
|
||||||
import com.google.android.exoplayer2.source.TrackGroup;
|
import com.google.android.exoplayer2.source.TrackGroup;
|
||||||
@ -86,7 +85,7 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
Context context,
|
Context context,
|
||||||
DataSource.Factory dataSourceFactory,
|
DataSource.Factory dataSourceFactory,
|
||||||
File actionFile,
|
File actionFile,
|
||||||
DownloadAction.Deserializer[] deserializers) {
|
DownloadAction.Deserializer... deserializers) {
|
||||||
this.context = context.getApplicationContext();
|
this.context = context.getApplicationContext();
|
||||||
this.dataSourceFactory = dataSourceFactory;
|
this.dataSourceFactory = dataSourceFactory;
|
||||||
this.actionFile = new ActionFile(actionFile);
|
this.actionFile = new ActionFile(actionFile);
|
||||||
@ -96,7 +95,8 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
HandlerThread actionFileWriteThread = new HandlerThread("DownloadTracker");
|
HandlerThread actionFileWriteThread = new HandlerThread("DownloadTracker");
|
||||||
actionFileWriteThread.start();
|
actionFileWriteThread.start();
|
||||||
actionFileWriteHandler = new Handler(actionFileWriteThread.getLooper());
|
actionFileWriteHandler = new Handler(actionFileWriteThread.getLooper());
|
||||||
loadTrackedActions(deserializers);
|
loadTrackedActions(
|
||||||
|
deserializers.length > 0 ? deserializers : DownloadAction.getDefaultDeserializers());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addListener(Listener listener) {
|
public void addListener(Listener listener) {
|
||||||
@ -116,11 +116,7 @@ public class DownloadTracker implements DownloadManager.Listener {
|
|||||||
if (!trackedDownloadStates.containsKey(uri)) {
|
if (!trackedDownloadStates.containsKey(uri)) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
DownloadAction action = trackedDownloadStates.get(uri);
|
return trackedDownloadStates.get(uri).getKeys();
|
||||||
if (action instanceof SegmentDownloadAction) {
|
|
||||||
return ((SegmentDownloadAction) action).keys;
|
|
||||||
}
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleDownload(Activity activity, String name, Uri uri, String extension) {
|
public void toggleDownload(Activity activity, String name, Uri uri, String extension) {
|
||||||
|
@ -17,6 +17,7 @@ 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.util.Assertions;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
@ -24,6 +25,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/** Contains the necessary parameters for a download or remove action. */
|
/** Contains the necessary parameters for a download or remove action. */
|
||||||
public abstract class DownloadAction {
|
public abstract class DownloadAction {
|
||||||
@ -50,6 +53,48 @@ public abstract class DownloadAction {
|
|||||||
throws IOException;
|
throws IOException;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static @Nullable Deserializer[] defaultDeserializers;
|
||||||
|
|
||||||
|
/** Returns available default {@link Deserializer}s. */
|
||||||
|
public static synchronized Deserializer[] getDefaultDeserializers() {
|
||||||
|
if (defaultDeserializers != null) {
|
||||||
|
return defaultDeserializers;
|
||||||
|
}
|
||||||
|
Deserializer[] deserializers = new Deserializer[4];
|
||||||
|
int count = 0;
|
||||||
|
deserializers[count++] = ProgressiveDownloadAction.DESERIALIZER;
|
||||||
|
Class<?> clazz;
|
||||||
|
// Full class names used for constructor args so the LINT rule triggers if any of them move.
|
||||||
|
try {
|
||||||
|
// LINT.IfChange
|
||||||
|
clazz = Class.forName("com.google.android.exoplayer2.source.dash.offline.DashDownloadAction");
|
||||||
|
// LINT.ThenChange(../../../../../../../../../dash/proguard-rules.txt)
|
||||||
|
deserializers[count++] = getDeserializer(clazz);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// LINT.IfChange
|
||||||
|
clazz = Class.forName("com.google.android.exoplayer2.source.hls.offline.HlsDownloadAction");
|
||||||
|
// LINT.ThenChange(../../../../../../../../../hls/proguard-rules.txt)
|
||||||
|
deserializers[count++] = getDeserializer(clazz);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// LINT.IfChange
|
||||||
|
clazz =
|
||||||
|
Class.forName(
|
||||||
|
"com.google.android.exoplayer2.source.smoothstreaming.offline.SsDownloadAction");
|
||||||
|
// LINT.ThenChange(../../../../../../../../../smoothstreaming/proguard-rules.txt)
|
||||||
|
deserializers[count++] = getDeserializer(clazz);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
defaultDeserializers = Arrays.copyOf(Assertions.checkNotNull(deserializers), count);
|
||||||
|
return defaultDeserializers;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserializes one action that was serialized with {@link #serializeToStream(DownloadAction,
|
* Deserializes one action that was serialized with {@link #serializeToStream(DownloadAction,
|
||||||
* OutputStream)} from the {@code input}, using the {@link Deserializer}s that supports the
|
* OutputStream)} from the {@code input}, using the {@link Deserializer}s that supports the
|
||||||
@ -132,11 +177,16 @@ public abstract class DownloadAction {
|
|||||||
return uri.equals(other.uri);
|
return uri.equals(other.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns keys of tracks to be downloaded. */
|
||||||
|
public List<StreamKey> getKeys() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
/** 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;
|
||||||
|
|
||||||
/** Creates a {@link Downloader} with the given parameters. */
|
/** Creates a {@link Downloader} with the given parameters. */
|
||||||
protected abstract Downloader createDownloader(
|
public abstract Downloader createDownloader(
|
||||||
DownloaderConstructorHelper downloaderConstructorHelper);
|
DownloaderConstructorHelper downloaderConstructorHelper);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -160,4 +210,9 @@ public abstract class DownloadAction {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Deserializer getDeserializer(Class<?> clazz)
|
||||||
|
throws NoSuchFieldException, IllegalAccessException {
|
||||||
|
Object value = clazz.getDeclaredField("DESERIALIZER").get(null);
|
||||||
|
return (Deserializer) Assertions.checkNotNull(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,8 @@ public final class DownloadManager {
|
|||||||
* @param upstreamDataSourceFactory A {@link DataSource.Factory} for creating data sources for
|
* @param upstreamDataSourceFactory A {@link DataSource.Factory} for creating data sources for
|
||||||
* downloading upstream data.
|
* downloading upstream data.
|
||||||
* @param actionSaveFile File to save active actions.
|
* @param actionSaveFile File to save active actions.
|
||||||
* @param deserializers Used to deserialize {@link DownloadAction}s.
|
* @param deserializers Used to deserialize {@link DownloadAction}s. If empty, {@link
|
||||||
|
* DownloadAction#getDefaultDeserializers()} is used instead.
|
||||||
*/
|
*/
|
||||||
public DownloadManager(
|
public DownloadManager(
|
||||||
Cache cache,
|
Cache cache,
|
||||||
@ -127,7 +128,8 @@ public final class DownloadManager {
|
|||||||
* @param constructorHelper A {@link DownloaderConstructorHelper} to create {@link Downloader}s
|
* @param constructorHelper A {@link DownloaderConstructorHelper} to create {@link Downloader}s
|
||||||
* for downloading data.
|
* for downloading data.
|
||||||
* @param actionFile The file in which active actions are saved.
|
* @param actionFile The file in which active actions are saved.
|
||||||
* @param deserializers Used to deserialize {@link DownloadAction}s.
|
* @param deserializers Used to deserialize {@link DownloadAction}s. If empty, {@link
|
||||||
|
* DownloadAction#getDefaultDeserializers()} is used instead.
|
||||||
*/
|
*/
|
||||||
public DownloadManager(
|
public DownloadManager(
|
||||||
DownloaderConstructorHelper constructorHelper,
|
DownloaderConstructorHelper constructorHelper,
|
||||||
@ -149,7 +151,8 @@ public final class DownloadManager {
|
|||||||
* @param maxSimultaneousDownloads The maximum number of simultaneous download tasks.
|
* @param maxSimultaneousDownloads The maximum number of simultaneous download tasks.
|
||||||
* @param minRetryCount The minimum number of times a task must be retried before failing.
|
* @param minRetryCount The minimum number of times a task must be retried before failing.
|
||||||
* @param actionFile The file in which active actions are saved.
|
* @param actionFile The file in which active actions are saved.
|
||||||
* @param deserializers Used to deserialize {@link DownloadAction}s.
|
* @param deserializers Used to deserialize {@link DownloadAction}s. If empty, {@link
|
||||||
|
* DownloadAction#getDefaultDeserializers()} is used instead.
|
||||||
*/
|
*/
|
||||||
public DownloadManager(
|
public DownloadManager(
|
||||||
DownloaderConstructorHelper constructorHelper,
|
DownloaderConstructorHelper constructorHelper,
|
||||||
@ -157,13 +160,12 @@ public final class DownloadManager {
|
|||||||
int minRetryCount,
|
int minRetryCount,
|
||||||
File actionFile,
|
File actionFile,
|
||||||
Deserializer... deserializers) {
|
Deserializer... deserializers) {
|
||||||
Assertions.checkArgument(deserializers.length > 0, "At least one Deserializer is required.");
|
|
||||||
|
|
||||||
this.downloaderConstructorHelper = constructorHelper;
|
this.downloaderConstructorHelper = constructorHelper;
|
||||||
this.maxActiveDownloadTasks = maxSimultaneousDownloads;
|
this.maxActiveDownloadTasks = maxSimultaneousDownloads;
|
||||||
this.minRetryCount = minRetryCount;
|
this.minRetryCount = minRetryCount;
|
||||||
this.actionFile = new ActionFile(actionFile);
|
this.actionFile = new ActionFile(actionFile);
|
||||||
this.deserializers = deserializers;
|
this.deserializers =
|
||||||
|
deserializers.length > 0 ? deserializers : DownloadAction.getDefaultDeserializers();
|
||||||
this.downloadsStopped = true;
|
this.downloadsStopped = true;
|
||||||
|
|
||||||
tasks = new ArrayList<>();
|
tasks = new ArrayList<>();
|
||||||
|
@ -44,7 +44,33 @@ public final class ProgressiveDownloadAction extends DownloadAction {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final @Nullable String customCacheKey;
|
private final @Nullable String customCacheKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a progressive stream download action.
|
||||||
|
*
|
||||||
|
* @param uri Uri of the data to be downloaded.
|
||||||
|
* @param data Optional custom data for this action.
|
||||||
|
* @param customCacheKey A custom key that uniquely identifies the original stream. If not null it
|
||||||
|
* is used for cache indexing.
|
||||||
|
*/
|
||||||
|
public static ProgressiveDownloadAction createDownloadAction(
|
||||||
|
Uri uri, @Nullable byte[] data, @Nullable String customCacheKey) {
|
||||||
|
return new ProgressiveDownloadAction(uri, /* isRemoveAction= */ false, data, customCacheKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a progressive stream remove action.
|
||||||
|
*
|
||||||
|
* @param uri Uri of the data to be removed.
|
||||||
|
* @param data Optional custom data for this action.
|
||||||
|
* @param customCacheKey A custom key that uniquely identifies the original stream. If not null it
|
||||||
|
* is used for cache indexing.
|
||||||
|
*/
|
||||||
|
public static ProgressiveDownloadAction createRemoveAction(
|
||||||
|
Uri uri, @Nullable byte[] data, @Nullable String customCacheKey) {
|
||||||
|
return new ProgressiveDownloadAction(uri, /* isRemoveAction= */ true, data, customCacheKey);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param uri Uri of the data to be downloaded.
|
* @param uri Uri of the data to be downloaded.
|
||||||
@ -52,7 +78,10 @@ public final class ProgressiveDownloadAction extends DownloadAction {
|
|||||||
* @param data Optional custom data for this action.
|
* @param data Optional custom data for this action.
|
||||||
* @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.
|
||||||
|
* @deprecated Use {@link #createDownloadAction(Uri, byte[], String)} or {@link
|
||||||
|
* #createRemoveAction(Uri, byte[], String)}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public ProgressiveDownloadAction(
|
public ProgressiveDownloadAction(
|
||||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, @Nullable String customCacheKey) {
|
Uri uri, boolean isRemoveAction, @Nullable byte[] data, @Nullable String customCacheKey) {
|
||||||
super(TYPE, VERSION, uri, isRemoveAction, data);
|
super(TYPE, VERSION, uri, isRemoveAction, data);
|
||||||
@ -60,7 +89,7 @@ public final class ProgressiveDownloadAction extends DownloadAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ProgressiveDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
|
public ProgressiveDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
|
||||||
return new ProgressiveDownloader(uri, customCacheKey, constructorHelper);
|
return new ProgressiveDownloader(uri, customCacheKey, constructorHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,4 +134,5 @@ public final class ProgressiveDownloadAction extends DownloadAction {
|
|||||||
private String getCacheKey() {
|
private String getCacheKey() {
|
||||||
return customCacheKey != null ? customCacheKey : CacheUtil.generateKey(uri);
|
return customCacheKey != null ? customCacheKey : CacheUtil.generateKey(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -51,12 +51,13 @@ public final class ProgressiveDownloadHelper extends DownloadHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DownloadAction getDownloadAction(@Nullable byte[] data, List<TrackKey> trackKeys) {
|
public ProgressiveDownloadAction getDownloadAction(
|
||||||
return new ProgressiveDownloadAction(uri, false, data, customCacheKey);
|
@Nullable byte[] data, List<TrackKey> trackKeys) {
|
||||||
|
return ProgressiveDownloadAction.createDownloadAction(uri, data, customCacheKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DownloadAction getRemoveAction(@Nullable byte[] data) {
|
public ProgressiveDownloadAction getRemoveAction(@Nullable byte[] data) {
|
||||||
return new ProgressiveDownloadAction(uri, true, data, customCacheKey);
|
return ProgressiveDownloadAction.createRemoveAction(uri, data, customCacheKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,13 +46,18 @@ public abstract class SegmentDownloadAction extends DownloadAction {
|
|||||||
int keyCount = input.readInt();
|
int keyCount = input.readInt();
|
||||||
List<StreamKey> keys = new ArrayList<>();
|
List<StreamKey> keys = new ArrayList<>();
|
||||||
for (int i = 0; i < keyCount; i++) {
|
for (int i = 0; i < keyCount; i++) {
|
||||||
keys.add(readKey(input));
|
keys.add(readKey(version, input));
|
||||||
}
|
}
|
||||||
return createDownloadAction(uri, isRemoveAction, data, keys);
|
return createDownloadAction(uri, isRemoveAction, data, keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Deserializes a key from the {@code input}. */
|
/** Deserializes a key from the {@code input}. */
|
||||||
protected abstract StreamKey readKey(DataInputStream input) throws IOException;
|
protected StreamKey readKey(int version, DataInputStream input) throws IOException {
|
||||||
|
int periodIndex = input.readInt();
|
||||||
|
int groupIndex = input.readInt();
|
||||||
|
int trackIndex = input.readInt();
|
||||||
|
return new StreamKey(periodIndex, groupIndex, trackIndex);
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns a {@link DownloadAction}. */
|
/** Returns a {@link DownloadAction}. */
|
||||||
protected abstract DownloadAction createDownloadAction(
|
protected abstract DownloadAction createDownloadAction(
|
||||||
@ -88,6 +93,11 @@ public abstract class SegmentDownloadAction extends DownloadAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StreamKey> getKeys() {
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void writeToStream(DataOutputStream output) throws IOException {
|
public final void writeToStream(DataOutputStream output) throws IOException {
|
||||||
output.writeUTF(uri.toString());
|
output.writeUTF(uri.toString());
|
||||||
@ -100,9 +110,6 @@ public abstract class SegmentDownloadAction extends DownloadAction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Serializes the {@code key} into the {@code output}. */
|
|
||||||
protected abstract void writeKey(DataOutputStream output, StreamKey key) throws IOException;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(@Nullable Object o) {
|
public boolean equals(@Nullable Object o) {
|
||||||
if (this == o) {
|
if (this == o) {
|
||||||
@ -122,4 +129,10 @@ public abstract class SegmentDownloadAction extends DownloadAction {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Serializes the {@code key} into the {@code output}. */
|
||||||
|
private void writeKey(DataOutputStream output, StreamKey key) throws IOException {
|
||||||
|
output.writeInt(key.periodIndex);
|
||||||
|
output.writeInt(key.groupIndex);
|
||||||
|
output.writeInt(key.trackIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,9 +33,7 @@ import org.junit.runner.RunWith;
|
|||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
import org.robolectric.RuntimeEnvironment;
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
|
||||||
/**
|
/** Unit tests for {@link ActionFile}. */
|
||||||
* Unit tests for {@link ProgressiveDownloadAction}.
|
|
||||||
*/
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class ActionFileTest {
|
public class ActionFileTest {
|
||||||
|
|
||||||
@ -258,7 +256,7 @@ public class ActionFileTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Downloader createDownloader(DownloaderConstructorHelper downloaderConstructorHelper) {
|
public Downloader createDownloader(DownloaderConstructorHelper downloaderConstructorHelper) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,7 +510,7 @@ public class DownloadManagerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Downloader createDownloader(DownloaderConstructorHelper downloaderConstructorHelper) {
|
public Downloader createDownloader(DownloaderConstructorHelper downloaderConstructorHelper) {
|
||||||
return downloader;
|
return downloader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,9 +32,7 @@ import org.mockito.Mockito;
|
|||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
/**
|
/** Unit tests for {@link ProgressiveDownloadAction}. */
|
||||||
* Unit tests for {@link ProgressiveDownloadAction}.
|
|
||||||
*/
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class ProgressiveDownloadActionTest {
|
public class ProgressiveDownloadActionTest {
|
||||||
|
|
||||||
@ -49,112 +47,109 @@ public class ProgressiveDownloadActionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDownloadActionIsNotRemoveAction() throws Exception {
|
public void testDownloadActionIsNotRemoveAction() throws Exception {
|
||||||
ProgressiveDownloadAction action = new ProgressiveDownloadAction(uri1, false, null, null);
|
DownloadAction action = createDownloadAction(uri1, 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(uri1, true, null, null);
|
DownloadAction action2 = createRemoveAction(uri1, 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(uri1, false, null, null);
|
DownloadAction action = createDownloadAction(uri1, null);
|
||||||
DownloaderConstructorHelper constructorHelper = new DownloaderConstructorHelper(
|
DownloaderConstructorHelper constructorHelper =
|
||||||
Mockito.mock(Cache.class), DummyDataSource.FACTORY);
|
new DownloaderConstructorHelper(Mockito.mock(Cache.class), DummyDataSource.FACTORY);
|
||||||
assertThat(action.createDownloader(constructorHelper)).isNotNull();
|
assertThat(action.createDownloader(constructorHelper)).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSameUriCacheKeyDifferentAction_IsSameMedia() throws Exception {
|
public void testSameUriCacheKeyDifferentAction_IsSameMedia() throws Exception {
|
||||||
ProgressiveDownloadAction action1 = new ProgressiveDownloadAction(uri1, true, null, null);
|
DownloadAction action1 = createRemoveAction(uri1, null);
|
||||||
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(uri1, false, null, null);
|
DownloadAction action2 = createDownloadAction(uri1, 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(uri2, true, null, null);
|
DownloadAction action3 = createRemoveAction(uri2, null);
|
||||||
ProgressiveDownloadAction action4 = new ProgressiveDownloadAction(uri1, false, null, null);
|
DownloadAction action4 = createDownloadAction(uri1, 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(uri2, true, null, "key");
|
DownloadAction action5 = createRemoveAction(uri2, "key");
|
||||||
ProgressiveDownloadAction action6 = new ProgressiveDownloadAction(uri1, false, null, "key");
|
DownloadAction action6 = createDownloadAction(uri1, "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(uri1, true, null, "key");
|
DownloadAction action7 = createRemoveAction(uri1, "key");
|
||||||
ProgressiveDownloadAction action8 = new ProgressiveDownloadAction(uri1, false, null, "key2");
|
DownloadAction action8 = createDownloadAction(uri1, "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(uri1, true, null, "key");
|
DownloadAction action1 = createRemoveAction(uri1, "key");
|
||||||
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(uri1, false, null, null);
|
DownloadAction action2 = createDownloadAction(uri1, null);
|
||||||
assertNotSameMedia(action1, action2);
|
assertNotSameMedia(action1, action2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEquals() throws Exception {
|
public void testEquals() throws Exception {
|
||||||
ProgressiveDownloadAction action1 = new ProgressiveDownloadAction(uri1, true, null, null);
|
DownloadAction action1 = createRemoveAction(uri1, null);
|
||||||
assertThat(action1.equals(action1)).isTrue();
|
assertThat(action1.equals(action1)).isTrue();
|
||||||
|
|
||||||
ProgressiveDownloadAction action2 = new ProgressiveDownloadAction(uri1, true, null, null);
|
DownloadAction action2 = createRemoveAction(uri1, null);
|
||||||
ProgressiveDownloadAction action3 = new ProgressiveDownloadAction(uri1, true, null, null);
|
DownloadAction action3 = createRemoveAction(uri1, null);
|
||||||
assertThat(action2.equals(action3)).isTrue();
|
assertThat(action2.equals(action3)).isTrue();
|
||||||
|
|
||||||
ProgressiveDownloadAction action4 = new ProgressiveDownloadAction(uri1, true, null, null);
|
DownloadAction action4 = createRemoveAction(uri1, null);
|
||||||
ProgressiveDownloadAction action5 = new ProgressiveDownloadAction(uri1, false, null, null);
|
DownloadAction action5 = createDownloadAction(uri1, null);
|
||||||
assertThat(action4.equals(action5)).isFalse();
|
assertThat(action4.equals(action5)).isFalse();
|
||||||
|
|
||||||
ProgressiveDownloadAction action6 = new ProgressiveDownloadAction(uri1, true, null, null);
|
DownloadAction action6 = createRemoveAction(uri1, null);
|
||||||
ProgressiveDownloadAction action7 = new ProgressiveDownloadAction(uri1, true, null, "key");
|
DownloadAction action7 = createRemoveAction(uri1, "key");
|
||||||
assertThat(action6.equals(action7)).isFalse();
|
assertThat(action6.equals(action7)).isFalse();
|
||||||
|
|
||||||
ProgressiveDownloadAction action8 = new ProgressiveDownloadAction(uri1, true, null, "key2");
|
DownloadAction action8 = createRemoveAction(uri1, "key2");
|
||||||
ProgressiveDownloadAction action9 = new ProgressiveDownloadAction(uri1, true, null, "key");
|
DownloadAction action9 = createRemoveAction(uri1, "key");
|
||||||
assertThat(action8.equals(action9)).isFalse();
|
assertThat(action8.equals(action9)).isFalse();
|
||||||
|
|
||||||
ProgressiveDownloadAction action10 = new ProgressiveDownloadAction(uri1, true, null, null);
|
DownloadAction action10 = createRemoveAction(uri1, null);
|
||||||
ProgressiveDownloadAction action11 = new ProgressiveDownloadAction(uri2, true, null, null);
|
DownloadAction action11 = createRemoveAction(uri2, 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(uri1, false, null, null);
|
DownloadAction action = createDownloadAction(uri1, null);
|
||||||
assertThat(action.type).isNotNull();
|
assertThat(action.type).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSerializerWriteRead() throws Exception {
|
public void testSerializerWriteRead() throws Exception {
|
||||||
doTestSerializationRoundTrip(new ProgressiveDownloadAction(uri1, false, null, null));
|
doTestSerializationRoundTrip(createDownloadAction(uri1, null));
|
||||||
doTestSerializationRoundTrip(new ProgressiveDownloadAction(uri2, true, null, "key"));
|
doTestSerializationRoundTrip(createRemoveAction(uri2, "key"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertSameMedia(
|
private void assertSameMedia(DownloadAction action1, DownloadAction action2) {
|
||||||
ProgressiveDownloadAction action1, ProgressiveDownloadAction action2) {
|
|
||||||
assertThat(action1.isSameMedia(action2)).isTrue();
|
assertThat(action1.isSameMedia(action2)).isTrue();
|
||||||
assertThat(action2.isSameMedia(action1)).isTrue();
|
assertThat(action2.isSameMedia(action1)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertNotSameMedia(
|
private void assertNotSameMedia(DownloadAction action1, DownloadAction action2) {
|
||||||
ProgressiveDownloadAction action1, ProgressiveDownloadAction action2) {
|
|
||||||
assertThat(action1.isSameMedia(action2)).isFalse();
|
assertThat(action1.isSameMedia(action2)).isFalse();
|
||||||
assertThat(action2.isSameMedia(action1)).isFalse();
|
assertThat(action2.isSameMedia(action1)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void doTestSerializationRoundTrip(ProgressiveDownloadAction action)
|
private static void doTestSerializationRoundTrip(DownloadAction action) throws IOException {
|
||||||
throws IOException {
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
DataOutputStream output = new DataOutputStream(out);
|
DataOutputStream output = new DataOutputStream(out);
|
||||||
DownloadAction.serializeToStream(action, output);
|
DownloadAction.serializeToStream(action, output);
|
||||||
@ -168,4 +163,11 @@ public class ProgressiveDownloadActionTest {
|
|||||||
assertThat(action2).isEqualTo(action);
|
assertThat(action2).isEqualTo(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static DownloadAction createDownloadAction(Uri uri1, String customCacheKey) {
|
||||||
|
return ProgressiveDownloadAction.createDownloadAction(uri1, null, customCacheKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DownloadAction createRemoveAction(Uri uri1, String customCacheKey) {
|
||||||
|
return ProgressiveDownloadAction.createRemoveAction(uri1, null, customCacheKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion project.ext.minSdkVersion
|
minSdkVersion project.ext.minSdkVersion
|
||||||
targetSdkVersion project.ext.targetSdkVersion
|
targetSdkVersion project.ext.targetSdkVersion
|
||||||
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
7
library/dash/proguard-rules.txt
Normal file
7
library/dash/proguard-rules.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Proguard rules specific to the dash module.
|
||||||
|
|
||||||
|
# Constructors accessed via reflection in SegmentDownloadAction
|
||||||
|
-dontnote com.google.android.exoplayer2.source.dash.offline.DashDownloadAction
|
||||||
|
-keepclassmembers class com.google.android.exoplayer2.source.dash.offline.DashDownloadAction {
|
||||||
|
static ** DESERIALIZER;
|
||||||
|
}
|
@ -21,9 +21,7 @@ import com.google.android.exoplayer2.offline.DownloadAction;
|
|||||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||||
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
|
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
|
||||||
import com.google.android.exoplayer2.offline.StreamKey;
|
import com.google.android.exoplayer2.offline.StreamKey;
|
||||||
import java.io.DataInputStream;
|
import java.util.Collections;
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/** An action to download or remove downloaded DASH streams. */
|
/** An action to download or remove downloaded DASH streams. */
|
||||||
@ -34,15 +32,6 @@ public final class DashDownloadAction extends SegmentDownloadAction {
|
|||||||
|
|
||||||
public static final Deserializer DESERIALIZER =
|
public static final Deserializer DESERIALIZER =
|
||||||
new SegmentDownloadActionDeserializer(TYPE, VERSION) {
|
new SegmentDownloadActionDeserializer(TYPE, VERSION) {
|
||||||
|
|
||||||
@Override
|
|
||||||
protected StreamKey readKey(DataInputStream input) throws IOException {
|
|
||||||
int periodIndex = input.readInt();
|
|
||||||
int groupIndex = input.readInt();
|
|
||||||
int trackIndex = input.readInt();
|
|
||||||
return new StreamKey(periodIndex, groupIndex, trackIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DownloadAction createDownloadAction(
|
protected DownloadAction createDownloadAction(
|
||||||
Uri uri, boolean isRemoveAction, byte[] data, List<StreamKey> keys) {
|
Uri uri, boolean isRemoveAction, byte[] data, List<StreamKey> keys) {
|
||||||
@ -50,28 +39,46 @@ public final class DashDownloadAction extends SegmentDownloadAction {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a DASH download action.
|
||||||
|
*
|
||||||
|
* @param uri The URI of the media to be downloaded.
|
||||||
|
* @param data Optional custom data for this action. If {@code null} an empty array will be used.
|
||||||
|
* @param keys Keys of tracks to be downloaded. If empty, all tracks will be downloaded.
|
||||||
|
*/
|
||||||
|
public static DashDownloadAction createDownloadAction(
|
||||||
|
Uri uri, @Nullable byte[] data, List<StreamKey> keys) {
|
||||||
|
return new DashDownloadAction(uri, /* isRemoveAction= */ false, data, keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a DASH remove action.
|
||||||
|
*
|
||||||
|
* @param uri The URI of the media to be removed.
|
||||||
|
* @param data Optional custom data for this action. If {@code null} an empty array will be used.
|
||||||
|
*/
|
||||||
|
public static DashDownloadAction createRemoveAction(Uri uri, @Nullable byte[] data) {
|
||||||
|
return new DashDownloadAction(uri, /* isRemoveAction= */ true, data, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param uri The DASH manifest URI.
|
* @param uri The DASH manifest URI.
|
||||||
* @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.
|
* @param data Optional custom data for this action.
|
||||||
* @param keys Keys of representations to be downloaded. If empty, all representations are
|
* @param keys Keys of representations to be downloaded. If empty, all representations are
|
||||||
* downloaded. If {@code removeAction} is true, {@code keys} must be empty.
|
* downloaded. If {@code removeAction} is true, {@code keys} must be empty.
|
||||||
|
* @deprecated Use {@link #createDownloadAction(Uri, byte[], List)} or {@link
|
||||||
|
* #createRemoveAction(Uri, byte[])}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public DashDownloadAction(
|
public DashDownloadAction(
|
||||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, List<StreamKey> keys) {
|
Uri uri, boolean isRemoveAction, @Nullable byte[] data, List<StreamKey> keys) {
|
||||||
super(TYPE, VERSION, uri, isRemoveAction, data, keys);
|
super(TYPE, VERSION, uri, isRemoveAction, data, keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DashDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
|
public DashDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
|
||||||
return new DashDownloader(uri, keys, constructorHelper);
|
return new DashDownloader(uri, keys, constructorHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void writeKey(DataOutputStream output, StreamKey key) throws IOException {
|
|
||||||
output.writeInt(key.periodIndex);
|
|
||||||
output.writeInt(key.groupIndex);
|
|
||||||
output.writeInt(key.trackIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ import com.google.android.exoplayer2.upstream.ParsingLoadable;
|
|||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
@ -88,12 +87,12 @@ public final class DashDownloadHelper extends DownloadHelper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DashDownloadAction getDownloadAction(@Nullable byte[] data, List<TrackKey> trackKeys) {
|
public DashDownloadAction getDownloadAction(@Nullable byte[] data, List<TrackKey> trackKeys) {
|
||||||
return new DashDownloadAction(uri, /* isRemoveAction= */ false, data, toStreamKeys(trackKeys));
|
return DashDownloadAction.createDownloadAction(uri, data, toStreamKeys(trackKeys));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DashDownloadAction getRemoveAction(@Nullable byte[] data) {
|
public DashDownloadAction getRemoveAction(@Nullable byte[] data) {
|
||||||
return new DashDownloadAction(uri, /* isRemoveAction= */ true, data, Collections.emptyList());
|
return DashDownloadAction.createRemoveAction(uri, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<StreamKey> toStreamKeys(List<TrackKey> trackKeys) {
|
private static List<StreamKey> toStreamKeys(List<TrackKey> trackKeys) {
|
||||||
|
7
library/dash/src/main/proguard-rules.txt
Normal file
7
library/dash/src/main/proguard-rules.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Proguard rules specific to the dash module.
|
||||||
|
|
||||||
|
# Constructors accessed via reflection in SegmentDownloadAction
|
||||||
|
-dontnote com.google.android.exoplayer2.source.dash.offline.DashDownloadAction
|
||||||
|
-keepclassmembers class com.google.android.exoplayer2.source.dash.offline.DashDownloadAction {
|
||||||
|
static ** DESERIALIZER;
|
||||||
|
}
|
@ -18,7 +18,6 @@ package com.google.android.exoplayer2.source.dash.offline;
|
|||||||
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.DownloadAction;
|
import com.google.android.exoplayer2.offline.DownloadAction;
|
||||||
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||||
import com.google.android.exoplayer2.offline.StreamKey;
|
import com.google.android.exoplayer2.offline.StreamKey;
|
||||||
@ -38,9 +37,7 @@ import org.mockito.Mockito;
|
|||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.robolectric.RobolectricTestRunner;
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
/**
|
/** Unit tests for {@link DashDownloadAction}. */
|
||||||
* Unit tests for {@link DashDownloadAction}.
|
|
||||||
*/
|
|
||||||
@RunWith(RobolectricTestRunner.class)
|
@RunWith(RobolectricTestRunner.class)
|
||||||
public class DashDownloadActionTest {
|
public class DashDownloadActionTest {
|
||||||
|
|
||||||
@ -55,130 +52,106 @@ public class DashDownloadActionTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDownloadActionIsNotRemoveAction() {
|
public void testDownloadActionIsNotRemoveAction() {
|
||||||
DashDownloadAction action = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
|
DownloadAction action = createDownloadAction(uri1);
|
||||||
assertThat(action.isRemoveAction).isFalse();
|
assertThat(action.isRemoveAction).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoveActionisRemoveAction() {
|
public void testRemoveActionIsRemoveAction() {
|
||||||
DashDownloadAction action2 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
|
DownloadAction action2 = createRemoveAction(uri1);
|
||||||
assertThat(action2.isRemoveAction).isTrue();
|
assertThat(action2.isRemoveAction).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateDownloader() {
|
public void testCreateDownloader() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
DashDownloadAction action = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
|
DownloadAction action = createDownloadAction(uri1);
|
||||||
DownloaderConstructorHelper constructorHelper = new DownloaderConstructorHelper(
|
DownloaderConstructorHelper constructorHelper =
|
||||||
Mockito.mock(Cache.class), DummyDataSource.FACTORY);
|
new DownloaderConstructorHelper(Mockito.mock(Cache.class), DummyDataSource.FACTORY);
|
||||||
assertThat(action.createDownloader(constructorHelper)).isNotNull();
|
assertThat(action.createDownloader(constructorHelper)).isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSameUriDifferentAction_IsSameMedia() {
|
public void testSameUriDifferentAction_IsSameMedia() {
|
||||||
DashDownloadAction action1 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
|
DownloadAction action1 = createRemoveAction(uri1);
|
||||||
DashDownloadAction action2 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
|
DownloadAction action2 = createDownloadAction(uri1);
|
||||||
assertThat(action1.isSameMedia(action2)).isTrue();
|
assertThat(action1.isSameMedia(action2)).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDifferentUriAndAction_IsNotSameMedia() {
|
public void testDifferentUriAndAction_IsNotSameMedia() {
|
||||||
DashDownloadAction action3 = newAction(uri2, /* isRemoveAction= */ true, /* data= */ null);
|
DownloadAction action3 = createRemoveAction(uri2);
|
||||||
DashDownloadAction action4 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
|
DownloadAction action4 = createDownloadAction(uri1);
|
||||||
assertThat(action3.isSameMedia(action4)).isFalse();
|
assertThat(action3.isSameMedia(action4)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("EqualsWithItself")
|
@SuppressWarnings("EqualsWithItself")
|
||||||
@Test
|
@Test
|
||||||
public void testEquals() {
|
public void testEquals() {
|
||||||
DashDownloadAction action1 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
|
DownloadAction action1 = createRemoveAction(uri1);
|
||||||
assertThat(action1.equals(action1)).isTrue();
|
assertThat(action1.equals(action1)).isTrue();
|
||||||
|
|
||||||
DashDownloadAction action2 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
|
DownloadAction action2 = createRemoveAction(uri1);
|
||||||
DashDownloadAction action3 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
|
DownloadAction action3 = createRemoveAction(uri1);
|
||||||
assertEqual(action2, action3);
|
assertEqual(action2, action3);
|
||||||
|
|
||||||
DashDownloadAction action4 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
|
DownloadAction action4 = createRemoveAction(uri1);
|
||||||
DashDownloadAction action5 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
|
DownloadAction action5 = createDownloadAction(uri1);
|
||||||
assertNotEqual(action4, action5);
|
assertNotEqual(action4, action5);
|
||||||
|
|
||||||
DashDownloadAction action6 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
|
DownloadAction action6 = createDownloadAction(uri1);
|
||||||
DashDownloadAction action7 =
|
DownloadAction action7 = createDownloadAction(uri1, new StreamKey(0, 0, 0));
|
||||||
newAction(uri1, /* isRemoveAction= */ false, /* data= */ null, new StreamKey(0, 0, 0));
|
|
||||||
assertNotEqual(action6, action7);
|
assertNotEqual(action6, action7);
|
||||||
|
|
||||||
DashDownloadAction action8 =
|
DownloadAction action8 = createDownloadAction(uri1, new StreamKey(1, 1, 1));
|
||||||
newAction(uri1, /* isRemoveAction= */ false, /* data= */ null, new StreamKey(1, 1, 1));
|
DownloadAction action9 = createDownloadAction(uri1, new StreamKey(0, 0, 0));
|
||||||
DashDownloadAction action9 =
|
|
||||||
newAction(uri1, /* isRemoveAction= */ false, /* data= */ null, new StreamKey(0, 0, 0));
|
|
||||||
assertNotEqual(action8, action9);
|
assertNotEqual(action8, action9);
|
||||||
|
|
||||||
DashDownloadAction action10 = newAction(uri1, /* isRemoveAction= */ true, /* data= */ null);
|
DownloadAction action10 = createRemoveAction(uri1);
|
||||||
DashDownloadAction action11 = newAction(uri2, /* isRemoveAction= */ true, /* data= */ null);
|
DownloadAction action11 = createRemoveAction(uri2);
|
||||||
assertNotEqual(action10, action11);
|
assertNotEqual(action10, action11);
|
||||||
|
|
||||||
DashDownloadAction action12 =
|
DownloadAction action12 =
|
||||||
newAction(
|
createDownloadAction(uri1, new StreamKey(0, 0, 0), new StreamKey(1, 1, 1));
|
||||||
uri1,
|
DownloadAction action13 =
|
||||||
/* isRemoveAction= */ false,
|
createDownloadAction(uri1, new StreamKey(1, 1, 1), new StreamKey(0, 0, 0));
|
||||||
/* data= */ null,
|
|
||||||
new StreamKey(0, 0, 0),
|
|
||||||
new StreamKey(1, 1, 1));
|
|
||||||
DashDownloadAction action13 =
|
|
||||||
newAction(
|
|
||||||
uri1,
|
|
||||||
/* isRemoveAction= */ false,
|
|
||||||
/* data= */ null,
|
|
||||||
new StreamKey(1, 1, 1),
|
|
||||||
new StreamKey(0, 0, 0));
|
|
||||||
assertEqual(action12, action13);
|
assertEqual(action12, action13);
|
||||||
|
|
||||||
DashDownloadAction action14 =
|
DownloadAction action14 = createDownloadAction(uri1, new StreamKey(0, 0, 0));
|
||||||
newAction(uri1, /* isRemoveAction= */ false, /* data= */ null, new StreamKey(0, 0, 0));
|
DownloadAction action15 =
|
||||||
DashDownloadAction action15 =
|
createDownloadAction(uri1, new StreamKey(1, 1, 1), new StreamKey(0, 0, 0));
|
||||||
newAction(
|
|
||||||
uri1,
|
|
||||||
/* isRemoveAction= */ false,
|
|
||||||
/* data= */ null,
|
|
||||||
new StreamKey(1, 1, 1),
|
|
||||||
new StreamKey(0, 0, 0));
|
|
||||||
assertNotEqual(action14, action15);
|
assertNotEqual(action14, action15);
|
||||||
|
|
||||||
DashDownloadAction action16 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
|
DownloadAction action16 = createDownloadAction(uri1);
|
||||||
DashDownloadAction action17 = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
|
DownloadAction action17 = createDownloadAction(uri1);
|
||||||
assertEqual(action16, action17);
|
assertEqual(action16, action17);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSerializerGetType() {
|
public void testSerializerGetType() {
|
||||||
DashDownloadAction action = newAction(uri1, /* isRemoveAction= */ false, /* data= */ null);
|
DownloadAction action = createDownloadAction(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(createDownloadAction(uri1));
|
||||||
doTestSerializationRoundTrip(newAction(uri1, /* isRemoveAction= */ true, /* data= */ null));
|
doTestSerializationRoundTrip(createRemoveAction(uri1));
|
||||||
doTestSerializationRoundTrip(
|
doTestSerializationRoundTrip(
|
||||||
newAction(
|
createDownloadAction(uri2, new StreamKey(0, 0, 0), new StreamKey(1, 1, 1)));
|
||||||
uri2,
|
|
||||||
/* isRemoveAction= */ false,
|
|
||||||
/* data= */ null,
|
|
||||||
new StreamKey(0, 0, 0),
|
|
||||||
new StreamKey(1, 1, 1)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertNotEqual(DashDownloadAction action1, DashDownloadAction action2) {
|
private static void assertNotEqual(DownloadAction action1, DownloadAction action2) {
|
||||||
assertThat(action1).isNotEqualTo(action2);
|
assertThat(action1).isNotEqualTo(action2);
|
||||||
assertThat(action2).isNotEqualTo(action1);
|
assertThat(action2).isNotEqualTo(action1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertEqual(DashDownloadAction action1, DashDownloadAction action2) {
|
private static void assertEqual(DownloadAction action1, DownloadAction action2) {
|
||||||
assertThat(action1).isEqualTo(action2);
|
assertThat(action1).isEqualTo(action2);
|
||||||
assertThat(action2).isEqualTo(action1);
|
assertThat(action2).isEqualTo(action1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void doTestSerializationRoundTrip(DashDownloadAction action) throws IOException {
|
private static void doTestSerializationRoundTrip(DownloadAction action) throws IOException {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
DataOutputStream output = new DataOutputStream(out);
|
DataOutputStream output = new DataOutputStream(out);
|
||||||
DownloadAction.serializeToStream(action, output);
|
DownloadAction.serializeToStream(action, output);
|
||||||
@ -192,10 +165,13 @@ public class DashDownloadActionTest {
|
|||||||
assertThat(action).isEqualTo(action2);
|
assertThat(action).isEqualTo(action2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DashDownloadAction newAction(
|
private static DownloadAction createDownloadAction(Uri uri, StreamKey... keys) {
|
||||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, StreamKey... keys) {
|
|
||||||
ArrayList<StreamKey> keysList = new ArrayList<>();
|
ArrayList<StreamKey> keysList = new ArrayList<>();
|
||||||
Collections.addAll(keysList, keys);
|
Collections.addAll(keysList, keys);
|
||||||
return new DashDownloadAction(uri, isRemoveAction, data, keysList);
|
return DashDownloadAction.createDownloadAction(uri, null, keysList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DownloadAction createRemoveAction(Uri uri) {
|
||||||
|
return DashDownloadAction.createRemoveAction(uri, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import android.content.Context;
|
|||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.ConditionVariable;
|
import android.os.ConditionVariable;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import com.google.android.exoplayer2.offline.DownloadAction;
|
||||||
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;
|
||||||
import com.google.android.exoplayer2.offline.StreamKey;
|
import com.google.android.exoplayer2.offline.StreamKey;
|
||||||
@ -279,10 +280,16 @@ public class DownloadManagerDashTest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DashDownloadAction newAction(
|
private static DownloadAction newAction(
|
||||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, StreamKey... keys) {
|
Uri uri, boolean isRemoveAction, @Nullable byte[] data, StreamKey... keys) {
|
||||||
ArrayList<StreamKey> keysList = new ArrayList<>();
|
ArrayList<StreamKey> keysList = new ArrayList<>();
|
||||||
Collections.addAll(keysList, keys);
|
Collections.addAll(keysList, keys);
|
||||||
return new DashDownloadAction(uri, isRemoveAction, data, keysList);
|
DownloadAction result;
|
||||||
|
if (isRemoveAction) {
|
||||||
|
result = DashDownloadAction.createRemoveAction(uri, data);
|
||||||
|
} else {
|
||||||
|
result = DashDownloadAction.createDownloadAction(uri, data, keysList);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
import com.google.android.exoplayer2.offline.DownloadAction;
|
||||||
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;
|
||||||
import com.google.android.exoplayer2.offline.DownloadService;
|
import com.google.android.exoplayer2.offline.DownloadService;
|
||||||
@ -216,7 +217,7 @@ public class DownloadServiceDashTest {
|
|||||||
callDownloadServiceOnStart(newAction(TEST_MPD_URI, false, null, keys));
|
callDownloadServiceOnStart(newAction(TEST_MPD_URI, false, null, keys));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void callDownloadServiceOnStart(final DashDownloadAction action) {
|
private void callDownloadServiceOnStart(final DownloadAction action) {
|
||||||
dummyMainThread.runOnMainThread(
|
dummyMainThread.runOnMainThread(
|
||||||
new Runnable() {
|
new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
@ -228,10 +229,16 @@ public class DownloadServiceDashTest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static DashDownloadAction newAction(
|
private static DownloadAction newAction(
|
||||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, StreamKey... keys) {
|
Uri uri, boolean isRemoveAction, @Nullable byte[] data, StreamKey... keys) {
|
||||||
ArrayList<StreamKey> keysList = new ArrayList<>();
|
ArrayList<StreamKey> keysList = new ArrayList<>();
|
||||||
Collections.addAll(keysList, keys);
|
Collections.addAll(keysList, keys);
|
||||||
return new DashDownloadAction(uri, isRemoveAction, data, keysList);
|
DownloadAction result;
|
||||||
|
if (isRemoveAction) {
|
||||||
|
result = DashDownloadAction.createRemoveAction(uri, data);
|
||||||
|
} else {
|
||||||
|
result = DashDownloadAction.createDownloadAction(uri, data, keysList);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion project.ext.minSdkVersion
|
minSdkVersion project.ext.minSdkVersion
|
||||||
targetSdkVersion project.ext.targetSdkVersion
|
targetSdkVersion project.ext.targetSdkVersion
|
||||||
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
7
library/hls/proguard-rules.txt
Normal file
7
library/hls/proguard-rules.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Proguard rules specific to the hls module.
|
||||||
|
|
||||||
|
# Constructors accessed via reflection in SegmentDownloadAction
|
||||||
|
-dontnote com.google.android.exoplayer2.source.hls.offline.HlsDownloadAction
|
||||||
|
-keepclassmembers class com.google.android.exoplayer2.source.hls.offline.HlsDownloadAction {
|
||||||
|
static ** DESERIALIZER;
|
||||||
|
}
|
@ -22,21 +22,24 @@ import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
|||||||
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
|
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
|
||||||
import com.google.android.exoplayer2.offline.StreamKey;
|
import com.google.android.exoplayer2.offline.StreamKey;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
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 {
|
public final class HlsDownloadAction extends SegmentDownloadAction {
|
||||||
|
|
||||||
private static final String TYPE = "hls";
|
private static final String TYPE = "hls";
|
||||||
private static final int VERSION = 0;
|
private static final int VERSION = 1;
|
||||||
|
|
||||||
public static final Deserializer DESERIALIZER =
|
public static final Deserializer DESERIALIZER =
|
||||||
new SegmentDownloadActionDeserializer(TYPE, VERSION) {
|
new SegmentDownloadActionDeserializer(TYPE, VERSION) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected StreamKey readKey(DataInputStream input) throws IOException {
|
protected StreamKey readKey(int version, DataInputStream input) throws IOException {
|
||||||
|
if (version > 0) {
|
||||||
|
return super.readKey(version, input);
|
||||||
|
}
|
||||||
int renditionGroup = input.readInt();
|
int renditionGroup = input.readInt();
|
||||||
int trackIndex = input.readInt();
|
int trackIndex = input.readInt();
|
||||||
return new StreamKey(renditionGroup, trackIndex);
|
return new StreamKey(renditionGroup, trackIndex);
|
||||||
@ -49,27 +52,46 @@ public final class HlsDownloadAction extends SegmentDownloadAction {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a HLS download action.
|
||||||
|
*
|
||||||
|
* @param uri The URI of the media to be downloaded.
|
||||||
|
* @param data Optional custom data for this action. If {@code null} an empty array will be used.
|
||||||
|
* @param keys Keys of tracks to be downloaded. If empty, all tracks will be downloaded.
|
||||||
|
*/
|
||||||
|
public static HlsDownloadAction createDownloadAction(
|
||||||
|
Uri uri, @Nullable byte[] data, List<StreamKey> keys) {
|
||||||
|
return new HlsDownloadAction(uri, /* isRemoveAction= */ false, data, keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a HLS remove action.
|
||||||
|
*
|
||||||
|
* @param uri The URI of the media to be removed.
|
||||||
|
* @param data Optional custom data for this action. If {@code null} an empty array will be used.
|
||||||
|
*/
|
||||||
|
public static HlsDownloadAction createRemoveAction(Uri uri, @Nullable byte[] data) {
|
||||||
|
return new HlsDownloadAction(uri, /* isRemoveAction= */ true, data, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param uri The HLS playlist URI.
|
* @param uri The HLS playlist URI.
|
||||||
* @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.
|
* @param data Optional custom data for this action.
|
||||||
* @param keys Keys of renditions to be downloaded. If empty, all renditions are downloaded. If
|
* @param keys Keys of renditions to be downloaded. If empty, all renditions are downloaded. If
|
||||||
* {@code removeAction} is true, {@code keys} must empty.
|
* {@code removeAction} is true, {@code keys} must empty.
|
||||||
|
* @deprecated Use {@link #createDownloadAction(Uri, byte[], List)} or {@link
|
||||||
|
* #createRemoveAction(Uri, byte[])}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public HlsDownloadAction(
|
public HlsDownloadAction(
|
||||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, List<StreamKey> keys) {
|
Uri uri, boolean isRemoveAction, @Nullable byte[] data, List<StreamKey> keys) {
|
||||||
super(TYPE, VERSION, uri, isRemoveAction, data, keys);
|
super(TYPE, VERSION, uri, isRemoveAction, data, keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HlsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
|
public HlsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
|
||||||
return new HlsDownloader(uri, keys, constructorHelper);
|
return new HlsDownloader(uri, keys, constructorHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void writeKey(DataOutputStream output, StreamKey key) throws IOException {
|
|
||||||
output.writeInt(key.groupIndex);
|
|
||||||
output.writeInt(key.trackIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,6 @@ import com.google.android.exoplayer2.util.Assertions;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
@ -100,13 +99,13 @@ public final class HlsDownloadHelper extends DownloadHelper {
|
|||||||
@Override
|
@Override
|
||||||
public HlsDownloadAction getDownloadAction(@Nullable byte[] data, List<TrackKey> trackKeys) {
|
public HlsDownloadAction getDownloadAction(@Nullable byte[] data, List<TrackKey> trackKeys) {
|
||||||
Assertions.checkNotNull(renditionGroups);
|
Assertions.checkNotNull(renditionGroups);
|
||||||
return new HlsDownloadAction(
|
return HlsDownloadAction.createDownloadAction(
|
||||||
uri, /* isRemoveAction= */ false, data, toStreamKeys(trackKeys, renditionGroups));
|
uri, data, toStreamKeys(trackKeys, renditionGroups));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HlsDownloadAction getRemoveAction(@Nullable byte[] data) {
|
public HlsDownloadAction getRemoveAction(@Nullable byte[] data) {
|
||||||
return new HlsDownloadAction(uri, /* isRemoveAction= */ true, data, Collections.emptyList());
|
return HlsDownloadAction.createRemoveAction(uri, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Format[] toFormats(List<HlsMasterPlaylist.HlsUrl> hlsUrls) {
|
private static Format[] toFormats(List<HlsMasterPlaylist.HlsUrl> hlsUrls) {
|
||||||
|
7
library/hls/src/main/proguard-rules.txt
Normal file
7
library/hls/src/main/proguard-rules.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Proguard rules specific to the hls module.
|
||||||
|
|
||||||
|
# Constructors accessed via reflection in SegmentDownloadAction
|
||||||
|
-dontnote com.google.android.exoplayer2.source.hls.offline.HlsDownloadAction
|
||||||
|
-keepclassmembers class com.google.android.exoplayer2.source.hls.offline.HlsDownloadAction {
|
||||||
|
static ** DESERIALIZER;
|
||||||
|
}
|
@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer2.source.hls.offline;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import com.google.android.exoplayer2.offline.DownloadAction;
|
||||||
|
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||||
|
import com.google.android.exoplayer2.offline.StreamKey;
|
||||||
|
import com.google.android.exoplayer2.upstream.DummyDataSource;
|
||||||
|
import com.google.android.exoplayer2.upstream.cache.Cache;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
/** Unit tests for {@link HlsDownloadAction}. */
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class HlsDownloadActionTest {
|
||||||
|
|
||||||
|
private Uri uri1;
|
||||||
|
private Uri uri2;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
uri1 = Uri.parse("http://test1.uri");
|
||||||
|
uri2 = Uri.parse("http://test2.uri");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDownloadActionIsNotRemoveAction() {
|
||||||
|
DownloadAction action = createDownloadAction(uri1);
|
||||||
|
assertThat(action.isRemoveAction).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveActionIsRemoveAction() {
|
||||||
|
DownloadAction action2 = createRemoveAction(uri1);
|
||||||
|
assertThat(action2.isRemoveAction).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateDownloader() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
DownloadAction action = createDownloadAction(uri1);
|
||||||
|
DownloaderConstructorHelper constructorHelper =
|
||||||
|
new DownloaderConstructorHelper(Mockito.mock(Cache.class), DummyDataSource.FACTORY);
|
||||||
|
assertThat(action.createDownloader(constructorHelper)).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSameUriDifferentAction_IsSameMedia() {
|
||||||
|
DownloadAction action1 = createRemoveAction(uri1);
|
||||||
|
DownloadAction action2 = createDownloadAction(uri1);
|
||||||
|
assertThat(action1.isSameMedia(action2)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDifferentUriAndAction_IsNotSameMedia() {
|
||||||
|
DownloadAction action3 = createRemoveAction(uri2);
|
||||||
|
DownloadAction action4 = createDownloadAction(uri1);
|
||||||
|
assertThat(action3.isSameMedia(action4)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("EqualsWithItself")
|
||||||
|
@Test
|
||||||
|
public void testEquals() {
|
||||||
|
DownloadAction action1 = createRemoveAction(uri1);
|
||||||
|
assertThat(action1.equals(action1)).isTrue();
|
||||||
|
|
||||||
|
DownloadAction action2 = createRemoveAction(uri1);
|
||||||
|
DownloadAction action3 = createRemoveAction(uri1);
|
||||||
|
assertEqual(action2, action3);
|
||||||
|
|
||||||
|
DownloadAction action4 = createRemoveAction(uri1);
|
||||||
|
DownloadAction action5 = createDownloadAction(uri1);
|
||||||
|
assertNotEqual(action4, action5);
|
||||||
|
|
||||||
|
DownloadAction action6 = createDownloadAction(uri1);
|
||||||
|
DownloadAction action7 = createDownloadAction(uri1, new StreamKey(0, 0));
|
||||||
|
assertNotEqual(action6, action7);
|
||||||
|
|
||||||
|
DownloadAction action8 = createDownloadAction(uri1, new StreamKey(1, 1));
|
||||||
|
DownloadAction action9 = createDownloadAction(uri1, new StreamKey(0, 0));
|
||||||
|
assertNotEqual(action8, action9);
|
||||||
|
|
||||||
|
DownloadAction action10 = createRemoveAction(uri1);
|
||||||
|
DownloadAction action11 = createRemoveAction(uri2);
|
||||||
|
assertNotEqual(action10, action11);
|
||||||
|
|
||||||
|
DownloadAction action12 = createDownloadAction(uri1, new StreamKey(0, 0), new StreamKey(1, 1));
|
||||||
|
DownloadAction action13 = createDownloadAction(uri1, new StreamKey(1, 1), new StreamKey(0, 0));
|
||||||
|
assertEqual(action12, action13);
|
||||||
|
|
||||||
|
DownloadAction action14 = createDownloadAction(uri1, new StreamKey(0, 0));
|
||||||
|
DownloadAction action15 = createDownloadAction(uri1, new StreamKey(1, 1), new StreamKey(0, 0));
|
||||||
|
assertNotEqual(action14, action15);
|
||||||
|
|
||||||
|
DownloadAction action16 = createDownloadAction(uri1);
|
||||||
|
DownloadAction action17 = createDownloadAction(uri1);
|
||||||
|
assertEqual(action16, action17);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerializerGetType() {
|
||||||
|
DownloadAction action = createDownloadAction(uri1);
|
||||||
|
assertThat(action.type).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerializerWriteRead() throws Exception {
|
||||||
|
doTestSerializationRoundTrip(createDownloadAction(uri1));
|
||||||
|
doTestSerializationRoundTrip(createRemoveAction(uri1));
|
||||||
|
doTestSerializationRoundTrip(
|
||||||
|
createDownloadAction(uri2, new StreamKey(0, 0), new StreamKey(1, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerializerVersion0() throws Exception {
|
||||||
|
doTestSerializationV0RoundTrip(createDownloadAction(uri1));
|
||||||
|
doTestSerializationV0RoundTrip(createRemoveAction(uri1));
|
||||||
|
doTestSerializationV0RoundTrip(
|
||||||
|
createDownloadAction(uri2, new StreamKey(0, 0), new StreamKey(1, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertNotEqual(DownloadAction action1, DownloadAction action2) {
|
||||||
|
assertThat(action1).isNotEqualTo(action2);
|
||||||
|
assertThat(action2).isNotEqualTo(action1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertEqual(DownloadAction action1, DownloadAction action2) {
|
||||||
|
assertThat(action1).isEqualTo(action2);
|
||||||
|
assertThat(action2).isEqualTo(action1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void doTestSerializationRoundTrip(DownloadAction action) throws IOException {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream output = new DataOutputStream(out);
|
||||||
|
DownloadAction.serializeToStream(action, output);
|
||||||
|
|
||||||
|
assertEqual(action, deserializeActionFromStream(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void doTestSerializationV0RoundTrip(HlsDownloadAction action) throws IOException {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream output = new DataOutputStream(out);
|
||||||
|
DataOutputStream dataOutputStream = new DataOutputStream(output);
|
||||||
|
dataOutputStream.writeUTF(action.type);
|
||||||
|
dataOutputStream.writeInt(/* version */ 0);
|
||||||
|
dataOutputStream.writeUTF(action.uri.toString());
|
||||||
|
dataOutputStream.writeBoolean(action.isRemoveAction);
|
||||||
|
dataOutputStream.writeInt(action.data.length);
|
||||||
|
dataOutputStream.write(action.data);
|
||||||
|
dataOutputStream.writeInt(action.keys.size());
|
||||||
|
for (int i = 0; i < action.keys.size(); i++) {
|
||||||
|
StreamKey key = action.keys.get(i);
|
||||||
|
dataOutputStream.writeInt(key.groupIndex);
|
||||||
|
dataOutputStream.writeInt(key.trackIndex);
|
||||||
|
}
|
||||||
|
dataOutputStream.flush();
|
||||||
|
|
||||||
|
assertEqual(action, deserializeActionFromStream(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DownloadAction deserializeActionFromStream(ByteArrayOutputStream out)
|
||||||
|
throws IOException {
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
|
DataInputStream input = new DataInputStream(in);
|
||||||
|
return DownloadAction.deserializeFromStream(
|
||||||
|
new DownloadAction.Deserializer[] {HlsDownloadAction.DESERIALIZER}, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HlsDownloadAction createDownloadAction(Uri uri, StreamKey... keys) {
|
||||||
|
ArrayList<StreamKey> keysList = new ArrayList<>();
|
||||||
|
Collections.addAll(keysList, keys);
|
||||||
|
return HlsDownloadAction.createDownloadAction(uri, null, keysList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HlsDownloadAction createRemoveAction(Uri uri) {
|
||||||
|
return HlsDownloadAction.createRemoveAction(uri, null);
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,7 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion project.ext.minSdkVersion
|
minSdkVersion project.ext.minSdkVersion
|
||||||
targetSdkVersion project.ext.targetSdkVersion
|
targetSdkVersion project.ext.targetSdkVersion
|
||||||
|
consumerProguardFiles 'proguard-rules.txt'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
7
library/smoothstreaming/proguard-rules.txt
Normal file
7
library/smoothstreaming/proguard-rules.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Proguard rules specific to the smoothstreaming module.
|
||||||
|
|
||||||
|
# Constructors accessed via reflection in SegmentDownloadAction
|
||||||
|
-dontnote com.google.android.exoplayer2.source.smoothstreaming.offline.SsDownloadAction
|
||||||
|
-keepclassmembers class com.google.android.exoplayer2.source.smoothstreaming.offline.SsDownloadAction {
|
||||||
|
static ** DESERIALIZER;
|
||||||
|
}
|
@ -22,21 +22,24 @@ import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
|||||||
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
|
import com.google.android.exoplayer2.offline.SegmentDownloadAction;
|
||||||
import com.google.android.exoplayer2.offline.StreamKey;
|
import com.google.android.exoplayer2.offline.StreamKey;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
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 {
|
public final class SsDownloadAction extends SegmentDownloadAction {
|
||||||
|
|
||||||
private static final String TYPE = "ss";
|
private static final String TYPE = "ss";
|
||||||
private static final int VERSION = 0;
|
private static final int VERSION = 1;
|
||||||
|
|
||||||
public static final Deserializer DESERIALIZER =
|
public static final Deserializer DESERIALIZER =
|
||||||
new SegmentDownloadActionDeserializer(TYPE, VERSION) {
|
new SegmentDownloadActionDeserializer(TYPE, VERSION) {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected StreamKey readKey(DataInputStream input) throws IOException {
|
protected StreamKey readKey(int version, DataInputStream input) throws IOException {
|
||||||
|
if (version > 0) {
|
||||||
|
return super.readKey(version, input);
|
||||||
|
}
|
||||||
int groupIndex = input.readInt();
|
int groupIndex = input.readInt();
|
||||||
int trackIndex = input.readInt();
|
int trackIndex = input.readInt();
|
||||||
return new StreamKey(groupIndex, trackIndex);
|
return new StreamKey(groupIndex, trackIndex);
|
||||||
@ -49,27 +52,46 @@ public final class SsDownloadAction extends SegmentDownloadAction {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a SmoothStreaming download action.
|
||||||
|
*
|
||||||
|
* @param uri The URI of the media to be downloaded.
|
||||||
|
* @param data Optional custom data for this action. If {@code null} an empty array will be used.
|
||||||
|
* @param keys Keys of tracks to be downloaded. If empty, all tracks will be downloaded.
|
||||||
|
*/
|
||||||
|
public static SsDownloadAction createDownloadAction(
|
||||||
|
Uri uri, @Nullable byte[] data, List<StreamKey> keys) {
|
||||||
|
return new SsDownloadAction(uri, /* isRemoveAction= */ false, data, keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a SmoothStreaming remove action.
|
||||||
|
*
|
||||||
|
* @param uri The URI of the media to be removed.
|
||||||
|
* @param data Optional custom data for this action. If {@code null} an empty array will be used.
|
||||||
|
*/
|
||||||
|
public static SsDownloadAction createRemoveAction(Uri uri, @Nullable byte[] data) {
|
||||||
|
return new SsDownloadAction(uri, /* isRemoveAction= */ true, data, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param uri The SmoothStreaming manifest URI.
|
* @param uri The SmoothStreaming manifest URI.
|
||||||
* @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.
|
* @param data Optional custom data for this action.
|
||||||
* @param keys Keys of streams to be downloaded. If empty, all streams are downloaded. If {@code
|
* @param keys Keys of streams to be downloaded. If empty, all streams are downloaded. If {@code
|
||||||
* removeAction} is true, {@code keys} must be empty.
|
* removeAction} is true, {@code keys} must be empty.
|
||||||
|
* @deprecated Use {@link #createDownloadAction(Uri, byte[], List)} or {@link
|
||||||
|
* #createRemoveAction(Uri, byte[])}.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public SsDownloadAction(
|
public SsDownloadAction(
|
||||||
Uri uri, boolean isRemoveAction, @Nullable byte[] data, List<StreamKey> keys) {
|
Uri uri, boolean isRemoveAction, @Nullable byte[] data, List<StreamKey> keys) {
|
||||||
super(TYPE, VERSION, uri, isRemoveAction, data, keys);
|
super(TYPE, VERSION, uri, isRemoveAction, data, keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
|
public SsDownloader createDownloader(DownloaderConstructorHelper constructorHelper) {
|
||||||
return new SsDownloader(uri, keys, constructorHelper);
|
return new SsDownloader(uri, keys, constructorHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void writeKey(DataOutputStream output, StreamKey key) throws IOException {
|
|
||||||
output.writeInt(key.groupIndex);
|
|
||||||
output.writeInt(key.trackIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ import com.google.android.exoplayer2.upstream.ParsingLoadable;
|
|||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
|
||||||
@ -78,12 +77,12 @@ public final class SsDownloadHelper extends DownloadHelper {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SsDownloadAction getDownloadAction(@Nullable byte[] data, List<TrackKey> trackKeys) {
|
public SsDownloadAction getDownloadAction(@Nullable byte[] data, List<TrackKey> trackKeys) {
|
||||||
return new SsDownloadAction(uri, /* isRemoveAction= */ false, data, toStreamKeys(trackKeys));
|
return SsDownloadAction.createDownloadAction(uri, data, toStreamKeys(trackKeys));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SsDownloadAction getRemoveAction(@Nullable byte[] data) {
|
public SsDownloadAction getRemoveAction(@Nullable byte[] data) {
|
||||||
return new SsDownloadAction(uri, /* isRemoveAction= */ true, data, Collections.emptyList());
|
return SsDownloadAction.createRemoveAction(uri, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<StreamKey> toStreamKeys(List<TrackKey> trackKeys) {
|
private static List<StreamKey> toStreamKeys(List<TrackKey> trackKeys) {
|
||||||
|
7
library/smoothstreaming/src/main/proguard-rules.txt
Normal file
7
library/smoothstreaming/src/main/proguard-rules.txt
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# Proguard rules specific to the smoothstreaming module.
|
||||||
|
|
||||||
|
# Constructors accessed via reflection in SegmentDownloadAction
|
||||||
|
-dontnote com.google.android.exoplayer2.source.smoothstreaming.offline.SsDownloadAction
|
||||||
|
-keepclassmembers class com.google.android.exoplayer2.source.smoothstreaming.offline.SsDownloadAction {
|
||||||
|
static ** DESERIALIZER;
|
||||||
|
}
|
@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.google.android.exoplayer2.source.smoothstreaming.offline;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
import com.google.android.exoplayer2.offline.DownloadAction;
|
||||||
|
import com.google.android.exoplayer2.offline.DownloaderConstructorHelper;
|
||||||
|
import com.google.android.exoplayer2.offline.StreamKey;
|
||||||
|
import com.google.android.exoplayer2.upstream.DummyDataSource;
|
||||||
|
import com.google.android.exoplayer2.upstream.cache.Cache;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
|
||||||
|
/** Unit tests for {@link SsDownloadAction}. */
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class SsDownloadActionTest {
|
||||||
|
|
||||||
|
private Uri uri1;
|
||||||
|
private Uri uri2;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
uri1 = Uri.parse("http://test/1.uri");
|
||||||
|
uri2 = Uri.parse("http://test/2.uri");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDownloadActionIsNotRemoveAction() {
|
||||||
|
DownloadAction action = createDownloadAction(uri1);
|
||||||
|
assertThat(action.isRemoveAction).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveActionIsRemoveAction() {
|
||||||
|
DownloadAction action2 = createRemoveAction(uri1);
|
||||||
|
assertThat(action2.isRemoveAction).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateDownloader() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
DownloadAction action = createDownloadAction(uri1);
|
||||||
|
DownloaderConstructorHelper constructorHelper =
|
||||||
|
new DownloaderConstructorHelper(Mockito.mock(Cache.class), DummyDataSource.FACTORY);
|
||||||
|
assertThat(action.createDownloader(constructorHelper)).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSameUriDifferentAction_IsSameMedia() {
|
||||||
|
DownloadAction action1 = createRemoveAction(uri1);
|
||||||
|
DownloadAction action2 = createDownloadAction(uri1);
|
||||||
|
assertThat(action1.isSameMedia(action2)).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDifferentUriAndAction_IsNotSameMedia() {
|
||||||
|
DownloadAction action3 = createRemoveAction(uri2);
|
||||||
|
DownloadAction action4 = createDownloadAction(uri1);
|
||||||
|
assertThat(action3.isSameMedia(action4)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("EqualsWithItself")
|
||||||
|
@Test
|
||||||
|
public void testEquals() {
|
||||||
|
DownloadAction action1 = createRemoveAction(uri1);
|
||||||
|
assertThat(action1.equals(action1)).isTrue();
|
||||||
|
|
||||||
|
DownloadAction action2 = createRemoveAction(uri1);
|
||||||
|
DownloadAction action3 = createRemoveAction(uri1);
|
||||||
|
assertEqual(action2, action3);
|
||||||
|
|
||||||
|
DownloadAction action4 = createRemoveAction(uri1);
|
||||||
|
DownloadAction action5 = createDownloadAction(uri1);
|
||||||
|
assertNotEqual(action4, action5);
|
||||||
|
|
||||||
|
DownloadAction action6 = createDownloadAction(uri1);
|
||||||
|
DownloadAction action7 = createDownloadAction(uri1, new StreamKey(0, 0));
|
||||||
|
assertNotEqual(action6, action7);
|
||||||
|
|
||||||
|
DownloadAction action8 = createDownloadAction(uri1, new StreamKey(1, 1));
|
||||||
|
DownloadAction action9 = createDownloadAction(uri1, new StreamKey(0, 0));
|
||||||
|
assertNotEqual(action8, action9);
|
||||||
|
|
||||||
|
DownloadAction action10 = createRemoveAction(uri1);
|
||||||
|
DownloadAction action11 = createRemoveAction(uri2);
|
||||||
|
assertNotEqual(action10, action11);
|
||||||
|
|
||||||
|
DownloadAction action12 = createDownloadAction(uri1, new StreamKey(0, 0), new StreamKey(1, 1));
|
||||||
|
DownloadAction action13 = createDownloadAction(uri1, new StreamKey(1, 1), new StreamKey(0, 0));
|
||||||
|
assertEqual(action12, action13);
|
||||||
|
|
||||||
|
DownloadAction action14 = createDownloadAction(uri1, new StreamKey(0, 0));
|
||||||
|
DownloadAction action15 = createDownloadAction(uri1, new StreamKey(1, 1), new StreamKey(0, 0));
|
||||||
|
assertNotEqual(action14, action15);
|
||||||
|
|
||||||
|
DownloadAction action16 = createDownloadAction(uri1);
|
||||||
|
DownloadAction action17 = createDownloadAction(uri1);
|
||||||
|
assertEqual(action16, action17);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerializerGetType() {
|
||||||
|
DownloadAction action = createDownloadAction(uri1);
|
||||||
|
assertThat(action.type).isNotNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerializerWriteRead() throws Exception {
|
||||||
|
doTestSerializationRoundTrip(createDownloadAction(uri1));
|
||||||
|
doTestSerializationRoundTrip(createRemoveAction(uri1));
|
||||||
|
doTestSerializationRoundTrip(
|
||||||
|
createDownloadAction(uri2, new StreamKey(0, 0), new StreamKey(1, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerializerVersion0() throws Exception {
|
||||||
|
doTestSerializationV0RoundTrip(createDownloadAction(uri1));
|
||||||
|
doTestSerializationV0RoundTrip(createRemoveAction(uri1));
|
||||||
|
doTestSerializationV0RoundTrip(
|
||||||
|
createDownloadAction(uri2, new StreamKey(0, 0), new StreamKey(1, 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertNotEqual(DownloadAction action1, DownloadAction action2) {
|
||||||
|
assertThat(action1).isNotEqualTo(action2);
|
||||||
|
assertThat(action2).isNotEqualTo(action1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertEqual(DownloadAction action1, DownloadAction action2) {
|
||||||
|
assertThat(action1).isEqualTo(action2);
|
||||||
|
assertThat(action2).isEqualTo(action1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void doTestSerializationRoundTrip(DownloadAction action) throws IOException {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream output = new DataOutputStream(out);
|
||||||
|
DownloadAction.serializeToStream(action, output);
|
||||||
|
|
||||||
|
assertEqual(action, deserializeActionFromStream(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void doTestSerializationV0RoundTrip(SsDownloadAction action) throws IOException {
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
DataOutputStream output = new DataOutputStream(out);
|
||||||
|
DataOutputStream dataOutputStream = new DataOutputStream(output);
|
||||||
|
dataOutputStream.writeUTF(action.type);
|
||||||
|
dataOutputStream.writeInt(/* version */ 0);
|
||||||
|
dataOutputStream.writeUTF(action.uri.toString());
|
||||||
|
dataOutputStream.writeBoolean(action.isRemoveAction);
|
||||||
|
dataOutputStream.writeInt(action.data.length);
|
||||||
|
dataOutputStream.write(action.data);
|
||||||
|
dataOutputStream.writeInt(action.keys.size());
|
||||||
|
for (int i = 0; i < action.keys.size(); i++) {
|
||||||
|
StreamKey key = action.keys.get(i);
|
||||||
|
dataOutputStream.writeInt(key.groupIndex);
|
||||||
|
dataOutputStream.writeInt(key.trackIndex);
|
||||||
|
}
|
||||||
|
dataOutputStream.flush();
|
||||||
|
|
||||||
|
assertEqual(action, deserializeActionFromStream(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DownloadAction deserializeActionFromStream(ByteArrayOutputStream out)
|
||||||
|
throws IOException {
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
|
||||||
|
DataInputStream input = new DataInputStream(in);
|
||||||
|
return DownloadAction.deserializeFromStream(
|
||||||
|
new DownloadAction.Deserializer[] {SsDownloadAction.DESERIALIZER}, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SsDownloadAction createDownloadAction(Uri uri, StreamKey... keys) {
|
||||||
|
ArrayList<StreamKey> keysList = new ArrayList<>();
|
||||||
|
Collections.addAll(keysList, keys);
|
||||||
|
return SsDownloadAction.createDownloadAction(uri, null, keysList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SsDownloadAction createRemoveAction(Uri uri) {
|
||||||
|
return SsDownloadAction.createRemoveAction(uri, null);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user