From 5782bbc6e551d6668f26e4dfa51394e61d552ca7 Mon Sep 17 00:00:00 2001 From: eguven Date: Tue, 12 Feb 2019 13:07:03 +0000 Subject: [PATCH] Use DownloadState in DownloadManager PiperOrigin-RevId: 233587184 --- .../exoplayer2/offline/DownloadAction.java | 5 - .../offline/DownloadActionUtil.java | 79 ----- .../exoplayer2/offline/DownloadManager.java | 186 +++++----- .../exoplayer2/offline/DownloadState.java | 20 +- .../offline/DownloadActionTest.java | 18 +- .../offline/DownloadActionUtilTest.java | 335 ------------------ .../offline/DownloadManagerTest.java | 15 - .../exoplayer2/offline/DownloadStateTest.java | 22 +- 8 files changed, 125 insertions(+), 555 deletions(-) delete mode 100644 library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadActionUtil.java delete mode 100644 library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadActionUtilTest.java diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadAction.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadAction.java index 40ea094b5e..0c36b8bb63 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadAction.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadAction.java @@ -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 getKeys() { return keys; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadActionUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadActionUtil.java deleted file mode 100644 index f722f9b59b..0000000000 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadActionUtil.java +++ /dev/null @@ -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. - * - *

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 actionQueue) { - DownloadAction removeAction = null; - DownloadAction downloadAction = null; - HashSet 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()); - } -} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadManager.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadManager.java index 731f7fc43e..cd5f0dc6cf 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadManager.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadManager.java @@ -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 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 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 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); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadState.java b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadState.java index b32288fa3f..5bf3496def 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadState.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/offline/DownloadState.java @@ -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) { diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadActionTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadActionTest.java index 9d057e0f56..96aa4e4509 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadActionTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadActionTest.java @@ -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") diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadActionUtilTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadActionUtilTest.java deleted file mode 100644 index a494057a05..0000000000 --- a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadActionUtilTest.java +++ /dev/null @@ -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 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 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 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 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 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 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 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 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 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 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 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 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); - } -} diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java index 98b21c6e22..a4e63a1c78 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadManagerTest.java @@ -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); diff --git a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadStateTest.java b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadStateTest.java index 982a6e8ef9..dcb0b443af 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadStateTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/offline/DownloadStateTest.java @@ -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;