Simplify DownloadState to contain its DownloadAction

This makes sense now that DownloadAction is only for downloading,
and not also for removal.

PiperOrigin-RevId: 242561575
This commit is contained in:
olly 2019-04-09 00:26:07 +01:00 committed by Oliver Woodman
parent 73acdcf1e2
commit 18dcad9b8d
12 changed files with 161 additions and 222 deletions

View File

@ -74,13 +74,13 @@ public class DemoDownloadService extends DownloadService {
notificationHelper.buildDownloadCompletedNotification(
R.drawable.ic_download_done,
/* contentIntent= */ null,
Util.fromUtf8Bytes(downloadState.customMetadata));
Util.fromUtf8Bytes(downloadState.action.data));
} else if (downloadState.state == DownloadState.STATE_FAILED) {
notification =
notificationHelper.buildDownloadFailedNotification(
R.drawable.ic_download_done,
/* contentIntent= */ null,
Util.fromUtf8Bytes(downloadState.customMetadata));
Util.fromUtf8Bytes(downloadState.action.data));
} else {
return;
}

View File

@ -37,7 +37,6 @@ import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@ -96,7 +95,7 @@ public class DownloadTracker implements DownloadManager.Listener {
public List<StreamKey> getOfflineStreamKeys(Uri uri) {
DownloadState downloadState = downloadStates.get(uri);
return downloadState != null && downloadState.state != DownloadState.STATE_FAILED
? Arrays.asList(downloadState.streamKeys)
? downloadState.action.streamKeys
: Collections.emptyList();
}
@ -109,7 +108,7 @@ public class DownloadTracker implements DownloadManager.Listener {
DownloadState downloadState = downloadStates.get(uri);
if (downloadState != null) {
DownloadService.startWithRemoveDownload(
context, DemoDownloadService.class, downloadState.id, /* foreground= */ false);
context, DemoDownloadService.class, downloadState.action.id, /* foreground= */ false);
} else {
if (startDownloadDialogHelper != null) {
startDownloadDialogHelper.release();
@ -124,23 +123,19 @@ public class DownloadTracker implements DownloadManager.Listener {
@Override
public void onDownloadStateChanged(DownloadManager downloadManager, DownloadState downloadState) {
boolean downloadAdded = downloadStates.put(downloadState.uri, downloadState) == null;
if (downloadAdded) {
downloadStates.put(downloadState.action.uri, downloadState);
for (Listener listener : listeners) {
listener.onDownloadsChanged();
}
}
}
@Override
public void onDownloadRemoved(DownloadManager downloadManager, DownloadState downloadState) {
boolean downloadRemoved = downloadStates.remove(downloadState.uri) != null;
if (downloadRemoved) {
downloadStates.remove(downloadState.action.uri);
for (Listener listener : listeners) {
listener.onDownloadsChanged();
}
}
}
// Internal methods
@ -148,7 +143,7 @@ public class DownloadTracker implements DownloadManager.Listener {
try (DownloadStateCursor loadedDownloadStates = downloadIndex.getDownloadStates()) {
while (loadedDownloadStates.moveToNext()) {
DownloadState downloadState = loadedDownloadStates.getDownloadState();
downloadStates.put(downloadState.uri, downloadState);
downloadStates.put(downloadState.action.uri, downloadState);
}
} catch (IOException e) {
Log.w(TAG, "Failed to query download states", e);

View File

@ -29,6 +29,8 @@ 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;
import java.util.List;
/**
* A {@link DownloadIndex} which uses SQLite to persist {@link DownloadState}s.
@ -38,8 +40,7 @@ import com.google.android.exoplayer2.util.Util;
*/
public final class DefaultDownloadIndex implements DownloadIndex {
@VisibleForTesting
/* package */ static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "Downloads";
private static final String TABLE_NAME = DatabaseProvider.TABLE_PREFIX + "Downloads";
// TODO: Support multiple instances. Probably using the underlying cache UID.
@VisibleForTesting /* package */ static final String INSTANCE_UID = "singleton";
@ -48,7 +49,9 @@ public final class DefaultDownloadIndex implements DownloadIndex {
private static final String COLUMN_ID = "id";
private static final String COLUMN_TYPE = "title";
private static final String COLUMN_URI = "subtitle";
private static final String COLUMN_CACHE_KEY = "cache_key";
private static final String COLUMN_STREAM_KEYS = "stream_keys";
private static final String COLUMN_CUSTOM_CACHE_KEY = "cache_key";
private static final String COLUMN_DATA = "custom_metadata";
private static final String COLUMN_STATE = "state";
private static final String COLUMN_DOWNLOAD_PERCENTAGE = "download_percentage";
private static final String COLUMN_DOWNLOADED_BYTES = "downloaded_bytes";
@ -58,8 +61,6 @@ public final class DefaultDownloadIndex implements DownloadIndex {
private static final String COLUMN_MANUAL_STOP_REASON = "manual_stop_reason";
private static final String COLUMN_START_TIME_MS = "start_time_ms";
private static final String COLUMN_UPDATE_TIME_MS = "update_time_ms";
private static final String COLUMN_STREAM_KEYS = "stream_keys";
private static final String COLUMN_CUSTOM_METADATA = "custom_metadata";
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
@ -68,18 +69,18 @@ public final class DefaultDownloadIndex implements DownloadIndex {
private static final int COLUMN_INDEX_ID = 0;
private static final int COLUMN_INDEX_TYPE = 1;
private static final int COLUMN_INDEX_URI = 2;
private static final int COLUMN_INDEX_CACHE_KEY = 3;
private static final int COLUMN_INDEX_STATE = 4;
private static final int COLUMN_INDEX_DOWNLOAD_PERCENTAGE = 5;
private static final int COLUMN_INDEX_DOWNLOADED_BYTES = 6;
private static final int COLUMN_INDEX_TOTAL_BYTES = 7;
private static final int COLUMN_INDEX_FAILURE_REASON = 8;
private static final int COLUMN_INDEX_NOT_MET_REQUIREMENTS = 9;
private static final int COLUMN_INDEX_MANUAL_STOP_REASON = 10;
private static final int COLUMN_INDEX_START_TIME_MS = 11;
private static final int COLUMN_INDEX_UPDATE_TIME_MS = 12;
private static final int COLUMN_INDEX_STREAM_KEYS = 13;
private static final int COLUMN_INDEX_CUSTOM_METADATA = 14;
private static final int COLUMN_INDEX_STREAM_KEYS = 3;
private static final int COLUMN_INDEX_CUSTOM_CACHE_KEY = 4;
private static final int COLUMN_INDEX_DATA = 5;
private static final int COLUMN_INDEX_STATE = 6;
private static final int COLUMN_INDEX_DOWNLOAD_PERCENTAGE = 7;
private static final int COLUMN_INDEX_DOWNLOADED_BYTES = 8;
private static final int COLUMN_INDEX_TOTAL_BYTES = 9;
private static final int COLUMN_INDEX_FAILURE_REASON = 10;
private static final int COLUMN_INDEX_NOT_MET_REQUIREMENTS = 11;
private static final int COLUMN_INDEX_MANUAL_STOP_REASON = 12;
private static final int COLUMN_INDEX_START_TIME_MS = 13;
private static final int COLUMN_INDEX_UPDATE_TIME_MS = 14;
private static final String WHERE_ID_EQUALS = COLUMN_ID + " = ?";
private static final String WHERE_STATE_TERMINAL =
@ -90,7 +91,9 @@ public final class DefaultDownloadIndex implements DownloadIndex {
COLUMN_ID,
COLUMN_TYPE,
COLUMN_URI,
COLUMN_CACHE_KEY,
COLUMN_STREAM_KEYS,
COLUMN_CUSTOM_CACHE_KEY,
COLUMN_DATA,
COLUMN_STATE,
COLUMN_DOWNLOAD_PERCENTAGE,
COLUMN_DOWNLOADED_BYTES,
@ -99,9 +102,7 @@ public final class DefaultDownloadIndex implements DownloadIndex {
COLUMN_NOT_MET_REQUIREMENTS,
COLUMN_MANUAL_STOP_REASON,
COLUMN_START_TIME_MS,
COLUMN_UPDATE_TIME_MS,
COLUMN_STREAM_KEYS,
COLUMN_CUSTOM_METADATA
COLUMN_UPDATE_TIME_MS
};
private static final String SQL_DROP_TABLE_IF_EXISTS = "DROP TABLE IF EXISTS " + TABLE_NAME;
@ -115,7 +116,7 @@ public final class DefaultDownloadIndex implements DownloadIndex {
+ " TEXT NOT NULL,"
+ COLUMN_URI
+ " TEXT NOT NULL,"
+ COLUMN_CACHE_KEY
+ COLUMN_CUSTOM_CACHE_KEY
+ " TEXT,"
+ COLUMN_STATE
+ " INTEGER NOT NULL,"
@ -139,7 +140,7 @@ public final class DefaultDownloadIndex implements DownloadIndex {
+ " INTEGER NOT NULL,"
+ COLUMN_STREAM_KEYS
+ " TEXT NOT NULL,"
+ COLUMN_CUSTOM_METADATA
+ COLUMN_DATA
+ " BLOB NOT NULL)";
private static final String TRUE = "1";
@ -168,9 +169,7 @@ public final class DefaultDownloadIndex implements DownloadIndex {
return null;
}
cursor.moveToNext();
DownloadState downloadState = getDownloadStateForCurrentRow(cursor);
Assertions.checkState(id.equals(downloadState.id));
return downloadState;
return getDownloadStateForCurrentRow(cursor);
} catch (SQLiteException e) {
throw new DatabaseIOException(e);
}
@ -192,24 +191,24 @@ public final class DefaultDownloadIndex implements DownloadIndex {
*/
public void putDownloadState(DownloadState downloadState) throws DatabaseIOException {
ensureInitialized();
try {
ContentValues values = new ContentValues();
values.put(COLUMN_ID, downloadState.id);
values.put(COLUMN_TYPE, downloadState.type);
values.put(COLUMN_URI, downloadState.uri.toString());
values.put(COLUMN_CACHE_KEY, downloadState.cacheKey);
values.put(COLUMN_ID, downloadState.action.id);
values.put(COLUMN_TYPE, downloadState.action.type);
values.put(COLUMN_URI, downloadState.action.uri.toString());
values.put(COLUMN_STREAM_KEYS, encodeStreamKeys(downloadState.action.streamKeys));
values.put(COLUMN_CUSTOM_CACHE_KEY, downloadState.action.customCacheKey);
values.put(COLUMN_DATA, downloadState.action.data);
values.put(COLUMN_STATE, downloadState.state);
values.put(COLUMN_DOWNLOAD_PERCENTAGE, downloadState.getDownloadPercentage());
values.put(COLUMN_DOWNLOADED_BYTES, downloadState.getDownloadedBytes());
values.put(COLUMN_TOTAL_BYTES, downloadState.getTotalBytes());
values.put(COLUMN_FAILURE_REASON, downloadState.failureReason);
values.put(COLUMN_STOP_FLAGS, /*stopFlags*/ 0);
values.put(COLUMN_STOP_FLAGS, 0);
values.put(COLUMN_NOT_MET_REQUIREMENTS, downloadState.notMetRequirements);
values.put(COLUMN_MANUAL_STOP_REASON, downloadState.manualStopReason);
values.put(COLUMN_START_TIME_MS, downloadState.startTimeMs);
values.put(COLUMN_UPDATE_TIME_MS, downloadState.updateTimeMs);
values.put(COLUMN_STREAM_KEYS, encodeStreamKeys(downloadState.streamKeys));
values.put(COLUMN_CUSTOM_METADATA, downloadState.customMetadata);
try {
SQLiteDatabase writableDatabase = databaseProvider.getWritableDatabase();
writableDatabase.replaceOrThrow(TABLE_NAME, /* nullColumnHack= */ null, values);
} catch (SQLiteException e) {
@ -341,29 +340,33 @@ public final class DefaultDownloadIndex implements DownloadIndex {
}
private static DownloadState getDownloadStateForCurrentRow(Cursor cursor) {
DownloadAction action =
DownloadAction.createDownloadAction(
cursor.getString(COLUMN_INDEX_ID),
cursor.getString(COLUMN_INDEX_TYPE),
Uri.parse(cursor.getString(COLUMN_INDEX_URI)),
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);
return new DownloadState(
cursor.getString(COLUMN_INDEX_ID),
cursor.getString(COLUMN_INDEX_TYPE),
Uri.parse(cursor.getString(COLUMN_INDEX_URI)),
cursor.getString(COLUMN_INDEX_CACHE_KEY),
action,
cursor.getInt(COLUMN_INDEX_STATE),
cursor.getInt(COLUMN_INDEX_FAILURE_REASON),
cursor.getInt(COLUMN_INDEX_NOT_MET_REQUIREMENTS),
cursor.getInt(COLUMN_INDEX_MANUAL_STOP_REASON),
cursor.getLong(COLUMN_INDEX_START_TIME_MS),
cursor.getLong(COLUMN_INDEX_UPDATE_TIME_MS),
decodeStreamKeys(cursor.getString(COLUMN_INDEX_STREAM_KEYS)),
cursor.getBlob(COLUMN_INDEX_CUSTOM_METADATA),
cachingCounters);
}
private static String encodeStreamKeys(StreamKey[] streamKeys) {
private static String encodeStreamKeys(List<StreamKey> streamKeys) {
StringBuilder stringBuilder = new StringBuilder();
for (StreamKey streamKey : streamKeys) {
for (int i = 0; i < streamKeys.size(); i++) {
StreamKey streamKey = streamKeys.get(i);
stringBuilder
.append(streamKey.periodIndex)
.append('.')
@ -378,21 +381,20 @@ public final class DefaultDownloadIndex implements DownloadIndex {
return stringBuilder.toString();
}
private static StreamKey[] decodeStreamKeys(String encodedStreamKeys) {
private static List<StreamKey> decodeStreamKeys(String encodedStreamKeys) {
ArrayList<StreamKey> streamKeys = new ArrayList<>();
if (encodedStreamKeys.isEmpty()) {
return new StreamKey[0];
return streamKeys;
}
String[] streamKeysStrings = Util.split(encodedStreamKeys, ",");
int streamKeysCount = streamKeysStrings.length;
StreamKey[] streamKeys = new StreamKey[streamKeysCount];
for (int i = 0; i < streamKeysCount; i++) {
String[] indices = Util.split(streamKeysStrings[i], "\\.");
for (String streamKeysString : streamKeysStrings) {
String[] indices = Util.split(streamKeysString, "\\.");
Assertions.checkState(indices.length == 3);
streamKeys[i] =
streamKeys.add(
new StreamKey(
Integer.parseInt(indices[0]),
Integer.parseInt(indices[1]),
Integer.parseInt(indices[2]));
Integer.parseInt(indices[2])));
}
return streamKeys;
}

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.offline;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@ -133,6 +134,33 @@ public final class DownloadAction {
this.data = data != null ? Arrays.copyOf(data, data.length) : Util.EMPTY_BYTE_ARRAY;
}
/**
* Returns the result of merging {@code newAction} into this action.
*
* @param newAction The new action.
* @return The merged result.
*/
public DownloadAction copyWithMergedAction(DownloadAction newAction) {
Assertions.checkState(id.equals(newAction.id));
Assertions.checkState(type.equals(newAction.type));
List<StreamKey> mergedKeys;
if (streamKeys.isEmpty() || newAction.streamKeys.isEmpty()) {
// If either streamKeys is empty then all streams should be downloaded.
mergedKeys = Collections.emptyList();
} else {
mergedKeys = new ArrayList<>(streamKeys);
for (int i = 0; i < newAction.streamKeys.size(); i++) {
StreamKey newKey = newAction.streamKeys.get(i);
if (!mergedKeys.contains(newKey)) {
mergedKeys.add(newKey);
}
}
}
return new DownloadAction(
id, type, newAction.uri, mergedKeys, newAction.customCacheKey, newAction.data);
}
/** Serializes itself into a byte array. */
public byte[] toByteArray() {
ByteArrayOutputStream output = new ByteArrayOutputStream();

View File

@ -76,7 +76,7 @@ public final class DownloadIndexUtil {
throws IOException {
DownloadState downloadState = downloadIndex.getDownloadState(id != null ? id : action.id);
if (downloadState != null) {
downloadState = downloadState.mergeAction(action);
downloadState = downloadState.copyWithMergedAction(action);
} else {
downloadState = new DownloadState(action);
}

View File

@ -47,7 +47,6 @@ import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;
@ -504,7 +503,7 @@ public final class DownloadManager {
}
private void onDownloadStateChanged(DownloadState downloadState) {
int downloadStateIndex = getDownloadStateIndex(downloadState.id);
int downloadStateIndex = getDownloadStateIndex(downloadState.action.id);
if (downloadState.state == STATE_COMPLETED || downloadState.state == STATE_FAILED) {
if (downloadStateIndex != C.INDEX_UNSET) {
downloadStates.remove(downloadStateIndex);
@ -520,7 +519,7 @@ public final class DownloadManager {
}
private void onDownloadRemoved(DownloadState downloadState) {
downloadStates.remove(getDownloadStateIndex(downloadState.id));
downloadStates.remove(getDownloadStateIndex(downloadState.action.id));
for (Listener listener : listeners) {
listener.onDownloadRemoved(this, downloadState);
}
@ -538,7 +537,7 @@ public final class DownloadManager {
private int getDownloadStateIndex(String id) {
for (int i = 0; i < downloadStates.size(); i++) {
if (downloadStates.get(i).id.equals(id)) {
if (downloadStates.get(i).action.id.equals(id)) {
return i;
}
}
@ -624,7 +623,7 @@ public final class DownloadManager {
downloadState = new DownloadState(action);
logd("Download state is created for " + action.id);
} else {
downloadState = downloadState.mergeAction(action);
downloadState = downloadState.copyWithMergedAction(action);
logd("Download state is loaded for " + action.id);
}
addDownloadForState(downloadState);
@ -638,7 +637,7 @@ public final class DownloadManager {
} else {
DownloadState downloadState = loadDownloadState(id);
if (downloadState != null) {
addDownloadForState(downloadState.setRemoveState());
addDownloadForState(downloadState.copyWithState(STATE_REMOVING));
} else {
logd("Can't remove download. No download with id: " + id);
}
@ -661,7 +660,7 @@ public final class DownloadManager {
private void onDownloadRemovedInternal(Download download, DownloadState downloadState) {
logd("Download is removed", download);
try {
downloadIndex.removeDownloadState(downloadState.id);
downloadIndex.removeDownloadState(downloadState.action.id);
} catch (DatabaseIOException e) {
Log.e(TAG, "Failed to remove from index", e);
}
@ -837,11 +836,11 @@ public final class DownloadManager {
}
public String getId() {
return downloadState.id;
return downloadState.action.id;
}
public void addAction(DownloadAction newAction) {
downloadState = downloadState.mergeAction(newAction);
downloadState = downloadState.copyWithMergedAction(newAction);
initialize();
}
@ -852,18 +851,13 @@ public final class DownloadManager {
public DownloadState getUpdatedDownloadState() {
downloadState =
new DownloadState(
downloadState.id,
downloadState.type,
downloadState.uri,
downloadState.cacheKey,
downloadState.action,
state,
state != STATE_FAILED ? FAILURE_REASON_NONE : failureReason,
notMetRequirements,
manualStopReason,
downloadState.startTimeMs,
/* updateTimeMs= */ System.currentTimeMillis(),
downloadState.streamKeys,
downloadState.customMetadata,
downloadState.counters);
return downloadState;
}
@ -895,16 +889,6 @@ public final class DownloadManager {
updateStopState();
}
public DownloadAction getAction() {
return DownloadAction.createDownloadAction(
downloadState.id,
downloadState.type,
downloadState.uri,
Arrays.asList(downloadState.streamKeys),
downloadState.cacheKey,
downloadState.customMetadata);
}
public boolean isInRemoveState() {
return state == STATE_REMOVING || state == STATE_RESTARTING;
}
@ -980,7 +964,7 @@ public final class DownloadManager {
initialize(STATE_QUEUED);
} else { // STATE_DOWNLOADING
if (error != null) {
Log.e(TAG, "Download failed: " + downloadState.id, error);
Log.e(TAG, "Download failed: " + downloadState.action.id, error);
failureReason = FAILURE_REASON_UNKNOWN;
setState(STATE_FAILED);
} else {
@ -1001,7 +985,7 @@ public final class DownloadManager {
private DownloadThread(Download download) {
this.download = download;
this.downloader = downloaderFactory.createDownloader(download.getAction());
this.downloader = downloaderFactory.createDownloader(download.downloadState.action);
this.isRemoveThread = download.isInRemoveState();
start();
}

View File

@ -15,9 +15,7 @@
*/
package com.google.android.exoplayer2.offline;
import android.net.Uri;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.scheduler.Requirements.RequirementFlags;
@ -26,8 +24,6 @@ import com.google.android.exoplayer2.util.Assertions;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collections;
import java.util.HashSet;
/** Represents state of a download. */
public final class DownloadState {
@ -114,24 +110,15 @@ public final class DownloadState {
}
}
/** The unique content id. */
public final String id;
/** The type of the content. */
public final String type;
/** The Uri of the content. */
public final Uri uri;
/** A custom key for cache indexing. */
@Nullable public final String cacheKey;
/** The download action. */
public final DownloadAction action;
/** 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;
/** Keys of streams to be downloaded. If empty, all streams will be downloaded. */
public final StreamKey[] streamKeys;
/** Optional custom data. */
public final byte[] customMetadata;
/**
* If {@link #state} is {@link #STATE_FAILED} then this is the cause, otherwise {@link
* #FAILURE_REASON_NONE}.
@ -155,52 +142,37 @@ public final class DownloadState {
private DownloadState(DownloadAction action, long currentTimeMs) {
this(
action.id,
action.type,
action.uri,
action.customCacheKey,
action,
/* state= */ STATE_QUEUED,
FAILURE_REASON_NONE,
/* notMetRequirements= */ 0,
/* manualStopReason= */ 0,
/* startTimeMs= */ currentTimeMs,
/* updateTimeMs= */ currentTimeMs,
action.streamKeys.toArray(new StreamKey[0]),
action.data,
new CachingCounters());
}
/* package */ DownloadState(
String id,
String type,
Uri uri,
@Nullable String cacheKey,
DownloadAction action,
@State int state,
@FailureReason int failureReason,
@RequirementFlags int notMetRequirements,
int manualStopReason,
long startTimeMs,
long updateTimeMs,
StreamKey[] streamKeys,
byte[] customMetadata,
CachingCounters counters) {
Assertions.checkNotNull(counters);
Assertions.checkState((failureReason == FAILURE_REASON_NONE) == (state != STATE_FAILED));
if (manualStopReason != 0 || notMetRequirements != 0) {
Assertions.checkState(state != STATE_DOWNLOADING && state != STATE_QUEUED);
}
this.id = id;
this.type = type;
this.uri = uri;
this.cacheKey = cacheKey;
this.action = action;
this.state = state;
this.failureReason = failureReason;
this.notMetRequirements = notMetRequirements;
this.manualStopReason = manualStopReason;
this.startTimeMs = startTimeMs;
this.updateTimeMs = updateTimeMs;
this.streamKeys = streamKeys;
this.customMetadata = customMetadata;
this.counters = counters;
}
@ -208,43 +180,35 @@ public final class DownloadState {
* Merges the given {@link DownloadAction} and creates a new {@link DownloadState}. The action
* must have the same id and type.
*
* @param action The {@link DownloadAction} to be merged.
* @param newAction The {@link DownloadAction} to be merged.
* @return A new {@link DownloadState}.
*/
public DownloadState mergeAction(DownloadAction action) {
Assertions.checkArgument(action.id.equals(id));
Assertions.checkArgument(action.type.equals(type));
public DownloadState copyWithMergedAction(DownloadAction newAction) {
return new DownloadState(
id,
type,
action.uri,
action.customCacheKey,
action.copyWithMergedAction(newAction),
getNextState(state, manualStopReason != 0 || notMetRequirements != 0),
FAILURE_REASON_NONE,
notMetRequirements,
manualStopReason,
startTimeMs,
/* updateTimeMs= */ System.currentTimeMillis(),
mergeStreamKeys(this, action),
action.data,
counters);
}
/** Returns a duplicate {@link DownloadState} in {@link #STATE_REMOVING}. */
public DownloadState setRemoveState() {
/**
* Returns a copy with the specified state, clearing {@link #failureReason}.
*
* @param state The {@link State}.
*/
public DownloadState copyWithState(@State int state) {
return new DownloadState(
id,
type,
uri,
cacheKey,
STATE_REMOVING,
action,
state,
FAILURE_REASON_NONE,
notMetRequirements,
manualStopReason,
startTimeMs,
/* updateTimeMs= */ System.currentTimeMillis(),
streamKeys,
customMetadata,
counters);
}
@ -285,18 +249,4 @@ public final class DownloadState {
return STATE_QUEUED;
}
}
private static StreamKey[] mergeStreamKeys(DownloadState downloadState, DownloadAction action) {
StreamKey[] streamKeys = downloadState.streamKeys;
if (streamKeys.length > 0) {
if (action.streamKeys.isEmpty()) {
streamKeys = new StreamKey[0];
} else {
HashSet<StreamKey> keys = new HashSet<>(action.streamKeys);
Collections.addAll(keys, downloadState.streamKeys);
streamKeys = keys.toArray(new StreamKey[0]);
}
}
return streamKeys;
}
}

View File

@ -102,11 +102,11 @@ public class DownloadIndexUtilTest {
DownloadState downloadState = downloadIndex.getDownloadState(action2.id);
assertThat(downloadState).isNotNull();
assertThat(downloadState.type).isEqualTo(action2.type);
assertThat(downloadState.cacheKey).isEqualTo(action2.customCacheKey);
assertThat(downloadState.customMetadata).isEqualTo(action2.data);
assertThat(downloadState.uri).isEqualTo(action2.uri);
assertThat(Arrays.asList(downloadState.streamKeys)).containsExactly(streamKey1, streamKey2);
assertThat(downloadState.action.type).isEqualTo(action2.type);
assertThat(downloadState.action.customCacheKey).isEqualTo(action2.customCacheKey);
assertThat(downloadState.action.data).isEqualTo(action2.data);
assertThat(downloadState.action.uri).isEqualTo(action2.uri);
assertThat(downloadState.action.streamKeys).containsExactly(streamKey1, streamKey2);
assertThat(downloadState.state).isEqualTo(DownloadState.STATE_QUEUED);
}
@ -151,12 +151,7 @@ public class DownloadIndexUtilTest {
private void assertDownloadIndexContainsAction(DownloadAction action, int state)
throws IOException {
DownloadState downloadState = downloadIndex.getDownloadState(action.id);
assertThat(downloadState.type).isEqualTo(action.type);
assertThat(downloadState.cacheKey).isEqualTo(action.customCacheKey);
assertThat(downloadState.customMetadata).isEqualTo(action.data);
assertThat(downloadState.uri).isEqualTo(action.uri);
assertThat(Arrays.asList(downloadState.streamKeys))
.containsExactlyElementsIn(action.streamKeys);
assertThat(downloadState.action).isEqualTo(action);
assertThat(downloadState.state).isEqualTo(state);
}

View File

@ -347,7 +347,7 @@ public class DownloadManagerTest {
assertThat(states).hasLength(3);
String[] taskIds = {task1.taskId, task2.taskId, task3.taskId};
String[] stateTaskIds = {states[0].id, states[1].id, states[2].id};
String[] stateTaskIds = {states[0].action.id, states[1].action.id, states[2].action.id};
assertThat(stateTaskIds).isEqualTo(taskIds);
}

View File

@ -18,6 +18,9 @@ package com.google.android.exoplayer2.offline;
import android.net.Uri;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* Builder for DownloadState.
@ -38,21 +41,15 @@ class DownloadStateBuilder {
private int manualStopReason;
private long startTimeMs;
private long updateTimeMs;
private StreamKey[] streamKeys;
private List<StreamKey> streamKeys;
private byte[] customMetadata;
DownloadStateBuilder(String id) {
this(id, "type", Uri.parse("uri"), /* cacheKey= */ null, new byte[0], new StreamKey[0]);
this(id, "type", Uri.parse("uri"), /* cacheKey= */ null, new byte[0], Collections.emptyList());
}
DownloadStateBuilder(DownloadAction action) {
this(
action.id,
action.type,
action.uri,
action.customCacheKey,
action.data,
action.streamKeys.toArray(new StreamKey[0]));
this(action.id, action.type, action.uri, action.customCacheKey, action.data, action.streamKeys);
}
DownloadStateBuilder(
@ -61,7 +58,7 @@ class DownloadStateBuilder {
Uri uri,
String cacheKey,
byte[] customMetadata,
StreamKey[] streamKeys) {
List<StreamKey> streamKeys) {
this.id = id;
this.type = type;
this.uri = uri;
@ -146,7 +143,7 @@ class DownloadStateBuilder {
}
public DownloadStateBuilder setStreamKeys(StreamKey... streamKeys) {
this.streamKeys = streamKeys;
this.streamKeys = Arrays.asList(streamKeys);
return this;
}
@ -156,19 +153,16 @@ class DownloadStateBuilder {
}
public DownloadState build() {
DownloadAction action =
DownloadAction.createDownloadAction(id, type, uri, streamKeys, cacheKey, customMetadata);
return new DownloadState(
id,
type,
uri,
cacheKey,
action,
state,
failureReason,
notMetRequirements,
manualStopReason,
startTimeMs,
updateTimeMs,
streamKeys,
customMetadata,
counters);
}
}

View File

@ -47,7 +47,7 @@ public class DownloadStateTest {
.build();
try {
downloadState.mergeAction(downloadAction);
downloadState.copyWithMergedAction(downloadAction);
fail();
} catch (Exception e) {
// Expected.
@ -64,7 +64,7 @@ public class DownloadStateTest {
.build();
try {
downloadState.mergeAction(downloadAction);
downloadState.copyWithMergedAction(downloadAction);
fail();
} catch (Exception e) {
// Expected.
@ -78,7 +78,7 @@ public class DownloadStateTest {
new DownloadStateBuilder(downloadAction).setState(DownloadState.STATE_QUEUED);
DownloadState downloadState = downloadStateBuilder.build();
downloadState.mergeAction(downloadAction);
downloadState.copyWithMergedAction(downloadAction);
}
@Test
@ -90,7 +90,7 @@ public class DownloadStateTest {
.setState(DownloadState.STATE_QUEUED);
DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.mergeAction(downloadAction);
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction);
DownloadState expectedDownloadState = downloadStateBuilder.setUri(downloadAction.uri).build();
assertEqual(mergedDownloadState, expectedDownloadState);
@ -112,7 +112,7 @@ public class DownloadStateTest {
.setCustomMetadata(new byte[0]);
DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.mergeAction(downloadAction);
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction);
DownloadState expectedDownloadState =
downloadStateBuilder.setCustomMetadata(downloadAction.data).build();
@ -126,7 +126,7 @@ public class DownloadStateTest {
new DownloadStateBuilder(downloadAction).setState(DownloadState.STATE_REMOVING);
DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.mergeAction(downloadAction);
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction);
DownloadState expectedDownloadState =
downloadStateBuilder.setState(DownloadState.STATE_RESTARTING).build();
@ -142,7 +142,7 @@ public class DownloadStateTest {
.setFailureReason(DownloadState.FAILURE_REASON_UNKNOWN);
DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.mergeAction(downloadAction);
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction);
DownloadState expectedDownloadState =
downloadStateBuilder
@ -161,7 +161,7 @@ public class DownloadStateTest {
.setManualStopReason(DownloadState.MANUAL_STOP_REASON_UNDEFINED);
DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.mergeAction(downloadAction);
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction);
assertEqual(mergedDownloadState, downloadState);
}
@ -175,7 +175,7 @@ public class DownloadStateTest {
.setManualStopReason(DownloadState.MANUAL_STOP_REASON_UNDEFINED);
DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.mergeAction(downloadAction);
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction);
DownloadState expectedDownloadState =
downloadStateBuilder.setState(DownloadState.STATE_STOPPED).build();
@ -191,7 +191,7 @@ public class DownloadStateTest {
.setNotMetRequirements(0x12345678);
DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.mergeAction(downloadAction);
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction);
DownloadState expectedDownloadState =
downloadStateBuilder.setState(DownloadState.STATE_STOPPED).build();
@ -259,7 +259,7 @@ public class DownloadStateTest {
.setStreamKeys(keys1);
DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.mergeAction(downloadAction);
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction);
DownloadState expectedDownloadState = downloadStateBuilder.setStreamKeys(expectedKeys).build();
assertEqual(mergedDownloadState, expectedDownloadState);
@ -271,6 +271,7 @@ public class DownloadStateTest {
static void assertEqual(
DownloadState downloadState, DownloadState that, boolean compareTimeFields) {
assertThat(downloadState.action).isEqualTo(that.action);
assertThat(downloadState.state).isEqualTo(that.state);
assertThat(downloadState.getDownloadPercentage()).isEqualTo(that.getDownloadPercentage());
assertThat(downloadState.getDownloadedBytes()).isEqualTo(that.getDownloadedBytes());
@ -282,12 +283,6 @@ public class DownloadStateTest {
assertThat(downloadState.failureReason).isEqualTo(that.failureReason);
assertThat(downloadState.manualStopReason).isEqualTo(that.manualStopReason);
assertThat(downloadState.notMetRequirements).isEqualTo(that.notMetRequirements);
assertThat(downloadState.id).isEqualTo(that.id);
assertThat(downloadState.type).isEqualTo(that.type);
assertThat(downloadState.uri).isEqualTo(that.uri);
assertThat(downloadState.cacheKey).isEqualTo(that.cacheKey);
assertThat(Arrays.asList(downloadState.streamKeys)).containsExactlyElementsIn(that.streamKeys);
assertThat(downloadState.customMetadata).isEqualTo(that.customMetadata);
}
private DownloadAction createDownloadAction() {

View File

@ -57,10 +57,6 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
return getStateQueue(taskId).poll(timeoutMs, TimeUnit.MILLISECONDS);
}
public void clearDownloadError() {
this.failureReason = DownloadState.FAILURE_REASON_NONE;
}
@Override
public void onInitialized(DownloadManager downloadManager) {
initializedCondition.open();
@ -77,12 +73,12 @@ public final class TestDownloadManagerListener implements DownloadManager.Listen
if (downloadState.state == DownloadState.STATE_FAILED) {
failureReason = downloadState.failureReason;
}
getStateQueue(downloadState.id).add(downloadState.state);
getStateQueue(downloadState.action.id).add(downloadState.state);
}
@Override
public void onDownloadRemoved(DownloadManager downloadManager, DownloadState downloadState) {
getStateQueue(downloadState.id).add(STATE_REMOVED);
getStateQueue(downloadState.action.id).add(STATE_REMOVED);
}
@Override