Commit 54a5d691 by olly Committed by Oliver Woodman

Improve progress reporting logic

- Listener based reporting of progress allows the content length
  to be persisted into the download index (and notified via a
  download state change) as soon as it's available.
- Moved contentLength back into Download proper. It should only
  ever change once, so I'm not sure it belongs in the mutable part
  of Download.
- Made a DownloadProgress class, for naming sanity.

PiperOrigin-RevId: 244242487
parent 7d67047e
Showing with 513 additions and 394 deletions
......@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.offline;
import static com.google.android.exoplayer2.offline.Download.STATE_QUEUED;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import java.io.File;
import java.io.IOException;
......@@ -97,10 +98,11 @@ public final class ActionFileUpgradeUtil {
new Download(
request,
STATE_QUEUED,
Download.FAILURE_REASON_NONE,
Download.STOP_REASON_NONE,
/* startTimeMs= */ nowMs,
/* updateTimeMs= */ nowMs);
/* updateTimeMs= */ nowMs,
/* contentLength= */ C.LENGTH_UNSET,
Download.STOP_REASON_NONE,
Download.FAILURE_REASON_NONE);
}
downloadIndex.putDownload(download);
}
......
......@@ -27,7 +27,6 @@ import android.text.TextUtils;
import com.google.android.exoplayer2.database.DatabaseIOException;
import com.google.android.exoplayer2.database.DatabaseProvider;
import com.google.android.exoplayer2.database.VersionTable;
import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
......@@ -210,15 +209,15 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
values.put(COLUMN_CUSTOM_CACHE_KEY, download.request.customCacheKey);
values.put(COLUMN_DATA, download.request.data);
values.put(COLUMN_STATE, download.state);
values.put(COLUMN_DOWNLOAD_PERCENTAGE, download.getDownloadPercentage());
values.put(COLUMN_DOWNLOADED_BYTES, download.getDownloadedBytes());
values.put(COLUMN_TOTAL_BYTES, download.getTotalBytes());
values.put(COLUMN_START_TIME_MS, download.startTimeMs);
values.put(COLUMN_UPDATE_TIME_MS, download.updateTimeMs);
values.put(COLUMN_TOTAL_BYTES, download.contentLength);
values.put(COLUMN_STOP_REASON, download.stopReason);
values.put(COLUMN_FAILURE_REASON, download.failureReason);
values.put(COLUMN_DOWNLOAD_PERCENTAGE, download.getPercentDownloaded());
values.put(COLUMN_DOWNLOADED_BYTES, download.getBytesDownloaded());
values.put(COLUMN_STOP_FLAGS, 0);
values.put(COLUMN_NOT_MET_REQUIREMENTS, 0);
values.put(COLUMN_STOP_REASON, download.stopReason);
values.put(COLUMN_START_TIME_MS, download.startTimeMs);
values.put(COLUMN_UPDATE_TIME_MS, download.updateTimeMs);
try {
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
writableDatabase.replaceOrThrow(tableName, /* nullColumnHack= */ null, values);
......@@ -337,18 +336,18 @@ public final class DefaultDownloadIndex implements WritableDownloadIndex {
decodeStreamKeys(cursor.getString(COLUMN_INDEX_STREAM_KEYS)),
cursor.getString(COLUMN_INDEX_CUSTOM_CACHE_KEY),
cursor.getBlob(COLUMN_INDEX_DATA));
CachingCounters cachingCounters = new CachingCounters();
cachingCounters.alreadyCachedBytes = cursor.getLong(COLUMN_INDEX_DOWNLOADED_BYTES);
cachingCounters.contentLength = cursor.getLong(COLUMN_INDEX_TOTAL_BYTES);
cachingCounters.percentage = cursor.getFloat(COLUMN_INDEX_DOWNLOAD_PERCENTAGE);
DownloadProgress downloadProgress = new DownloadProgress();
downloadProgress.bytesDownloaded = cursor.getLong(COLUMN_INDEX_DOWNLOADED_BYTES);
downloadProgress.percentDownloaded = cursor.getFloat(COLUMN_INDEX_DOWNLOAD_PERCENTAGE);
return new Download(
request,
cursor.getInt(COLUMN_INDEX_STATE),
cursor.getInt(COLUMN_INDEX_FAILURE_REASON),
cursor.getInt(COLUMN_INDEX_STOP_REASON),
cursor.getLong(COLUMN_INDEX_START_TIME_MS),
cursor.getLong(COLUMN_INDEX_UPDATE_TIME_MS),
cachingCounters);
cursor.getLong(COLUMN_INDEX_TOTAL_BYTES),
cursor.getInt(COLUMN_INDEX_STOP_REASON),
cursor.getInt(COLUMN_INDEX_FAILURE_REASON),
downloadProgress);
}
private static String encodeStreamKeys(List<StreamKey> streamKeys) {
......
......@@ -17,7 +17,6 @@ package com.google.android.exoplayer2.offline;
import androidx.annotation.IntDef;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters;
import com.google.android.exoplayer2.util.Assertions;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
......@@ -96,60 +95,65 @@ public final class Download {
/** The download request. */
public final DownloadRequest request;
/** The state of the download. */
@State public final int state;
/** The first time when download entry is created. */
public final long startTimeMs;
/** The last update time. */
public final long updateTimeMs;
/** The total size of the content in bytes, or {@link C#LENGTH_UNSET} if unknown. */
public final long contentLength;
/** The reason the download is stopped, or {@link #STOP_REASON_NONE}. */
public final int stopReason;
/**
* If {@link #state} is {@link #STATE_FAILED} then this is the cause, otherwise {@link
* #FAILURE_REASON_NONE}.
*/
@FailureReason public final int failureReason;
/** The reason the download is stopped, or {@link #STOP_REASON_NONE}. */
public final int stopReason;
/* package */ CachingCounters counters;
/* package */ final DownloadProgress progress;
/* package */ Download(
public Download(
DownloadRequest request,
@State int state,
@FailureReason int failureReason,
int stopReason,
long startTimeMs,
long updateTimeMs) {
long updateTimeMs,
long contentLength,
int stopReason,
@FailureReason int failureReason) {
this(
request,
state,
failureReason,
stopReason,
startTimeMs,
updateTimeMs,
new CachingCounters());
contentLength,
stopReason,
failureReason,
new DownloadProgress());
}
/* package */ Download(
public Download(
DownloadRequest request,
@State int state,
@FailureReason int failureReason,
int stopReason,
long startTimeMs,
long updateTimeMs,
CachingCounters counters) {
Assertions.checkNotNull(counters);
long contentLength,
int stopReason,
@FailureReason int failureReason,
DownloadProgress progress) {
Assertions.checkNotNull(progress);
Assertions.checkState((failureReason == FAILURE_REASON_NONE) == (state != STATE_FAILED));
if (stopReason != 0) {
Assertions.checkState(state != STATE_DOWNLOADING && state != STATE_QUEUED);
}
this.request = request;
this.state = state;
this.failureReason = failureReason;
this.stopReason = stopReason;
this.startTimeMs = startTimeMs;
this.updateTimeMs = updateTimeMs;
this.counters = counters;
this.contentLength = contentLength;
this.stopReason = stopReason;
this.failureReason = failureReason;
this.progress = progress;
}
/** Returns whether the download is completed or failed. These are terminal states. */
......@@ -158,30 +162,15 @@ public final class Download {
}
/** Returns the total number of downloaded bytes. */
public long getDownloadedBytes() {
return counters.totalCachedBytes();
}
/** Returns the total size of the media, or {@link C#LENGTH_UNSET} if unknown. */
public long getTotalBytes() {
return counters.contentLength;
public long getBytesDownloaded() {
return progress.bytesDownloaded;
}
/**
* Returns the estimated download percentage, or {@link C#PERCENTAGE_UNSET} if no estimate is
* available.
*/
public float getDownloadPercentage() {
return counters.percentage;
}
/**
* Sets counters which are updated by a {@link Downloader}.
*
* @param counters An instance of {@link CachingCounters}.
*/
protected void setCounters(CachingCounters counters) {
Assertions.checkNotNull(counters);
this.counters = counters;
public float getPercentDownloaded() {
return progress.percentDownloaded;
}
}
/*
* Copyright (C) 2019 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.offline;
import com.google.android.exoplayer2.C;
/** Mutable {@link Download} progress. */
public class DownloadProgress {
/** The number of bytes that have been downloaded. */
public long bytesDownloaded;
/** The percentage that has been downloaded, or {@link C#PERCENTAGE_UNSET} if unknown. */
public float percentDownloaded;
}
......@@ -15,44 +15,44 @@
*/
package com.google.android.exoplayer2.offline;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters;
import java.io.IOException;
/**
* An interface for stream downloaders.
*/
/** Downloads and removes a piece of content. */
public interface Downloader {
/** Receives progress updates during download operations. */
interface ProgressListener {
/**
* Called when progress is made during a download operation.
*
* @param contentLength The length of the content in bytes, or {@link C#LENGTH_UNSET} if
* unknown.
* @param bytesDownloaded The number of bytes that have been downloaded.
* @param percentDownloaded The percentage of the content that has been downloaded, or {@link
* C#PERCENTAGE_UNSET}.
*/
void onProgress(long contentLength, long bytesDownloaded, float percentDownloaded);
}
/**
* Downloads the media.
* Downloads the content.
*
* @throws DownloadException Thrown if the media cannot be downloaded.
* @param progressListener A listener to receive progress updates, or {@code null}.
* @throws DownloadException Thrown if the content cannot be downloaded.
* @throws InterruptedException If the thread has been interrupted.
* @throws IOException Thrown when there is an io error while downloading.
*/
void download() throws InterruptedException, IOException;
void download(@Nullable ProgressListener progressListener)
throws InterruptedException, IOException;
/** Interrupts any current download operation and prevents future operations from running. */
/** Cancels the download operation and prevents future download operations from running. */
void cancel();
/** Returns the total number of downloaded bytes. */
long getDownloadedBytes();
/** Returns the total size of the media, or {@link C#LENGTH_UNSET} if unknown. */
long getTotalBytes();
/**
* Returns the estimated download percentage, or {@link C#PERCENTAGE_UNSET} if no estimate is
* available.
*/
float getDownloadPercentage();
/** Returns a {@link CachingCounters} which holds download counters. */
CachingCounters getCounters();
/**
* Removes the media.
* Removes the content.
*
* @throws InterruptedException Thrown if the thread was interrupted.
*/
......
......@@ -23,7 +23,6 @@ import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.CacheKeyFactory;
import com.google.android.exoplayer2.upstream.cache.CacheUtil;
import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters;
import com.google.android.exoplayer2.util.PriorityTaskManager;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
......@@ -40,7 +39,6 @@ public final class ProgressiveDownloader implements Downloader {
private final CacheDataSource dataSource;
private final CacheKeyFactory cacheKeyFactory;
private final PriorityTaskManager priorityTaskManager;
private final CacheUtil.CachingCounters cachingCounters;
private final AtomicBoolean isCanceled;
/**
......@@ -62,12 +60,12 @@ public final class ProgressiveDownloader implements Downloader {
this.dataSource = constructorHelper.createCacheDataSource();
this.cacheKeyFactory = constructorHelper.getCacheKeyFactory();
this.priorityTaskManager = constructorHelper.getPriorityTaskManager();
cachingCounters = new CachingCounters();
isCanceled = new AtomicBoolean();
}
@Override
public void download() throws InterruptedException, IOException {
public void download(@Nullable ProgressListener progressListener)
throws InterruptedException, IOException {
priorityTaskManager.add(C.PRIORITY_DOWNLOAD);
try {
CacheUtil.cache(
......@@ -78,7 +76,7 @@ public final class ProgressiveDownloader implements Downloader {
new byte[BUFFER_SIZE_BYTES],
priorityTaskManager,
C.PRIORITY_DOWNLOAD,
cachingCounters,
progressListener == null ? null : new ProgressForwarder(progressListener),
isCanceled,
/* enableEOFException= */ true);
} finally {
......@@ -92,27 +90,25 @@ public final class ProgressiveDownloader implements Downloader {
}
@Override
public long getDownloadedBytes() {
return cachingCounters.totalCachedBytes();
public void remove() {
CacheUtil.remove(dataSpec, cache, cacheKeyFactory);
}
@Override
public long getTotalBytes() {
return cachingCounters.contentLength;
}
private static final class ProgressForwarder implements CacheUtil.ProgressListener {
@Override
public float getDownloadPercentage() {
return cachingCounters.percentage;
}
private final ProgressListener progessListener;
@Override
public CachingCounters getCounters() {
return cachingCounters;
}
public ProgressForwarder(ProgressListener progressListener) {
this.progessListener = progressListener;
}
@Override
public void remove() {
CacheUtil.remove(dataSpec, cache, cacheKeyFactory);
@Override
public void onProgress(long contentLength, long bytesCached, long newBytesCached) {
float percentDownloaded =
contentLength == C.LENGTH_UNSET || contentLength == 0
? C.PERCENTAGE_UNSET
: ((bytesCached * 100f) / contentLength);
progessListener.onProgress(contentLength, bytesCached, percentDownloaded);
}
}
}
......@@ -76,9 +76,9 @@ public class DefaultDownloadIndexTest {
.setUri("different uri")
.setCacheKey("different cacheKey")
.setState(Download.STATE_FAILED)
.setDownloadPercentage(50)
.setDownloadedBytes(200)
.setTotalBytes(400)
.setPercentDownloaded(50)
.setBytesDownloaded(200)
.setContentLength(400)
.setFailureReason(Download.FAILURE_REASON_UNKNOWN)
.setStopReason(0x12345678)
.setStartTimeMs(10)
......@@ -300,10 +300,10 @@ public class DefaultDownloadIndexTest {
assertThat(download.state).isEqualTo(that.state);
assertThat(download.startTimeMs).isEqualTo(that.startTimeMs);
assertThat(download.updateTimeMs).isEqualTo(that.updateTimeMs);
assertThat(download.failureReason).isEqualTo(that.failureReason);
assertThat(download.contentLength).isEqualTo(that.contentLength);
assertThat(download.stopReason).isEqualTo(that.stopReason);
assertThat(download.getDownloadPercentage()).isEqualTo(that.getDownloadPercentage());
assertThat(download.getDownloadedBytes()).isEqualTo(that.getDownloadedBytes());
assertThat(download.getTotalBytes()).isEqualTo(that.getTotalBytes());
assertThat(download.failureReason).isEqualTo(that.failureReason);
assertThat(download.getPercentDownloaded()).isEqualTo(that.getPercentDownloaded());
assertThat(download.getBytesDownloaded()).isEqualTo(that.getBytesDownloaded());
}
}
......@@ -17,7 +17,7 @@ package com.google.android.exoplayer2.offline;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters;
import com.google.android.exoplayer2.C;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
......@@ -29,52 +29,61 @@ import java.util.List;
* creation for tests. Tests must avoid depending on the default values but explicitly set tested
* parameters during test initialization.
*/
class DownloadBuilder {
private final CachingCounters counters;
/* package */ final class DownloadBuilder {
private final DownloadProgress progress;
private String id;
private String type;
private Uri uri;
private List<StreamKey> streamKeys;
@Nullable private String cacheKey;
private byte[] customMetadata;
private int state;
private int failureReason;
private int stopReason;
private long startTimeMs;
private long updateTimeMs;
private List<StreamKey> streamKeys;
private byte[] customMetadata;
private long contentLength;
private int stopReason;
private int failureReason;
DownloadBuilder(String id) {
this(id, "type", Uri.parse("uri"), /* cacheKey= */ null, new byte[0], Collections.emptyList());
/* package */ DownloadBuilder(String id) {
this(
id,
"type",
Uri.parse("uri"),
/* streamKeys= */ Collections.emptyList(),
/* cacheKey= */ null,
new byte[0]);
}
DownloadBuilder(DownloadRequest request) {
/* package */ DownloadBuilder(DownloadRequest request) {
this(
request.id,
request.type,
request.uri,
request.streamKeys,
request.customCacheKey,
request.data,
request.streamKeys);
request.data);
}
DownloadBuilder(
/* package */ DownloadBuilder(
String id,
String type,
Uri uri,
List<StreamKey> streamKeys,
String cacheKey,
byte[] customMetadata,
List<StreamKey> streamKeys) {
byte[] customMetadata) {
this.id = id;
this.type = type;
this.uri = uri;
this.streamKeys = streamKeys;
this.cacheKey = cacheKey;
this.customMetadata = customMetadata;
this.state = Download.STATE_QUEUED;
this.contentLength = C.LENGTH_UNSET;
this.failureReason = Download.FAILURE_REASON_NONE;
this.startTimeMs = (long) 0;
this.updateTimeMs = (long) 0;
this.streamKeys = streamKeys;
this.customMetadata = customMetadata;
this.counters = new CachingCounters();
this.progress = new DownloadProgress();
}
public DownloadBuilder setId(String id) {
......@@ -107,18 +116,18 @@ class DownloadBuilder {
return this;
}
public DownloadBuilder setDownloadPercentage(float downloadPercentage) {
counters.percentage = downloadPercentage;
public DownloadBuilder setPercentDownloaded(float percentDownloaded) {
progress.percentDownloaded = percentDownloaded;
return this;
}
public DownloadBuilder setDownloadedBytes(long downloadedBytes) {
counters.alreadyCachedBytes = downloadedBytes;
public DownloadBuilder setBytesDownloaded(long bytesDownloaded) {
progress.bytesDownloaded = bytesDownloaded;
return this;
}
public DownloadBuilder setTotalBytes(long totalBytes) {
counters.contentLength = totalBytes;
public DownloadBuilder setContentLength(long contentLength) {
this.contentLength = contentLength;
return this;
}
......@@ -156,6 +165,13 @@ class DownloadBuilder {
DownloadRequest request =
new DownloadRequest(id, type, uri, streamKeys, cacheKey, customMetadata);
return new Download(
request, state, failureReason, stopReason, startTimeMs, updateTimeMs, counters);
request,
state,
startTimeMs,
updateTimeMs,
contentLength,
stopReason,
failureReason,
progress);
}
}
......@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.Download.State;
import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.testutil.DummyMainThread;
......@@ -27,7 +28,6 @@ import com.google.android.exoplayer2.testutil.DummyMainThread.TestRunnable;
import com.google.android.exoplayer2.testutil.RobolectricUtil;
import com.google.android.exoplayer2.testutil.TestDownloadManagerListener;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
......@@ -184,7 +184,7 @@ public class DownloadManagerTest {
int tooManyRetries = MIN_RETRY_COUNT + 10;
for (int i = 0; i < tooManyRetries; i++) {
downloader.increaseDownloadedByteCount();
downloader.incrementBytesDownloaded();
downloader.assertStarted(MAX_RETRY_DELAY).fail();
}
downloader.assertStarted(MAX_RETRY_DELAY).unblock();
......@@ -555,11 +555,11 @@ public class DownloadManagerTest {
private static void assertEqualIgnoringTimeFields(Download download, Download that) {
assertThat(download.request).isEqualTo(that.request);
assertThat(download.state).isEqualTo(that.state);
assertThat(download.contentLength).isEqualTo(that.contentLength);
assertThat(download.failureReason).isEqualTo(that.failureReason);
assertThat(download.stopReason).isEqualTo(that.stopReason);
assertThat(download.getDownloadPercentage()).isEqualTo(that.getDownloadPercentage());
assertThat(download.getDownloadedBytes()).isEqualTo(that.getDownloadedBytes());
assertThat(download.getTotalBytes()).isEqualTo(that.getTotalBytes());
assertThat(download.getPercentDownloaded()).isEqualTo(that.getPercentDownloaded());
assertThat(download.getBytesDownloaded()).isEqualTo(that.getBytesDownloaded());
}
private static DownloadRequest createDownloadRequest() {
......@@ -722,21 +722,23 @@ public class DownloadManagerTest {
private volatile boolean cancelled;
private volatile boolean enableDownloadIOException;
private volatile int startCount;
private CachingCounters counters;
private volatile int bytesDownloaded;
private FakeDownloader() {
this.started = new CountDownLatch(1);
this.blocker = new com.google.android.exoplayer2.util.ConditionVariable();
counters = new CachingCounters();
}
@SuppressWarnings({"NonAtomicOperationOnVolatileField", "NonAtomicVolatileUpdate"})
@Override
public void download() throws InterruptedException, IOException {
public void download(ProgressListener listener) throws InterruptedException, IOException {
// It's ok to update this directly as no other thread will update it.
startCount++;
started.countDown();
block();
if (bytesDownloaded > 0) {
listener.onProgress(C.LENGTH_UNSET, bytesDownloaded, C.PERCENTAGE_UNSET);
}
if (enableDownloadIOException) {
enableDownloadIOException = false;
throw new IOException();
......@@ -783,7 +785,7 @@ public class DownloadManagerTest {
return this;
}
private FakeDownloader assertStartCount(int count) throws InterruptedException {
private FakeDownloader assertStartCount(int count) {
assertThat(startCount).isEqualTo(count);
return this;
}
......@@ -823,34 +825,14 @@ public class DownloadManagerTest {
return unblock();
}
@Override
public long getDownloadedBytes() {
return counters.newlyCachedBytes;
}
@Override
public long getTotalBytes() {
return counters.contentLength;
}
@Override
public float getDownloadPercentage() {
return counters.percentage;
}
@Override
public CachingCounters getCounters() {
return counters;
}
private void assertDoesNotStart() throws InterruptedException {
Thread.sleep(ASSERT_FALSE_TIME);
assertThat(started.getCount()).isEqualTo(1);
}
@SuppressWarnings({"NonAtomicOperationOnVolatileField", "NonAtomicVolatileUpdate"})
private void increaseDownloadedByteCount() {
counters.newlyCachedBytes++;
private void incrementBytesDownloaded() {
bytesDownloaded++;
}
}
}
......@@ -343,7 +343,7 @@ public final class CacheDataSourceTest {
cache,
/* cacheKeyFactory= */ null,
upstream2,
/* counters= */ null,
/* progressListener= */ null,
/* isCanceled= */ null);
// Read the rest of the data.
......@@ -392,7 +392,7 @@ public final class CacheDataSourceTest {
cache,
/* cacheKeyFactory= */ null,
upstream2,
/* counters= */ null,
/* progressListener= */ null,
/* isCanceled= */ null);
// Read the rest of the data.
......@@ -416,7 +416,7 @@ public final class CacheDataSourceTest {
cache,
/* cacheKeyFactory= */ null,
upstream,
/* counters= */ null,
/* progressListener= */ null,
/* isCanceled= */ null);
// Create cache read-only CacheDataSource.
......@@ -452,7 +452,7 @@ public final class CacheDataSourceTest {
cache,
/* cacheKeyFactory= */ null,
upstream,
/* counters= */ null,
/* progressListener= */ null,
/* isCanceled= */ null);
// Create blocking CacheDataSource.
......
......@@ -45,7 +45,7 @@ import java.util.List;
* <p>Example usage:
*
* <pre>{@code
* SimpleCache cache = new SimpleCache(downloadFolder, new NoOpCacheEvictor());
* SimpleCache cache = new SimpleCache(downloadFolder, new NoOpCacheEvictor(), databaseProvider);
* DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory("ExoPlayer", null);
* DownloaderConstructorHelper constructorHelper =
* new DownloaderConstructorHelper(cache, factory);
......@@ -55,7 +55,7 @@ import java.util.List;
* new DashDownloader(
* manifestUrl, Collections.singletonList(new StreamKey(0, 0, 0)), constructorHelper);
* // Perform the download.
* dashDownloader.download();
* dashDownloader.download(progressListener);
* // Access downloaded data using CacheDataSource
* CacheDataSource cacheDataSource =
* new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE);
......
......@@ -62,6 +62,7 @@ public class DashDownloaderTest {
private SimpleCache cache;
private File tempFolder;
private ProgressListener progressListener;
@Before
public void setUp() throws Exception {
......@@ -69,6 +70,7 @@ public class DashDownloaderTest {
tempFolder =
Util.createTempDirectory(ApplicationProvider.getApplicationContext(), "ExoPlayerTest");
cache = new SimpleCache(tempFolder, new NoOpCacheEvictor());
progressListener = new ProgressListener();
}
@After
......@@ -77,7 +79,7 @@ public class DashDownloaderTest {
}
@Test
public void testCreateWithDefaultDownloaderFactory() throws Exception {
public void testCreateWithDefaultDownloaderFactory() {
DownloaderConstructorHelper constructorHelper =
new DownloaderConstructorHelper(Mockito.mock(Cache.class), DummyDataSource.FACTORY);
DownloaderFactory factory = new DefaultDownloaderFactory(constructorHelper);
......@@ -105,7 +107,7 @@ public class DashDownloaderTest {
.setRandomData("audio_segment_3", 6);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0));
dashDownloader.download();
dashDownloader.download(progressListener);
assertCachedData(cache, fakeDataSet);
}
......@@ -124,7 +126,7 @@ public class DashDownloaderTest {
.setRandomData("audio_segment_3", 6);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0));
dashDownloader.download();
dashDownloader.download(progressListener);
assertCachedData(cache, fakeDataSet);
}
......@@ -143,7 +145,7 @@ public class DashDownloaderTest {
DashDownloader dashDownloader =
getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0), new StreamKey(0, 1, 0));
dashDownloader.download();
dashDownloader.download(progressListener);
assertCachedData(cache, fakeDataSet);
}
......@@ -164,7 +166,7 @@ public class DashDownloaderTest {
.setRandomData("period_2_segment_3", 3);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet);
dashDownloader.download();
dashDownloader.download(progressListener);
assertCachedData(cache, fakeDataSet);
}
......@@ -186,7 +188,7 @@ public class DashDownloaderTest {
DashDownloader dashDownloader =
getDashDownloader(factory, new StreamKey(0, 0, 0), new StreamKey(0, 1, 0));
dashDownloader.download();
dashDownloader.download(progressListener);
DataSpec[] openedDataSpecs = fakeDataSource.getAndClearOpenedDataSpecs();
assertThat(openedDataSpecs.length).isEqualTo(8);
......@@ -218,7 +220,7 @@ public class DashDownloaderTest {
DashDownloader dashDownloader =
getDashDownloader(factory, new StreamKey(0, 0, 0), new StreamKey(1, 0, 0));
dashDownloader.download();
dashDownloader.download(progressListener);
DataSpec[] openedDataSpecs = fakeDataSource.getAndClearOpenedDataSpecs();
assertThat(openedDataSpecs.length).isEqualTo(8);
......@@ -248,12 +250,12 @@ public class DashDownloaderTest {
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0));
try {
dashDownloader.download();
dashDownloader.download(progressListener);
fail();
} catch (IOException e) {
// Expected.
}
dashDownloader.download();
dashDownloader.download(progressListener);
assertCachedData(cache, fakeDataSet);
}
......@@ -272,18 +274,17 @@ public class DashDownloaderTest {
.setRandomData("audio_segment_3", 6);
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0));
assertThat(dashDownloader.getDownloadedBytes()).isEqualTo(0);
try {
dashDownloader.download();
dashDownloader.download(progressListener);
fail();
} catch (IOException e) {
// Failure expected after downloading init data, segment 1 and 2 bytes in segment 2.
}
assertThat(dashDownloader.getDownloadedBytes()).isEqualTo(10 + 4 + 2);
progressListener.assertBytesDownloaded(10 + 4 + 2);
dashDownloader.download();
assertThat(dashDownloader.getDownloadedBytes()).isEqualTo(10 + 4 + 5 + 6);
dashDownloader.download(progressListener);
progressListener.assertBytesDownloaded(10 + 4 + 5 + 6);
}
@Test
......@@ -301,7 +302,7 @@ public class DashDownloaderTest {
DashDownloader dashDownloader =
getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0), new StreamKey(0, 1, 0));
dashDownloader.download();
dashDownloader.download(progressListener);
dashDownloader.remove();
assertCacheEmpty(cache);
}
......@@ -315,7 +316,7 @@ public class DashDownloaderTest {
DashDownloader dashDownloader = getDashDownloader(fakeDataSet, new StreamKey(0, 0, 0));
try {
dashDownloader.download();
dashDownloader.download(progressListener);
fail();
} catch (DownloadException e) {
// Expected.
......@@ -339,4 +340,17 @@ public class DashDownloaderTest {
return keysList;
}
private static final class ProgressListener implements Downloader.ProgressListener {
private long bytesDownloaded;
@Override
public void onProgress(long contentLength, long bytesDownloaded, float percentDownloaded) {
this.bytesDownloaded = bytesDownloaded;
}
public void assertBytesDownloaded(long bytesDownloaded) {
assertThat(this.bytesDownloaded).isEqualTo(bytesDownloaded);
}
}
}
......@@ -39,7 +39,7 @@ import java.util.List;
* <p>Example usage:
*
* <pre>{@code
* SimpleCache cache = new SimpleCache(downloadFolder, new NoOpCacheEvictor());
* SimpleCache cache = new SimpleCache(downloadFolder, new NoOpCacheEvictor(), databaseProvider);
* DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory("ExoPlayer", null);
* DownloaderConstructorHelper constructorHelper =
* new DownloaderConstructorHelper(cache, factory);
......@@ -50,7 +50,7 @@ import java.util.List;
* Collections.singletonList(new StreamKey(HlsMasterPlaylist.GROUP_INDEX_VARIANT, 0)),
* constructorHelper);
* // Perform the download.
* hlsDownloader.download();
* hlsDownloader.download(progressListener);
* // Access downloaded data using CacheDataSource
* CacheDataSource cacheDataSource =
* new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE);
......
......@@ -67,6 +67,7 @@ public class HlsDownloaderTest {
private SimpleCache cache;
private File tempFolder;
private ProgressListener progressListener;
private FakeDataSet fakeDataSet;
@Before
......@@ -74,7 +75,7 @@ public class HlsDownloaderTest {
tempFolder =
Util.createTempDirectory(ApplicationProvider.getApplicationContext(), "ExoPlayerTest");
cache = new SimpleCache(tempFolder, new NoOpCacheEvictor());
progressListener = new ProgressListener();
fakeDataSet =
new FakeDataSet()
.setData(MASTER_PLAYLIST_URI, MASTER_PLAYLIST_DATA)
......@@ -94,7 +95,7 @@ public class HlsDownloaderTest {
}
@Test
public void testCreateWithDefaultDownloaderFactory() throws Exception {
public void testCreateWithDefaultDownloaderFactory() {
DownloaderConstructorHelper constructorHelper =
new DownloaderConstructorHelper(Mockito.mock(Cache.class), DummyDataSource.FACTORY);
DownloaderFactory factory = new DefaultDownloaderFactory(constructorHelper);
......@@ -115,17 +116,16 @@ public class HlsDownloaderTest {
public void testCounterMethods() throws Exception {
HlsDownloader downloader =
getHlsDownloader(MASTER_PLAYLIST_URI, getKeys(MASTER_MEDIA_PLAYLIST_1_INDEX));
downloader.download();
downloader.download(progressListener);
assertThat(downloader.getDownloadedBytes())
.isEqualTo(MEDIA_PLAYLIST_DATA.length + 10 + 11 + 12);
progressListener.assertBytesDownloaded(MEDIA_PLAYLIST_DATA.length + 10 + 11 + 12);
}
@Test
public void testDownloadRepresentation() throws Exception {
HlsDownloader downloader =
getHlsDownloader(MASTER_PLAYLIST_URI, getKeys(MASTER_MEDIA_PLAYLIST_1_INDEX));
downloader.download();
downloader.download(progressListener);
assertCachedData(
cache,
......@@ -143,7 +143,7 @@ public class HlsDownloaderTest {
getHlsDownloader(
MASTER_PLAYLIST_URI,
getKeys(MASTER_MEDIA_PLAYLIST_1_INDEX, MASTER_MEDIA_PLAYLIST_2_INDEX));
downloader.download();
downloader.download(progressListener);
assertCachedData(cache, fakeDataSet);
}
......@@ -162,7 +162,7 @@ public class HlsDownloaderTest {
.setRandomData(MEDIA_PLAYLIST_3_DIR + "fileSequence2.ts", 15);
HlsDownloader downloader = getHlsDownloader(MASTER_PLAYLIST_URI, getKeys());
downloader.download();
downloader.download(progressListener);
assertCachedData(cache, fakeDataSet);
}
......@@ -173,7 +173,7 @@ public class HlsDownloaderTest {
getHlsDownloader(
MASTER_PLAYLIST_URI,
getKeys(MASTER_MEDIA_PLAYLIST_1_INDEX, MASTER_MEDIA_PLAYLIST_2_INDEX));
downloader.download();
downloader.download(progressListener);
downloader.remove();
assertCacheEmpty(cache);
......@@ -182,7 +182,7 @@ public class HlsDownloaderTest {
@Test
public void testDownloadMediaPlaylist() throws Exception {
HlsDownloader downloader = getHlsDownloader(MEDIA_PLAYLIST_1_URI, getKeys());
downloader.download();
downloader.download(progressListener);
assertCachedData(
cache,
......@@ -205,7 +205,7 @@ public class HlsDownloaderTest {
.setRandomData("fileSequence2.ts", 12);
HlsDownloader downloader = getHlsDownloader(ENC_MEDIA_PLAYLIST_URI, getKeys());
downloader.download();
downloader.download(progressListener);
assertCachedData(cache, fakeDataSet);
}
......@@ -222,4 +222,18 @@ public class HlsDownloaderTest {
}
return streamKeys;
}
private static final class ProgressListener implements Downloader.ProgressListener {
private long bytesDownloaded;
@Override
public void onProgress(long contentLength, long bytesDownloaded, float percentDownloaded) {
this.bytesDownloaded = bytesDownloaded;
}
public void assertBytesDownloaded(long bytesDownloaded) {
assertThat(this.bytesDownloaded).isEqualTo(bytesDownloaded);
}
}
}
......@@ -37,7 +37,7 @@ import java.util.List;
* <p>Example usage:
*
* <pre>{@code
* SimpleCache cache = new SimpleCache(downloadFolder, new NoOpCacheEvictor());
* SimpleCache cache = new SimpleCache(downloadFolder, new NoOpCacheEvictor(), databaseProvider);
* DefaultHttpDataSourceFactory factory = new DefaultHttpDataSourceFactory("ExoPlayer", null);
* DownloaderConstructorHelper constructorHelper =
* new DownloaderConstructorHelper(cache, factory);
......@@ -48,7 +48,7 @@ import java.util.List;
* Collections.singletonList(new StreamKey(0, 0)),
* constructorHelper);
* // Perform the download.
* ssDownloader.download();
* ssDownloader.download(progressListener);
* // Access downloaded data using CacheDataSource
* CacheDataSource cacheDataSource =
* new CacheDataSource(cache, factory.createDataSource(), CacheDataSource.FLAG_BLOCK_ON_CACHE);
......
......@@ -75,12 +75,12 @@ public final class DownloadNotificationHelper {
continue;
}
haveDownloadTasks = true;
float downloadPercentage = download.getDownloadPercentage();
float downloadPercentage = download.getPercentDownloaded();
if (downloadPercentage != C.PERCENTAGE_UNSET) {
allDownloadPercentagesUnknown = false;
totalPercentage += downloadPercentage;
}
haveDownloadedBytes |= download.getDownloadedBytes() > 0;
haveDownloadedBytes |= download.getBytesDownloaded() > 0;
downloadTaskCount++;
}
......
......@@ -89,7 +89,7 @@ public final class DashDownloadTest {
@Test
public void testDownload() throws Exception {
DashDownloader dashDownloader = downloadContent();
dashDownloader.download();
dashDownloader.download(/* progressListener= */ null);
testRunner
.setStreamName("test_h264_fixed_download")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment