Add DownloadActionUtil class
PiperOrigin-RevId: 224647076
This commit is contained in:
parent
22948f2eda
commit
480bb50b54
@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* 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());
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,335 @@
|
|||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user