Make DownloadState counters mutable

PiperOrigin-RevId: 241763220
This commit is contained in:
eguven 2019-04-03 18:52:03 +01:00 committed by Oliver Woodman
parent b10f4023f0
commit 27884c70f8
7 changed files with 83 additions and 83 deletions

View File

@ -26,6 +26,7 @@ import androidx.annotation.VisibleForTesting;
import com.google.android.exoplayer2.database.DatabaseIOException; import com.google.android.exoplayer2.database.DatabaseIOException;
import com.google.android.exoplayer2.database.DatabaseProvider; import com.google.android.exoplayer2.database.DatabaseProvider;
import com.google.android.exoplayer2.database.VersionTable; 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.Assertions;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
@ -199,9 +200,9 @@ public final class DefaultDownloadIndex implements DownloadIndex {
values.put(COLUMN_URI, downloadState.uri.toString()); values.put(COLUMN_URI, downloadState.uri.toString());
values.put(COLUMN_CACHE_KEY, downloadState.cacheKey); values.put(COLUMN_CACHE_KEY, downloadState.cacheKey);
values.put(COLUMN_STATE, downloadState.state); values.put(COLUMN_STATE, downloadState.state);
values.put(COLUMN_DOWNLOAD_PERCENTAGE, downloadState.downloadPercentage); values.put(COLUMN_DOWNLOAD_PERCENTAGE, downloadState.getDownloadPercentage());
values.put(COLUMN_DOWNLOADED_BYTES, downloadState.downloadedBytes); values.put(COLUMN_DOWNLOADED_BYTES, downloadState.getDownloadedBytes());
values.put(COLUMN_TOTAL_BYTES, downloadState.totalBytes); values.put(COLUMN_TOTAL_BYTES, downloadState.getTotalBytes());
values.put(COLUMN_FAILURE_REASON, downloadState.failureReason); values.put(COLUMN_FAILURE_REASON, downloadState.failureReason);
values.put(COLUMN_STOP_FLAGS, /*stopFlags*/ 0); values.put(COLUMN_STOP_FLAGS, /*stopFlags*/ 0);
values.put(COLUMN_NOT_MET_REQUIREMENTS, downloadState.notMetRequirements); values.put(COLUMN_NOT_MET_REQUIREMENTS, downloadState.notMetRequirements);
@ -341,22 +342,24 @@ public final class DefaultDownloadIndex implements DownloadIndex {
} }
private static DownloadState getDownloadStateForCurrentRow(Cursor cursor) { private static DownloadState getDownloadStateForCurrentRow(Cursor cursor) {
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);
return new DownloadState( return new DownloadState(
cursor.getString(COLUMN_INDEX_ID), cursor.getString(COLUMN_INDEX_ID),
cursor.getString(COLUMN_INDEX_TYPE), cursor.getString(COLUMN_INDEX_TYPE),
Uri.parse(cursor.getString(COLUMN_INDEX_URI)), Uri.parse(cursor.getString(COLUMN_INDEX_URI)),
cursor.getString(COLUMN_INDEX_CACHE_KEY), cursor.getString(COLUMN_INDEX_CACHE_KEY),
cursor.getInt(COLUMN_INDEX_STATE), cursor.getInt(COLUMN_INDEX_STATE),
cursor.getFloat(COLUMN_INDEX_DOWNLOAD_PERCENTAGE),
cursor.getLong(COLUMN_INDEX_DOWNLOADED_BYTES),
cursor.getLong(COLUMN_INDEX_TOTAL_BYTES),
cursor.getInt(COLUMN_INDEX_FAILURE_REASON), cursor.getInt(COLUMN_INDEX_FAILURE_REASON),
cursor.getInt(COLUMN_INDEX_NOT_MET_REQUIREMENTS), cursor.getInt(COLUMN_INDEX_NOT_MET_REQUIREMENTS),
cursor.getInt(COLUMN_INDEX_MANUAL_STOP_REASON), cursor.getInt(COLUMN_INDEX_MANUAL_STOP_REASON),
cursor.getLong(COLUMN_INDEX_START_TIME_MS), cursor.getLong(COLUMN_INDEX_START_TIME_MS),
cursor.getLong(COLUMN_INDEX_UPDATE_TIME_MS), cursor.getLong(COLUMN_INDEX_UPDATE_TIME_MS),
decodeStreamKeys(cursor.getString(COLUMN_INDEX_STREAM_KEYS)), decodeStreamKeys(cursor.getString(COLUMN_INDEX_STREAM_KEYS)),
cursor.getBlob(COLUMN_INDEX_CUSTOM_METADATA)); cursor.getBlob(COLUMN_INDEX_CUSTOM_METADATA),
cachingCounters);
} }
private static String encodeStreamKeys(StreamKey[] streamKeys) { private static String encodeStreamKeys(StreamKey[] streamKeys) {

View File

@ -40,6 +40,7 @@ import com.google.android.exoplayer2.database.DatabaseIOException;
import com.google.android.exoplayer2.database.DatabaseProvider; import com.google.android.exoplayer2.database.DatabaseProvider;
import com.google.android.exoplayer2.scheduler.Requirements; import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.scheduler.RequirementsWatcher; import com.google.android.exoplayer2.scheduler.RequirementsWatcher;
import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import java.io.IOException; import java.io.IOException;
@ -699,7 +700,9 @@ public final class DownloadManager {
} }
simultaneousDownloads++; simultaneousDownloads++;
} }
activeDownloads.put(download, new DownloadThread(download)); DownloadThread downloadThread = new DownloadThread(download);
activeDownloads.put(download, downloadThread);
download.setCounters(downloadThread.downloader.getCounters());
logd("Download is started", download); logd("Download is started", download);
return START_THREAD_SUCCEEDED; return START_THREAD_SUCCEEDED;
} }
@ -744,15 +747,6 @@ public final class DownloadManager {
maybeNotifyListenersIdle(); maybeNotifyListenersIdle();
} }
@Nullable
private Downloader getDownloader(Download download) {
DownloadThread downloadThread = activeDownloads.get(download);
if (downloadThread != null) {
return downloadThread.downloader;
}
return null;
}
private static final class Download { private static final class Download {
private final DownloadManager downloadManager; private final DownloadManager downloadManager;
@ -794,15 +788,6 @@ public final class DownloadManager {
} }
public DownloadState getUpdatedDownloadState() { public DownloadState getUpdatedDownloadState() {
float downloadPercentage = C.PERCENTAGE_UNSET;
long downloadedBytes = 0;
long totalBytes = C.LENGTH_UNSET;
Downloader downloader = downloadManager.getDownloader(this);
if (downloader != null) {
downloadPercentage = downloader.getDownloadPercentage();
downloadedBytes = downloader.getDownloadedBytes();
totalBytes = downloader.getTotalBytes();
}
downloadState = downloadState =
new DownloadState( new DownloadState(
downloadState.id, downloadState.id,
@ -810,16 +795,14 @@ public final class DownloadManager {
downloadState.uri, downloadState.uri,
downloadState.cacheKey, downloadState.cacheKey,
state, state,
downloadPercentage,
downloadedBytes,
totalBytes,
state != STATE_FAILED ? FAILURE_REASON_NONE : failureReason, state != STATE_FAILED ? FAILURE_REASON_NONE : failureReason,
notMetRequirements, notMetRequirements,
manualStopReason, manualStopReason,
downloadState.startTimeMs, downloadState.startTimeMs,
/* updateTimeMs= */ System.currentTimeMillis(), /* updateTimeMs= */ System.currentTimeMillis(),
downloadState.streamKeys, downloadState.streamKeys,
downloadState.customMetadata); downloadState.customMetadata,
downloadState.counters);
return downloadState; return downloadState;
} }
@ -868,6 +851,10 @@ public final class DownloadManager {
return state == STATE_REMOVING || state == STATE_RESTARTING; return state == STATE_REMOVING || state == STATE_RESTARTING;
} }
public void setCounters(CachingCounters counters) {
downloadState.setCounters(counters);
}
private void updateStopState() { private void updateStopState() {
DownloadState oldDownloadState = downloadState; DownloadState oldDownloadState = downloadState;
if (canStart()) { if (canStart()) {

View File

@ -21,6 +21,7 @@ import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.scheduler.Requirements; import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.scheduler.Requirements.RequirementFlags; import com.google.android.exoplayer2.scheduler.Requirements.RequirementFlags;
import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@ -127,12 +128,6 @@ public final class DownloadState {
@Nullable public final String cacheKey; @Nullable public final String cacheKey;
/** The state of the download. */ /** The state of the download. */
@State public final int state; @State public final int state;
/** The estimated download percentage, or {@link C#PERCENTAGE_UNSET} if unavailable. */
public final float downloadPercentage;
/** The total number of downloaded bytes. */
public final long downloadedBytes;
/** The total size of the media, or {@link C#LENGTH_UNSET} if unknown. */
public final long totalBytes;
/** The first time when download entry is created. */ /** The first time when download entry is created. */
public final long startTimeMs; public final long startTimeMs;
/** The last update time. */ /** The last update time. */
@ -151,6 +146,8 @@ public final class DownloadState {
/** The manual stop reason. */ /** The manual stop reason. */
public final int manualStopReason; public final int manualStopReason;
/*package*/ CachingCounters counters;
/** /**
* Creates a {@link DownloadState} using a {@link DownloadAction}. * Creates a {@link DownloadState} using a {@link DownloadAction}.
* *
@ -167,16 +164,14 @@ public final class DownloadState {
action.uri, action.uri,
action.customCacheKey, action.customCacheKey,
/* state= */ STATE_QUEUED, /* state= */ STATE_QUEUED,
/* downloadPercentage= */ C.PERCENTAGE_UNSET,
/* downloadedBytes= */ 0,
/* totalBytes= */ C.LENGTH_UNSET,
FAILURE_REASON_NONE, FAILURE_REASON_NONE,
/* notMetRequirements= */ 0, /* notMetRequirements= */ 0,
/* manualStopReason= */ 0, /* manualStopReason= */ 0,
/* startTimeMs= */ currentTimeMs, /* startTimeMs= */ currentTimeMs,
/* updateTimeMs= */ currentTimeMs, /* updateTimeMs= */ currentTimeMs,
action.keys.toArray(new StreamKey[0]), action.keys.toArray(new StreamKey[0]),
action.data); action.data,
new CachingCounters());
} }
/* package */ DownloadState( /* package */ DownloadState(
@ -185,16 +180,15 @@ public final class DownloadState {
Uri uri, Uri uri,
@Nullable String cacheKey, @Nullable String cacheKey,
@State int state, @State int state,
float downloadPercentage,
long downloadedBytes,
long totalBytes,
@FailureReason int failureReason, @FailureReason int failureReason,
@RequirementFlags int notMetRequirements, @RequirementFlags int notMetRequirements,
int manualStopReason, int manualStopReason,
long startTimeMs, long startTimeMs,
long updateTimeMs, long updateTimeMs,
StreamKey[] streamKeys, StreamKey[] streamKeys,
byte[] customMetadata) { byte[] customMetadata,
CachingCounters counters) {
Assertions.checkNotNull(counters);
Assertions.checkState((failureReason == FAILURE_REASON_NONE) == (state != STATE_FAILED)); Assertions.checkState((failureReason == FAILURE_REASON_NONE) == (state != STATE_FAILED));
if (manualStopReason != 0 || notMetRequirements != 0) { if (manualStopReason != 0 || notMetRequirements != 0) {
Assertions.checkState(state != STATE_DOWNLOADING && state != STATE_QUEUED); Assertions.checkState(state != STATE_DOWNLOADING && state != STATE_QUEUED);
@ -204,9 +198,6 @@ public final class DownloadState {
this.uri = uri; this.uri = uri;
this.cacheKey = cacheKey; this.cacheKey = cacheKey;
this.state = state; this.state = state;
this.downloadPercentage = downloadPercentage;
this.downloadedBytes = downloadedBytes;
this.totalBytes = totalBytes;
this.failureReason = failureReason; this.failureReason = failureReason;
this.notMetRequirements = notMetRequirements; this.notMetRequirements = notMetRequirements;
this.manualStopReason = manualStopReason; this.manualStopReason = manualStopReason;
@ -214,6 +205,7 @@ public final class DownloadState {
this.updateTimeMs = updateTimeMs; this.updateTimeMs = updateTimeMs;
this.streamKeys = streamKeys; this.streamKeys = streamKeys;
this.customMetadata = customMetadata; this.customMetadata = customMetadata;
this.counters = counters;
} }
/** /**
@ -232,16 +224,14 @@ public final class DownloadState {
action.uri, action.uri,
action.customCacheKey, action.customCacheKey,
getNextState(state, manualStopReason != 0 || notMetRequirements != 0), getNextState(state, manualStopReason != 0 || notMetRequirements != 0),
/* downloadPercentage= */ C.PERCENTAGE_UNSET,
downloadedBytes,
/* totalBytes= */ C.LENGTH_UNSET,
FAILURE_REASON_NONE, FAILURE_REASON_NONE,
notMetRequirements, notMetRequirements,
manualStopReason, manualStopReason,
startTimeMs, startTimeMs,
/* updateTimeMs= */ System.currentTimeMillis(), /* updateTimeMs= */ System.currentTimeMillis(),
mergeStreamKeys(this, action), mergeStreamKeys(this, action),
action.data); action.data,
counters);
} }
/** Returns a duplicate {@link DownloadState} in {@link #STATE_REMOVING}. */ /** Returns a duplicate {@link DownloadState} in {@link #STATE_REMOVING}. */
@ -252,16 +242,42 @@ public final class DownloadState {
uri, uri,
cacheKey, cacheKey,
STATE_REMOVING, STATE_REMOVING,
/* downloadPercentage= */ C.PERCENTAGE_UNSET,
downloadedBytes,
/* totalBytes= */ C.LENGTH_UNSET,
FAILURE_REASON_NONE, FAILURE_REASON_NONE,
notMetRequirements, notMetRequirements,
manualStopReason, manualStopReason,
startTimeMs, startTimeMs,
/* updateTimeMs= */ System.currentTimeMillis(), /* updateTimeMs= */ System.currentTimeMillis(),
streamKeys, streamKeys,
customMetadata); customMetadata,
counters);
}
/** 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;
}
/**
* 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;
} }
private static int getNextState(int currentState, boolean isStopped) { private static int getNextState(int currentState, boolean isStopped) {

View File

@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertThat;
import android.net.Uri; import android.net.Uri;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.offline.DownloadState.State; import com.google.android.exoplayer2.offline.DownloadState.State;
import com.google.android.exoplayer2.scheduler.Requirements; import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.testutil.DummyMainThread; import com.google.android.exoplayer2.testutil.DummyMainThread;
@ -631,13 +630,13 @@ public class DownloadManagerTest {
private volatile boolean interrupted; private volatile boolean interrupted;
private volatile boolean cancelled; private volatile boolean cancelled;
private volatile boolean enableDownloadIOException; private volatile boolean enableDownloadIOException;
private volatile int downloadedBytes;
private volatile int startCount; private volatile int startCount;
private CachingCounters counters;
private FakeDownloader() { private FakeDownloader() {
this.started = new CountDownLatch(1); this.started = new CountDownLatch(1);
this.blocker = new com.google.android.exoplayer2.util.ConditionVariable(); this.blocker = new com.google.android.exoplayer2.util.ConditionVariable();
downloadedBytes = C.LENGTH_UNSET; counters = new CachingCounters();
} }
@SuppressWarnings({"NonAtomicOperationOnVolatileField", "NonAtomicVolatileUpdate"}) @SuppressWarnings({"NonAtomicOperationOnVolatileField", "NonAtomicVolatileUpdate"})
@ -735,22 +734,22 @@ public class DownloadManagerTest {
@Override @Override
public long getDownloadedBytes() { public long getDownloadedBytes() {
return downloadedBytes; return counters.newlyCachedBytes;
} }
@Override @Override
public long getTotalBytes() { public long getTotalBytes() {
return C.LENGTH_UNSET; return counters.contentLength;
} }
@Override @Override
public float getDownloadPercentage() { public float getDownloadPercentage() {
return C.PERCENTAGE_UNSET; return counters.percentage;
} }
@Override @Override
public CachingCounters getCounters() { public CachingCounters getCounters() {
return null; return counters;
} }
private void assertDoesNotStart() throws InterruptedException { private void assertDoesNotStart() throws InterruptedException {
@ -760,7 +759,7 @@ public class DownloadManagerTest {
@SuppressWarnings({"NonAtomicOperationOnVolatileField", "NonAtomicVolatileUpdate"}) @SuppressWarnings({"NonAtomicOperationOnVolatileField", "NonAtomicVolatileUpdate"})
private void increaseDownloadedByteCount() { private void increaseDownloadedByteCount() {
downloadedBytes++; counters.newlyCachedBytes++;
} }
} }
} }

View File

@ -17,7 +17,7 @@ package com.google.android.exoplayer2.offline;
import android.net.Uri; import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters;
/** /**
* Builder for DownloadState. * Builder for DownloadState.
@ -27,14 +27,12 @@ import com.google.android.exoplayer2.C;
* during test initialization. * during test initialization.
*/ */
class DownloadStateBuilder { class DownloadStateBuilder {
private final CachingCounters counters;
private String id; private String id;
private String type; private String type;
private Uri uri; private Uri uri;
@Nullable private String cacheKey; @Nullable private String cacheKey;
private int state; private int state;
private float downloadPercentage;
private long downloadedBytes;
private long totalBytes;
private int failureReason; private int failureReason;
private int notMetRequirements; private int notMetRequirements;
private int manualStopReason; private int manualStopReason;
@ -69,14 +67,12 @@ class DownloadStateBuilder {
this.uri = uri; this.uri = uri;
this.cacheKey = cacheKey; this.cacheKey = cacheKey;
this.state = DownloadState.STATE_QUEUED; this.state = DownloadState.STATE_QUEUED;
this.downloadPercentage = (float) C.PERCENTAGE_UNSET;
this.downloadedBytes = (long) 0;
this.totalBytes = (long) C.LENGTH_UNSET;
this.failureReason = DownloadState.FAILURE_REASON_NONE; this.failureReason = DownloadState.FAILURE_REASON_NONE;
this.startTimeMs = (long) 0; this.startTimeMs = (long) 0;
this.updateTimeMs = (long) 0; this.updateTimeMs = (long) 0;
this.streamKeys = streamKeys; this.streamKeys = streamKeys;
this.customMetadata = customMetadata; this.customMetadata = customMetadata;
this.counters = new CachingCounters();
} }
public DownloadStateBuilder setId(String id) { public DownloadStateBuilder setId(String id) {
@ -110,17 +106,17 @@ class DownloadStateBuilder {
} }
public DownloadStateBuilder setDownloadPercentage(float downloadPercentage) { public DownloadStateBuilder setDownloadPercentage(float downloadPercentage) {
this.downloadPercentage = downloadPercentage; counters.percentage = downloadPercentage;
return this; return this;
} }
public DownloadStateBuilder setDownloadedBytes(long downloadedBytes) { public DownloadStateBuilder setDownloadedBytes(long downloadedBytes) {
this.downloadedBytes = downloadedBytes; counters.alreadyCachedBytes = downloadedBytes;
return this; return this;
} }
public DownloadStateBuilder setTotalBytes(long totalBytes) { public DownloadStateBuilder setTotalBytes(long totalBytes) {
this.totalBytes = totalBytes; counters.contentLength = totalBytes;
return this; return this;
} }
@ -166,15 +162,13 @@ class DownloadStateBuilder {
uri, uri,
cacheKey, cacheKey,
state, state,
downloadPercentage,
downloadedBytes,
totalBytes,
failureReason, failureReason,
notMetRequirements, notMetRequirements,
manualStopReason, manualStopReason,
startTimeMs, startTimeMs,
updateTimeMs, updateTimeMs,
streamKeys, streamKeys,
customMetadata); customMetadata,
counters);
} }
} }

View File

@ -270,9 +270,9 @@ public class DownloadStateTest {
static void assertEqual( static void assertEqual(
DownloadState downloadState, DownloadState that, boolean compareTimeFields) { DownloadState downloadState, DownloadState that, boolean compareTimeFields) {
assertThat(downloadState.state).isEqualTo(that.state); assertThat(downloadState.state).isEqualTo(that.state);
assertThat(downloadState.downloadPercentage).isEqualTo(that.downloadPercentage); assertThat(downloadState.getDownloadPercentage()).isEqualTo(that.getDownloadPercentage());
assertThat(downloadState.downloadedBytes).isEqualTo(that.downloadedBytes); assertThat(downloadState.getDownloadedBytes()).isEqualTo(that.getDownloadedBytes());
assertThat(downloadState.totalBytes).isEqualTo(that.totalBytes); assertThat(downloadState.getTotalBytes()).isEqualTo(that.getTotalBytes());
if (compareTimeFields) { if (compareTimeFields) {
assertThat(downloadState.startTimeMs).isEqualTo(that.startTimeMs); assertThat(downloadState.startTimeMs).isEqualTo(that.startTimeMs);
assertThat(downloadState.updateTimeMs).isEqualTo(that.updateTimeMs); assertThat(downloadState.updateTimeMs).isEqualTo(that.updateTimeMs);

View File

@ -75,11 +75,12 @@ public final class DownloadNotificationHelper {
continue; continue;
} }
haveDownloadTasks = true; haveDownloadTasks = true;
if (downloadState.downloadPercentage != C.PERCENTAGE_UNSET) { float downloadPercentage = downloadState.getDownloadPercentage();
if (downloadPercentage != C.PERCENTAGE_UNSET) {
allDownloadPercentagesUnknown = false; allDownloadPercentagesUnknown = false;
totalPercentage += downloadState.downloadPercentage; totalPercentage += downloadPercentage;
} }
haveDownloadedBytes |= downloadState.downloadedBytes > 0; haveDownloadedBytes |= downloadState.getDownloadedBytes() > 0;
downloadTaskCount++; downloadTaskCount++;
} }