Use DownloadState in DownloadManager
PiperOrigin-RevId: 233587184
This commit is contained in:
parent
399a963e02
commit
5782bbc6e5
@ -172,11 +172,6 @@ public final class DownloadAction {
|
||||
return output.toByteArray();
|
||||
}
|
||||
|
||||
/** Returns whether this is an action for the same media as the {@code other}. */
|
||||
public boolean isSameMedia(DownloadAction other) {
|
||||
return id.equals(other.id);
|
||||
}
|
||||
|
||||
/** Returns keys of streams to be downloaded. */
|
||||
public List<StreamKey> getKeys() {
|
||||
return keys;
|
||||
|
@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.offline;
|
||||
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
/** {@link DownloadAction} related utility methods. */
|
||||
public class DownloadActionUtil {
|
||||
|
||||
private DownloadActionUtil() {}
|
||||
|
||||
/**
|
||||
* Merge {@link DownloadAction}s in {@code actionQueue} to minimum number of actions.
|
||||
*
|
||||
* <p>All actions must have the same type and must be for the same media.
|
||||
*
|
||||
* @param actionQueue Queue of actions. Must not be empty.
|
||||
* @return The first action in the queue.
|
||||
*/
|
||||
public static DownloadAction mergeActions(ArrayDeque<DownloadAction> actionQueue) {
|
||||
DownloadAction removeAction = null;
|
||||
DownloadAction downloadAction = null;
|
||||
HashSet<StreamKey> keys = new HashSet<>();
|
||||
boolean downloadAllTracks = false;
|
||||
DownloadAction firstAction = Assertions.checkNotNull(actionQueue.peek());
|
||||
|
||||
while (!actionQueue.isEmpty()) {
|
||||
DownloadAction action = actionQueue.remove();
|
||||
Assertions.checkState(action.type.equals(firstAction.type));
|
||||
Assertions.checkState(action.isSameMedia(firstAction));
|
||||
if (action.isRemoveAction) {
|
||||
removeAction = action;
|
||||
downloadAction = null;
|
||||
keys.clear();
|
||||
downloadAllTracks = false;
|
||||
} else {
|
||||
if (!downloadAllTracks) {
|
||||
if (action.keys.isEmpty()) {
|
||||
downloadAllTracks = true;
|
||||
keys.clear();
|
||||
} else {
|
||||
keys.addAll(action.keys);
|
||||
}
|
||||
}
|
||||
downloadAction = action;
|
||||
}
|
||||
}
|
||||
|
||||
if (removeAction != null) {
|
||||
actionQueue.add(removeAction);
|
||||
}
|
||||
if (downloadAction != null) {
|
||||
actionQueue.add(
|
||||
DownloadAction.createDownloadAction(
|
||||
downloadAction.type,
|
||||
downloadAction.uri,
|
||||
new ArrayList<>(keys),
|
||||
downloadAction.customCacheKey,
|
||||
downloadAction.data));
|
||||
}
|
||||
return Assertions.checkNotNull(actionQueue.peek());
|
||||
}
|
||||
}
|
@ -46,7 +46,9 @@ import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
@ -307,7 +309,7 @@ public final class DownloadManager {
|
||||
Assertions.checkState(!released);
|
||||
for (int i = 0; i < downloads.size(); i++) {
|
||||
Download download = downloads.get(i);
|
||||
if (download.id.equals(id)) {
|
||||
if (download.getId().equals(id)) {
|
||||
return download.getDownloadState();
|
||||
}
|
||||
}
|
||||
@ -384,19 +386,15 @@ public final class DownloadManager {
|
||||
if (released) {
|
||||
return;
|
||||
}
|
||||
notifyListenersDownloadStateChange(download);
|
||||
if (download.isFinished()) {
|
||||
downloads.remove(download);
|
||||
saveActions();
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListenersDownloadStateChange(Download download) {
|
||||
logd("Download state is changed", download);
|
||||
DownloadState downloadState = download.getDownloadState();
|
||||
for (Listener listener : listeners) {
|
||||
listener.onDownloadStateChanged(this, downloadState);
|
||||
}
|
||||
if (download.isFinished()) {
|
||||
downloads.remove(download);
|
||||
saveActions();
|
||||
}
|
||||
}
|
||||
|
||||
private void onRequirementsStateChanged(@Requirements.RequirementFlags int notMetRequirements) {
|
||||
@ -464,7 +462,7 @@ public final class DownloadManager {
|
||||
}
|
||||
ArrayList<DownloadAction> actions = new ArrayList<>(downloads.size());
|
||||
for (int i = 0; i < downloads.size(); i++) {
|
||||
actions.addAll(downloads.get(i).actionQueue);
|
||||
downloads.get(i).addActions(actions);
|
||||
}
|
||||
final DownloadAction[] actionsArray = actions.toArray(new DownloadAction[0]);
|
||||
fileIOHandler.post(
|
||||
@ -551,6 +549,9 @@ public final class DownloadManager {
|
||||
}
|
||||
|
||||
private void onDownloadThreadStopped(DownloadThread downloadThread, Throwable finalError) {
|
||||
if (released) {
|
||||
return;
|
||||
}
|
||||
Download download = downloadThread.download;
|
||||
logd("Download is stopped", download);
|
||||
activeDownloads.remove(download);
|
||||
@ -581,12 +582,9 @@ public final class DownloadManager {
|
||||
}
|
||||
|
||||
private static final class Download {
|
||||
|
||||
private final String id;
|
||||
private final DownloadManager downloadManager;
|
||||
private final long startTimeMs;
|
||||
private final ArrayDeque<DownloadAction> actionQueue;
|
||||
|
||||
private DownloadState downloadState;
|
||||
@DownloadState.State private int state;
|
||||
@MonotonicNonNull @DownloadState.FailureReason private int failureReason;
|
||||
@DownloadState.StopFlags private int stopFlags;
|
||||
@ -599,47 +597,26 @@ public final class DownloadManager {
|
||||
@DownloadState.StopFlags int stopFlags,
|
||||
@Requirements.RequirementFlags int notMetRequirements,
|
||||
int manualStopReason) {
|
||||
this.id = action.id;
|
||||
this.downloadManager = downloadManager;
|
||||
this.notMetRequirements = notMetRequirements;
|
||||
this.manualStopReason = manualStopReason;
|
||||
this.stopFlags = stopFlags;
|
||||
this.startTimeMs = System.currentTimeMillis();
|
||||
actionQueue = new ArrayDeque<>();
|
||||
actionQueue.add(action);
|
||||
downloadState = new DownloadState(action);
|
||||
|
||||
// Set to queued state but don't notify listeners until we make sure we don't switch to
|
||||
// another state immediately.
|
||||
state = STATE_QUEUED;
|
||||
initialize();
|
||||
if (state == STATE_QUEUED) {
|
||||
downloadManager.onDownloadStateChange(this);
|
||||
}
|
||||
initialize(downloadState.state);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return downloadState.id;
|
||||
}
|
||||
|
||||
public boolean addAction(DownloadAction newAction) {
|
||||
DownloadAction action = actionQueue.peek();
|
||||
if (!action.isSameMedia(newAction)) {
|
||||
if (!getId().equals(newAction.id)) {
|
||||
return false;
|
||||
}
|
||||
Assertions.checkState(action.type.equals(newAction.type));
|
||||
actionQueue.add(newAction);
|
||||
DownloadAction updatedAction = DownloadActionUtil.mergeActions(actionQueue);
|
||||
if (state == STATE_REMOVING) {
|
||||
Assertions.checkState(updatedAction.isRemoveAction);
|
||||
if (actionQueue.size() > 1) {
|
||||
setState(STATE_RESTARTING);
|
||||
}
|
||||
} else if (state == STATE_RESTARTING) {
|
||||
Assertions.checkState(updatedAction.isRemoveAction);
|
||||
if (actionQueue.size() == 1) {
|
||||
setState(STATE_REMOVING);
|
||||
}
|
||||
} else if (!action.equals(updatedAction)) {
|
||||
Assertions.checkState(
|
||||
state == STATE_DOWNLOADING || state == STATE_QUEUED || state == STATE_STOPPED);
|
||||
initialize();
|
||||
}
|
||||
Assertions.checkState(downloadState.type.equals(newAction.type));
|
||||
downloadState = downloadState.mergeAction(newAction);
|
||||
initialize(downloadState.state);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -653,24 +630,25 @@ public final class DownloadManager {
|
||||
downloadedBytes = downloader.getDownloadedBytes();
|
||||
totalBytes = downloader.getTotalBytes();
|
||||
}
|
||||
DownloadAction action = actionQueue.peek();
|
||||
return new DownloadState(
|
||||
action.id,
|
||||
action.type,
|
||||
action.uri,
|
||||
action.customCacheKey,
|
||||
state,
|
||||
downloadPercentage,
|
||||
downloadedBytes,
|
||||
totalBytes,
|
||||
failureReason,
|
||||
stopFlags,
|
||||
notMetRequirements,
|
||||
manualStopReason,
|
||||
startTimeMs,
|
||||
/* updateTimeMs= */ System.currentTimeMillis(),
|
||||
action.keys.toArray(new StreamKey[0]),
|
||||
action.data);
|
||||
downloadState =
|
||||
new DownloadState(
|
||||
downloadState.id,
|
||||
downloadState.type,
|
||||
downloadState.uri,
|
||||
downloadState.cacheKey,
|
||||
state,
|
||||
downloadPercentage,
|
||||
downloadedBytes,
|
||||
totalBytes,
|
||||
state != STATE_FAILED ? FAILURE_REASON_NONE : failureReason,
|
||||
stopFlags,
|
||||
notMetRequirements,
|
||||
manualStopReason,
|
||||
downloadState.startTimeMs,
|
||||
/* updateTimeMs= */ System.currentTimeMillis(),
|
||||
downloadState.streamKeys,
|
||||
downloadState.customMetadata);
|
||||
return downloadState;
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
@ -683,14 +661,14 @@ public final class DownloadManager {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return id + ' ' + DownloadState.getStateString(state);
|
||||
return getId() + ' ' + DownloadState.getStateString(state);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (state == STATE_QUEUED || state == STATE_DOWNLOADING) {
|
||||
startOrQueue();
|
||||
} else if (state == STATE_REMOVING || state == STATE_RESTARTING) {
|
||||
downloadManager.startDownloadThread(this, actionQueue.peek());
|
||||
downloadManager.startDownloadThread(this, getAction());
|
||||
}
|
||||
}
|
||||
|
||||
@ -725,26 +703,25 @@ public final class DownloadManager {
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
DownloadAction action = actionQueue.peek();
|
||||
if (action.isRemoveAction) {
|
||||
int result = downloadManager.startDownloadThread(this, action);
|
||||
Assertions.checkState(
|
||||
result == START_THREAD_SUCCEEDED
|
||||
|| result == START_THREAD_WAIT_DOWNLOAD_CANCELLATION
|
||||
|| result == START_THREAD_NOT_ALLOWED);
|
||||
setState(actionQueue.size() == 1 ? STATE_REMOVING : STATE_RESTARTING);
|
||||
private void initialize(int initialState) {
|
||||
// Don't notify listeners with initial state until we make sure we don't switch to
|
||||
// another state immediately.
|
||||
state = initialState;
|
||||
if (state == STATE_REMOVING || state == STATE_RESTARTING) {
|
||||
downloadManager.startDownloadThread(this, getAction());
|
||||
} else if (stopFlags != 0) {
|
||||
setState(STATE_STOPPED);
|
||||
} else {
|
||||
startOrQueue();
|
||||
}
|
||||
if (state == initialState) {
|
||||
downloadManager.onDownloadStateChange(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void startOrQueue() {
|
||||
DownloadAction action = Assertions.checkNotNull(actionQueue.peek());
|
||||
Assertions.checkState(!action.isRemoveAction);
|
||||
@StartThreadResults int result = downloadManager.startDownloadThread(this, action);
|
||||
Assertions.checkState(!(state == STATE_REMOVING || state == STATE_RESTARTING));
|
||||
@StartThreadResults int result = downloadManager.startDownloadThread(this, getAction());
|
||||
Assertions.checkState(result != START_THREAD_WAIT_REMOVAL_TO_FINISH);
|
||||
if (result == START_THREAD_SUCCEEDED || result == START_THREAD_WAIT_DOWNLOAD_CANCELLATION) {
|
||||
setState(STATE_DOWNLOADING);
|
||||
@ -753,6 +730,22 @@ public final class DownloadManager {
|
||||
}
|
||||
}
|
||||
|
||||
private DownloadAction getAction() {
|
||||
Assertions.checkState(state != STATE_REMOVED);
|
||||
if (state == STATE_REMOVING || state == STATE_RESTARTING) {
|
||||
return DownloadAction.createRemoveAction(
|
||||
downloadState.type, downloadState.uri, downloadState.cacheKey);
|
||||
}
|
||||
return getDownloadAction(downloadState);
|
||||
}
|
||||
|
||||
private void addActions(List<DownloadAction> actions) {
|
||||
actions.add(getAction());
|
||||
if (state == STATE_RESTARTING) {
|
||||
actions.add(getDownloadAction(downloadState));
|
||||
}
|
||||
}
|
||||
|
||||
private void setState(@DownloadState.State int newState) {
|
||||
if (state != newState) {
|
||||
state = newState;
|
||||
@ -761,29 +754,32 @@ public final class DownloadManager {
|
||||
}
|
||||
|
||||
private void onDownloadThreadStopped(boolean isCanceled, @Nullable Throwable error) {
|
||||
failureReason = FAILURE_REASON_NONE;
|
||||
if (isIdle()) {
|
||||
return;
|
||||
}
|
||||
if (isCanceled) {
|
||||
if (!isIdle()) {
|
||||
downloadManager.startDownloadThread(this, actionQueue.peek());
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (error != null && state == STATE_DOWNLOADING) {
|
||||
failureReason = FAILURE_REASON_UNKNOWN;
|
||||
setState(STATE_FAILED);
|
||||
return;
|
||||
}
|
||||
if (actionQueue.size() == 1) {
|
||||
if (state == STATE_REMOVING) {
|
||||
setState(STATE_REMOVED);
|
||||
downloadManager.startDownloadThread(this, getAction());
|
||||
} else if (state == STATE_RESTARTING) {
|
||||
initialize(STATE_QUEUED);
|
||||
} else if (state == STATE_REMOVING) {
|
||||
setState(STATE_REMOVED);
|
||||
} else { // STATE_DOWNLOADING
|
||||
if (error != null) {
|
||||
failureReason = FAILURE_REASON_UNKNOWN;
|
||||
setState(STATE_FAILED);
|
||||
} else {
|
||||
Assertions.checkState(state == STATE_DOWNLOADING);
|
||||
setState(STATE_COMPLETED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
actionQueue.remove();
|
||||
initialize();
|
||||
}
|
||||
|
||||
private static DownloadAction getDownloadAction(DownloadState downloadState) {
|
||||
return DownloadAction.createDownloadAction(
|
||||
downloadState.type,
|
||||
downloadState.uri,
|
||||
Arrays.asList(downloadState.streamKeys),
|
||||
downloadState.cacheKey,
|
||||
downloadState.customMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,7 +247,7 @@ public final class DownloadState {
|
||||
type,
|
||||
action.uri,
|
||||
action.customCacheKey,
|
||||
getNextState(action, state),
|
||||
getNextState(state, action.isRemoveAction),
|
||||
/* downloadPercentage= */ C.PERCENTAGE_UNSET,
|
||||
downloadedBytes,
|
||||
/* totalBytes= */ C.LENGTH_UNSET,
|
||||
@ -256,25 +256,25 @@ public final class DownloadState {
|
||||
notMetRequirements,
|
||||
manualStopReason,
|
||||
startTimeMs,
|
||||
updateTimeMs,
|
||||
/* updateTimeMs= */ System.currentTimeMillis(),
|
||||
mergeStreamKeys(this, action),
|
||||
action.data);
|
||||
}
|
||||
|
||||
private static int getNextState(DownloadAction action, int currentState) {
|
||||
int newState;
|
||||
if (action.isRemoveAction) {
|
||||
newState = STATE_REMOVING;
|
||||
private static int getNextState(int currentState, boolean remove) {
|
||||
int nextState;
|
||||
if (remove) {
|
||||
nextState = STATE_REMOVING;
|
||||
} else {
|
||||
if (currentState == STATE_REMOVING || currentState == STATE_RESTARTING) {
|
||||
newState = STATE_RESTARTING;
|
||||
nextState = STATE_RESTARTING;
|
||||
} else if (currentState == STATE_STOPPED) {
|
||||
newState = STATE_STOPPED;
|
||||
nextState = STATE_STOPPED;
|
||||
} else {
|
||||
newState = STATE_QUEUED;
|
||||
nextState = STATE_QUEUED;
|
||||
}
|
||||
}
|
||||
return newState;
|
||||
return nextState;
|
||||
}
|
||||
|
||||
private static StreamKey[] mergeStreamKeys(DownloadState downloadState, DownloadAction action) {
|
||||
|
@ -66,38 +66,38 @@ public class DownloadActionTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameUri_IsSameMedia() {
|
||||
public void testSameUri_hasSameId() {
|
||||
DownloadAction action1 = createDownloadAction(uri1);
|
||||
DownloadAction action2 = createDownloadAction(uri1);
|
||||
assertThat(action1.isSameMedia(action2)).isTrue();
|
||||
assertThat(action1.id.equals(action2.id)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameUriDifferentAction_IsSameMedia() {
|
||||
public void testSameUriDifferentAction_hasSameId() {
|
||||
DownloadAction action1 = createDownloadAction(uri1);
|
||||
DownloadAction action2 = createRemoveAction(uri1);
|
||||
assertThat(action1.isSameMedia(action2)).isTrue();
|
||||
assertThat(action1.id.equals(action2.id)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentUri_IsNotSameMedia() {
|
||||
DownloadAction action1 = createDownloadAction(uri1);
|
||||
DownloadAction action2 = createDownloadAction(uri2);
|
||||
assertThat(action1.isSameMedia(action2)).isFalse();
|
||||
assertThat(action1.id.equals(action2.id)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSameCacheKeyDifferentUri_IsSameMedia() {
|
||||
public void testSameCacheKeyDifferentUri_hasSameId() {
|
||||
DownloadAction action1 = DownloadAction.createRemoveAction(TYPE_DASH, uri1, "key123");
|
||||
DownloadAction action2 = DownloadAction.createRemoveAction(TYPE_DASH, uri2, "key123");
|
||||
assertThat(action1.isSameMedia(action2)).isTrue();
|
||||
assertThat(action1.id.equals(action2.id)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentCacheDifferentUri_IsNotSameMedia() {
|
||||
public void testDifferentCacheKeyDifferentUri_hasDifferentId() {
|
||||
DownloadAction action1 = DownloadAction.createRemoveAction(TYPE_DASH, uri1, "key123");
|
||||
DownloadAction action2 = DownloadAction.createRemoveAction(TYPE_DASH, uri2, "key456");
|
||||
assertThat(action1.isSameMedia(action2)).isFalse();
|
||||
assertThat(action1.id.equals(action2.id)).isFalse();
|
||||
}
|
||||
|
||||
@SuppressWarnings("EqualsWithItself")
|
||||
|
@ -1,335 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.offline;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import android.net.Uri;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
|
||||
/** Tests for {@link DownloadActionUtil} class. */
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
public class DownloadActionUtilTest {
|
||||
private Uri uri1;
|
||||
private Uri uri2;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
uri1 = Uri.parse("http://abc.com/media1");
|
||||
uri2 = Uri.parse("http://abc.com/media2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_ifQueueEmpty_throwsException() {
|
||||
try {
|
||||
DownloadActionUtil.mergeActions(toActionQueue());
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
// Expected.
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_ifOneActionInQueue_returnsTheSameAction() {
|
||||
DownloadAction action = createDownloadAction(uri1);
|
||||
|
||||
assertThat(DownloadActionUtil.mergeActions(toActionQueue(action))).isEqualTo(action);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_ifActionsHaveDifferentType_throwsException() {
|
||||
DownloadAction downloadAction1 =
|
||||
DownloadAction.createDownloadAction(
|
||||
DownloadAction.TYPE_PROGRESSIVE,
|
||||
uri1,
|
||||
Collections.emptyList(),
|
||||
/* customCacheKey= */ null,
|
||||
/* data= */ null);
|
||||
DownloadAction downloadAction2 =
|
||||
DownloadAction.createDownloadAction(
|
||||
DownloadAction.TYPE_DASH,
|
||||
uri1,
|
||||
Collections.emptyList(),
|
||||
/* customCacheKey= */ null,
|
||||
/* data= */ null);
|
||||
ArrayDeque<DownloadAction> actionQueue = toActionQueue(downloadAction1, downloadAction2);
|
||||
|
||||
try {
|
||||
DownloadActionUtil.mergeActions(actionQueue);
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
// Expected.
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_ifActionsHaveDifferentCacheKeys_throwsException() {
|
||||
DownloadAction downloadAction1 =
|
||||
DownloadAction.createDownloadAction(
|
||||
DownloadAction.TYPE_PROGRESSIVE,
|
||||
uri1,
|
||||
Collections.emptyList(),
|
||||
/* customCacheKey= */ "cacheKey1",
|
||||
/* data= */ null);
|
||||
DownloadAction downloadAction2 =
|
||||
DownloadAction.createDownloadAction(
|
||||
DownloadAction.TYPE_PROGRESSIVE,
|
||||
uri1,
|
||||
Collections.emptyList(),
|
||||
/* customCacheKey= */ "cacheKey2",
|
||||
/* data= */ null);
|
||||
ArrayDeque<DownloadAction> actionQueue = toActionQueue(downloadAction1, downloadAction2);
|
||||
|
||||
try {
|
||||
DownloadActionUtil.mergeActions(actionQueue);
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
// Expected.
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_nullCacheKeyAndDifferentUrl_throwsException() {
|
||||
DownloadAction downloadAction1 =
|
||||
DownloadAction.createDownloadAction(
|
||||
DownloadAction.TYPE_PROGRESSIVE,
|
||||
uri1,
|
||||
Collections.emptyList(),
|
||||
/* customCacheKey= */ null,
|
||||
/* data= */ null);
|
||||
DownloadAction downloadAction2 =
|
||||
DownloadAction.createDownloadAction(
|
||||
DownloadAction.TYPE_PROGRESSIVE,
|
||||
uri2,
|
||||
Collections.emptyList(),
|
||||
/* customCacheKey= */ null,
|
||||
/* data= */ null);
|
||||
ArrayDeque<DownloadAction> actionQueue = toActionQueue(downloadAction1, downloadAction2);
|
||||
|
||||
try {
|
||||
DownloadActionUtil.mergeActions(actionQueue);
|
||||
fail();
|
||||
} catch (Exception e) {
|
||||
// Expected.
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_sameCacheKeyAndDifferentUrl_latterUrlUsed() {
|
||||
DownloadAction downloadAction1 =
|
||||
DownloadAction.createDownloadAction(
|
||||
DownloadAction.TYPE_PROGRESSIVE,
|
||||
uri1,
|
||||
Collections.emptyList(),
|
||||
/* customCacheKey= */ "cacheKey1",
|
||||
/* data= */ null);
|
||||
DownloadAction downloadAction2 =
|
||||
DownloadAction.createDownloadAction(
|
||||
DownloadAction.TYPE_PROGRESSIVE,
|
||||
uri2,
|
||||
Collections.emptyList(),
|
||||
/* customCacheKey= */ "cacheKey1",
|
||||
/* data= */ null);
|
||||
ArrayDeque<DownloadAction> actionQueue = toActionQueue(downloadAction1, downloadAction2);
|
||||
|
||||
DownloadActionUtil.mergeActions(actionQueue);
|
||||
|
||||
DownloadAction mergedAction = DownloadActionUtil.mergeActions(actionQueue);
|
||||
|
||||
assertThat(mergedAction.uri).isEqualTo(uri2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_differentData_latterDataUsed() {
|
||||
byte[] data1 = "data1".getBytes();
|
||||
DownloadAction downloadAction1 =
|
||||
DownloadAction.createDownloadAction(
|
||||
DownloadAction.TYPE_PROGRESSIVE,
|
||||
uri1,
|
||||
Collections.emptyList(),
|
||||
/* customCacheKey= */ null,
|
||||
/* data= */ data1);
|
||||
byte[] data2 = "data2".getBytes();
|
||||
DownloadAction downloadAction2 =
|
||||
DownloadAction.createDownloadAction(
|
||||
DownloadAction.TYPE_PROGRESSIVE,
|
||||
uri1,
|
||||
Collections.emptyList(),
|
||||
/* customCacheKey= */ null,
|
||||
/* data= */ data2);
|
||||
ArrayDeque<DownloadAction> actionQueue = toActionQueue(downloadAction1, downloadAction2);
|
||||
|
||||
DownloadActionUtil.mergeActions(actionQueue);
|
||||
|
||||
DownloadAction mergedAction = DownloadActionUtil.mergeActions(actionQueue);
|
||||
|
||||
assertThat(mergedAction.data).isEqualTo(data2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_ifRemoveActionLast_returnsRemoveAction() {
|
||||
DownloadAction downloadAction = createDownloadAction(uri1);
|
||||
DownloadAction removeAction = createRemoveAction(uri1);
|
||||
ArrayDeque<DownloadAction> actionQueue = toActionQueue(downloadAction, removeAction);
|
||||
|
||||
DownloadAction action = DownloadActionUtil.mergeActions(actionQueue);
|
||||
|
||||
assertThat(action).isEqualTo(removeAction);
|
||||
assertThat(actionQueue).containsExactly(removeAction);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_downloadActionAfterRemove_returnsRemoveKeepsDownload() {
|
||||
DownloadAction removeAction = createRemoveAction(uri1);
|
||||
DownloadAction downloadAction = createDownloadAction(uri1);
|
||||
ArrayDeque<DownloadAction> actionQueue = toActionQueue(removeAction, downloadAction);
|
||||
|
||||
DownloadAction action = DownloadActionUtil.mergeActions(actionQueue);
|
||||
|
||||
assertThat(action).isEqualTo(removeAction);
|
||||
assertThat(actionQueue).containsExactly(removeAction, downloadAction);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_downloadActionsAfterRemove_returnsRemoveMergesDownloads() {
|
||||
DownloadAction removeAction = createRemoveAction(uri1);
|
||||
StreamKey streamKey1 = new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0);
|
||||
DownloadAction downloadAction1 =
|
||||
createDownloadAction(uri1, Collections.singletonList(streamKey1));
|
||||
StreamKey streamKey2 = new StreamKey(/* groupIndex= */ 1, /* trackIndex= */ 1);
|
||||
DownloadAction downloadAction2 =
|
||||
createDownloadAction(uri1, Collections.singletonList(streamKey2));
|
||||
ArrayDeque<DownloadAction> actionQueue =
|
||||
toActionQueue(removeAction, downloadAction1, downloadAction2);
|
||||
DownloadAction mergedDownloadAction =
|
||||
createDownloadAction(uri1, Arrays.asList(streamKey1, streamKey2));
|
||||
|
||||
DownloadAction action = DownloadActionUtil.mergeActions(actionQueue);
|
||||
|
||||
assertThat(action).isEqualTo(removeAction);
|
||||
assertThat(actionQueue).containsExactly(removeAction, mergedDownloadAction);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_actionBeforeRemove_ignoresActionBeforeRemove() {
|
||||
DownloadAction removeAction = createRemoveAction(uri1);
|
||||
StreamKey streamKey1 = new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0);
|
||||
DownloadAction downloadAction1 =
|
||||
createDownloadAction(uri1, Collections.singletonList(streamKey1));
|
||||
StreamKey streamKey2 = new StreamKey(/* groupIndex= */ 1, /* trackIndex= */ 1);
|
||||
DownloadAction downloadAction2 =
|
||||
createDownloadAction(uri1, Collections.singletonList(streamKey2));
|
||||
StreamKey streamKey3 = new StreamKey(/* groupIndex= */ 2, /* trackIndex= */ 2);
|
||||
DownloadAction downloadAction3 =
|
||||
createDownloadAction(uri1, Collections.singletonList(streamKey3));
|
||||
ArrayDeque<DownloadAction> actionQueue =
|
||||
toActionQueue(downloadAction1, removeAction, downloadAction2, downloadAction3);
|
||||
DownloadAction mergedDownloadAction =
|
||||
createDownloadAction(uri1, Arrays.asList(streamKey2, streamKey3));
|
||||
|
||||
DownloadAction action = DownloadActionUtil.mergeActions(actionQueue);
|
||||
|
||||
assertThat(action).isEqualTo(removeAction);
|
||||
assertThat(actionQueue).containsExactly(removeAction, mergedDownloadAction);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_returnsMergedAction() {
|
||||
StreamKey streamKey1 = new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0);
|
||||
StreamKey streamKey2 = new StreamKey(/* groupIndex= */ 1, /* trackIndex= */ 1);
|
||||
StreamKey[] keys1 = new StreamKey[] {streamKey1};
|
||||
StreamKey[] keys2 = new StreamKey[] {streamKey2};
|
||||
StreamKey[] expectedKeys = new StreamKey[] {streamKey1, streamKey2};
|
||||
|
||||
doTestMergeActionsReturnsMergedKeys(keys1, keys2, expectedKeys);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_returnsUniqueKeys() {
|
||||
StreamKey streamKey1 = new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0);
|
||||
StreamKey streamKey1Copy = new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0);
|
||||
StreamKey streamKey2 = new StreamKey(/* groupIndex= */ 1, /* trackIndex= */ 1);
|
||||
StreamKey[] keys1 = new StreamKey[] {streamKey1};
|
||||
StreamKey[] keys2 = new StreamKey[] {streamKey2, streamKey1Copy};
|
||||
StreamKey[] expectedKeys = new StreamKey[] {streamKey1, streamKey2};
|
||||
|
||||
doTestMergeActionsReturnsMergedKeys(keys1, keys2, expectedKeys);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_ifFirstActionKeysEmpty_returnsEmptyKeys() {
|
||||
StreamKey streamKey1 = new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0);
|
||||
StreamKey streamKey2 = new StreamKey(/* groupIndex= */ 1, /* trackIndex= */ 1);
|
||||
StreamKey[] keys1 = new StreamKey[] {};
|
||||
StreamKey[] keys2 = new StreamKey[] {streamKey2, streamKey1};
|
||||
StreamKey[] expectedKeys = new StreamKey[] {};
|
||||
|
||||
doTestMergeActionsReturnsMergedKeys(keys1, keys2, expectedKeys);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mergeActions_ifNotFirstActionKeysEmpty_returnsEmptyKeys() {
|
||||
StreamKey streamKey1 = new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0);
|
||||
StreamKey streamKey2 = new StreamKey(/* groupIndex= */ 1, /* trackIndex= */ 1);
|
||||
StreamKey[] keys1 = new StreamKey[] {streamKey2, streamKey1};
|
||||
StreamKey[] keys2 = new StreamKey[] {};
|
||||
StreamKey[] expectedKeys = new StreamKey[] {};
|
||||
|
||||
doTestMergeActionsReturnsMergedKeys(keys1, keys2, expectedKeys);
|
||||
}
|
||||
|
||||
private void doTestMergeActionsReturnsMergedKeys(
|
||||
StreamKey[] keys1, StreamKey[] keys2, StreamKey[] expectedKeys) {
|
||||
DownloadAction action1 = createDownloadAction(uri1, Arrays.asList(keys1));
|
||||
DownloadAction action2 = createDownloadAction(uri1, Arrays.asList(keys2));
|
||||
ArrayDeque<DownloadAction> actionQueue = toActionQueue(action1, action2);
|
||||
|
||||
DownloadAction mergedAction = DownloadActionUtil.mergeActions(actionQueue);
|
||||
|
||||
assertThat(mergedAction.type).isEqualTo(action1.type);
|
||||
assertThat(mergedAction.uri).isEqualTo(action1.uri);
|
||||
assertThat(mergedAction.customCacheKey).isEqualTo(action1.customCacheKey);
|
||||
assertThat(mergedAction.isRemoveAction).isEqualTo(action1.isRemoveAction);
|
||||
assertThat(mergedAction.keys).containsExactly((Object[]) expectedKeys);
|
||||
assertThat(actionQueue).containsExactly(mergedAction);
|
||||
}
|
||||
|
||||
private ArrayDeque<DownloadAction> toActionQueue(DownloadAction... actions) {
|
||||
return new ArrayDeque<>(Arrays.asList(actions));
|
||||
}
|
||||
|
||||
private static DownloadAction createDownloadAction(Uri uri) {
|
||||
return createDownloadAction(uri, Collections.emptyList());
|
||||
}
|
||||
|
||||
private static DownloadAction createDownloadAction(Uri uri, List<StreamKey> keys) {
|
||||
return DownloadAction.createDownloadAction(
|
||||
DownloadAction.TYPE_PROGRESSIVE, uri, keys, /* customCacheKey= */ null, /* data= */ null);
|
||||
}
|
||||
|
||||
private static DownloadAction createRemoveAction(Uri uri) {
|
||||
return DownloadAction.createRemoveAction(
|
||||
DownloadAction.TYPE_PROGRESSIVE, uri, /* customCacheKey= */ null);
|
||||
}
|
||||
}
|
@ -251,21 +251,6 @@ public class DownloadManagerTest {
|
||||
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void secondSameDownloadActionIgnored() throws Throwable {
|
||||
DownloadRunner runner = new DownloadRunner(uri1);
|
||||
FakeDownloader downloader1 = runner.getDownloader(0);
|
||||
|
||||
runner.postDownloadAction();
|
||||
downloader1.assertStarted();
|
||||
runner.postDownloadAction();
|
||||
|
||||
downloader1.unblock().assertNotCanceled();
|
||||
runner.getTask().assertCompleted();
|
||||
runner.assertCreatedDownloaderCount(1);
|
||||
downloadManagerListener.blockUntilTasksCompleteAndThrowAnyDownloadError();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void differentDownloadActionsMerged() throws Throwable {
|
||||
DownloadRunner runner = new DownloadRunner(uri1);
|
||||
|
@ -276,10 +276,16 @@ public class DownloadStateTest {
|
||||
}
|
||||
|
||||
static void assertEqual(DownloadState downloadState, DownloadState expected) {
|
||||
assertThat(areEqual(downloadState, expected)).isTrue();
|
||||
assertEqual(downloadState, expected, false);
|
||||
}
|
||||
|
||||
private static boolean areEqual(DownloadState downloadState, DownloadState that) {
|
||||
static void assertEqual(
|
||||
DownloadState downloadState, DownloadState expected, boolean compareTimeFields) {
|
||||
assertThat(areEqual(downloadState, expected, compareTimeFields)).isTrue();
|
||||
}
|
||||
|
||||
private static boolean areEqual(
|
||||
DownloadState downloadState, DownloadState that, boolean compareTimeFields) {
|
||||
if (downloadState.state != that.state) {
|
||||
return false;
|
||||
}
|
||||
@ -292,11 +298,13 @@ public class DownloadStateTest {
|
||||
if (downloadState.totalBytes != that.totalBytes) {
|
||||
return false;
|
||||
}
|
||||
if (downloadState.startTimeMs != that.startTimeMs) {
|
||||
return false;
|
||||
}
|
||||
if (downloadState.updateTimeMs != that.updateTimeMs) {
|
||||
return false;
|
||||
if (compareTimeFields) {
|
||||
if (downloadState.startTimeMs != that.startTimeMs) {
|
||||
return false;
|
||||
}
|
||||
if (downloadState.updateTimeMs != that.updateTimeMs) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (downloadState.failureReason != that.failureReason) {
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user