Remove deprecated ActionFile and ActionFileUpgradeUtil

#minor-release

PiperOrigin-RevId: 426868933
This commit is contained in:
ibaker 2022-02-07 11:08:51 +00:00 committed by Ian Baker
parent ce4225f864
commit 4e3d15be87
16 changed files with 1 additions and 786 deletions

View File

@ -16,7 +16,6 @@
package androidx.media3.demo.main; package androidx.media3.demo.main;
import android.content.Context; import android.content.Context;
import androidx.media3.common.util.Log;
import androidx.media3.database.DatabaseProvider; import androidx.media3.database.DatabaseProvider;
import androidx.media3.database.StandaloneDatabaseProvider; import androidx.media3.database.StandaloneDatabaseProvider;
import androidx.media3.datasource.DataSource; import androidx.media3.datasource.DataSource;
@ -31,12 +30,9 @@ import androidx.media3.datasource.cronet.CronetDataSource;
import androidx.media3.datasource.cronet.CronetUtil; import androidx.media3.datasource.cronet.CronetUtil;
import androidx.media3.exoplayer.DefaultRenderersFactory; import androidx.media3.exoplayer.DefaultRenderersFactory;
import androidx.media3.exoplayer.RenderersFactory; import androidx.media3.exoplayer.RenderersFactory;
import androidx.media3.exoplayer.offline.ActionFileUpgradeUtil;
import androidx.media3.exoplayer.offline.DefaultDownloadIndex;
import androidx.media3.exoplayer.offline.DownloadManager; import androidx.media3.exoplayer.offline.DownloadManager;
import androidx.media3.exoplayer.offline.DownloadNotificationHelper; import androidx.media3.exoplayer.offline.DownloadNotificationHelper;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.net.CookieHandler; import java.net.CookieHandler;
import java.net.CookieManager; import java.net.CookieManager;
import java.net.CookiePolicy; import java.net.CookiePolicy;
@ -60,8 +56,6 @@ public final class DemoUtil {
private static final boolean USE_CRONET_FOR_NETWORKING = true; private static final boolean USE_CRONET_FOR_NETWORKING = true;
private static final String TAG = "DemoUtil"; private static final String TAG = "DemoUtil";
private static final String DOWNLOAD_ACTION_FILE = "actions";
private static final String DOWNLOAD_TRACKER_ACTION_FILE = "tracked_actions";
private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads"; private static final String DOWNLOAD_CONTENT_DIRECTORY = "downloads";
private static DataSource.@MonotonicNonNull Factory dataSourceFactory; private static DataSource.@MonotonicNonNull Factory dataSourceFactory;
@ -155,14 +149,6 @@ public final class DemoUtil {
private static synchronized void ensureDownloadManagerInitialized(Context context) { private static synchronized void ensureDownloadManagerInitialized(Context context) {
if (downloadManager == null) { if (downloadManager == null) {
DefaultDownloadIndex downloadIndex = new DefaultDownloadIndex(getDatabaseProvider(context));
upgradeActionFile(
context, DOWNLOAD_ACTION_FILE, downloadIndex, /* addNewDownloadsAsCompleted= */ false);
upgradeActionFile(
context,
DOWNLOAD_TRACKER_ACTION_FILE,
downloadIndex,
/* addNewDownloadsAsCompleted= */ true);
downloadManager = downloadManager =
new DownloadManager( new DownloadManager(
context, context,
@ -175,23 +161,6 @@ public final class DemoUtil {
} }
} }
private static synchronized void upgradeActionFile(
Context context,
String fileName,
DefaultDownloadIndex downloadIndex,
boolean addNewDownloadsAsCompleted) {
try {
ActionFileUpgradeUtil.upgradeAndDelete(
new File(getDownloadDirectory(context), fileName),
/* downloadIdProvider= */ null,
downloadIndex,
/* deleteOnFailure= */ true,
addNewDownloadsAsCompleted);
} catch (IOException e) {
Log.e(TAG, "Failed to upgrade action file: " + fileName, e);
}
}
private static synchronized DatabaseProvider getDatabaseProvider(Context context) { private static synchronized DatabaseProvider getDatabaseProvider(Context context) {
if (databaseProvider == null) { if (databaseProvider == null) {
databaseProvider = new StandaloneDatabaseProvider(context); databaseProvider = new StandaloneDatabaseProvider(context);

View File

@ -1,189 +0,0 @@
/*
* Copyright (C) 2017 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 androidx.media3.exoplayer.offline;
import android.net.Uri;
import androidx.annotation.Nullable;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.StreamKey;
import androidx.media3.common.util.AtomicFile;
import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.offline.DownloadRequest.UnsupportedRequestException;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
/**
* Loads {@link DownloadRequest DownloadRequests} from legacy action files.
*
* @deprecated Legacy action files should be merged into download indices using {@link
* ActionFileUpgradeUtil}.
*/
@Deprecated
/* package */ final class ActionFile {
private static final int VERSION = 0;
private static final String DOWNLOAD_TYPE_PROGRESSIVE = "progressive";
private static final String DOWNLOAD_TYPE_DASH = "dash";
private static final String DOWNLOAD_TYPE_HLS = "hls";
private static final String DOWNLOAD_TYPE_SS = "ss";
private final AtomicFile atomicFile;
/**
* @param actionFile The file from which {@link DownloadRequest DownloadRequests} will be loaded.
*/
public ActionFile(File actionFile) {
atomicFile = new AtomicFile(actionFile);
}
/** Returns whether the file or its backup exists. */
public boolean exists() {
return atomicFile.exists();
}
/** Deletes the action file and its backup. */
public void delete() {
atomicFile.delete();
}
/**
* Loads {@link DownloadRequest DownloadRequests} from the file.
*
* @return The loaded {@link DownloadRequest DownloadRequests}, or an empty array if the file does
* not exist.
* @throws IOException If there is an error reading the file.
*/
public DownloadRequest[] load() throws IOException {
if (!exists()) {
return new DownloadRequest[0];
}
@Nullable InputStream inputStream = null;
try {
inputStream = atomicFile.openRead();
DataInputStream dataInputStream = new DataInputStream(inputStream);
int version = dataInputStream.readInt();
if (version > VERSION) {
throw new IOException("Unsupported action file version: " + version);
}
int actionCount = dataInputStream.readInt();
ArrayList<DownloadRequest> actions = new ArrayList<>();
for (int i = 0; i < actionCount; i++) {
try {
actions.add(readDownloadRequest(dataInputStream));
} catch (UnsupportedRequestException e) {
// remove DownloadRequest is not supported. Ignore and continue loading rest.
}
}
return actions.toArray(new DownloadRequest[0]);
} finally {
Util.closeQuietly(inputStream);
}
}
private static DownloadRequest readDownloadRequest(DataInputStream input) throws IOException {
String downloadType = input.readUTF();
int version = input.readInt();
Uri uri = Uri.parse(input.readUTF());
boolean isRemoveAction = input.readBoolean();
int dataLength = input.readInt();
@Nullable byte[] data;
if (dataLength != 0) {
data = new byte[dataLength];
input.readFully(data);
} else {
data = null;
}
// Serialized version 0 progressive actions did not contain keys.
boolean isLegacyProgressive = version == 0 && DOWNLOAD_TYPE_PROGRESSIVE.equals(downloadType);
List<StreamKey> keys = new ArrayList<>();
if (!isLegacyProgressive) {
int keyCount = input.readInt();
for (int i = 0; i < keyCount; i++) {
keys.add(readKey(downloadType, version, input));
}
}
// Serialized version 0 and 1 DASH/HLS/SS actions did not contain a custom cache key.
boolean isLegacySegmented =
version < 2
&& (DOWNLOAD_TYPE_DASH.equals(downloadType)
|| DOWNLOAD_TYPE_HLS.equals(downloadType)
|| DOWNLOAD_TYPE_SS.equals(downloadType));
@Nullable String customCacheKey = null;
if (!isLegacySegmented) {
customCacheKey = input.readBoolean() ? input.readUTF() : null;
}
// Serialized version 0, 1 and 2 did not contain an id. We need to generate one.
String id = version < 3 ? generateDownloadId(uri, customCacheKey) : input.readUTF();
if (isRemoveAction) {
// Remove actions are not supported anymore.
throw new UnsupportedRequestException();
}
return new DownloadRequest.Builder(id, uri)
.setMimeType(inferMimeType(downloadType))
.setStreamKeys(keys)
.setCustomCacheKey(customCacheKey)
.setData(data)
.build();
}
private static StreamKey readKey(String type, int version, DataInputStream input)
throws IOException {
int periodIndex;
int groupIndex;
int trackIndex;
// Serialized version 0 HLS/SS actions did not contain a period index.
if ((DOWNLOAD_TYPE_HLS.equals(type) || DOWNLOAD_TYPE_SS.equals(type)) && version == 0) {
periodIndex = 0;
groupIndex = input.readInt();
trackIndex = input.readInt();
} else {
periodIndex = input.readInt();
groupIndex = input.readInt();
trackIndex = input.readInt();
}
return new StreamKey(periodIndex, groupIndex, trackIndex);
}
private static String inferMimeType(String downloadType) {
switch (downloadType) {
case DOWNLOAD_TYPE_DASH:
return MimeTypes.APPLICATION_MPD;
case DOWNLOAD_TYPE_HLS:
return MimeTypes.APPLICATION_M3U8;
case DOWNLOAD_TYPE_SS:
return MimeTypes.APPLICATION_SS;
case DOWNLOAD_TYPE_PROGRESSIVE:
default:
return MimeTypes.VIDEO_UNKNOWN;
}
}
private static String generateDownloadId(Uri uri, @Nullable String customCacheKey) {
return customCacheKey != null ? customCacheKey : uri.toString();
}
}

View File

@ -1,122 +0,0 @@
/*
* Copyright (C) 2019 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 androidx.media3.exoplayer.offline;
import static androidx.media3.exoplayer.offline.Download.STATE_QUEUED;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.media3.common.C;
import androidx.media3.common.util.UnstableApi;
import java.io.File;
import java.io.IOException;
/** Utility class for upgrading legacy action files into {@link DefaultDownloadIndex}. */
@UnstableApi
public final class ActionFileUpgradeUtil {
/** Provides download IDs during action file upgrade. */
public interface DownloadIdProvider {
/**
* Returns a download id for given request.
*
* @param downloadRequest The request for which an ID is required.
* @return A corresponding download ID.
*/
String getId(DownloadRequest downloadRequest);
}
private ActionFileUpgradeUtil() {}
/**
* Merges {@link DownloadRequest DownloadRequests} contained in a legacy action file into a {@link
* DefaultDownloadIndex}, deleting the action file if the merge is successful or if {@code
* deleteOnFailure} is {@code true}.
*
* <p>This method must not be called while the {@link DefaultDownloadIndex} is being used by a
* {@link DownloadManager}.
*
* <p>This method may be slow and shouldn't normally be called on the main thread.
*
* @param actionFilePath The action file path.
* @param downloadIdProvider A download ID provider, or {@code null}. If {@code null} then ID of
* each download will be its custom cache key if one is specified, or else its URL.
* @param downloadIndex The index into which the requests will be merged.
* @param deleteOnFailure Whether to delete the action file if the merge fails.
* @param addNewDownloadsAsCompleted Whether to add new downloads as completed.
* @throws IOException If an error occurs loading or merging the requests.
*/
@WorkerThread
@SuppressWarnings("deprecation")
public static void upgradeAndDelete(
File actionFilePath,
@Nullable DownloadIdProvider downloadIdProvider,
DefaultDownloadIndex downloadIndex,
boolean deleteOnFailure,
boolean addNewDownloadsAsCompleted)
throws IOException {
ActionFile actionFile = new ActionFile(actionFilePath);
if (actionFile.exists()) {
boolean success = false;
try {
long nowMs = System.currentTimeMillis();
for (DownloadRequest request : actionFile.load()) {
if (downloadIdProvider != null) {
request = request.copyWithId(downloadIdProvider.getId(request));
}
mergeRequest(request, downloadIndex, addNewDownloadsAsCompleted, nowMs);
}
success = true;
} finally {
if (success || deleteOnFailure) {
actionFile.delete();
}
}
}
}
/**
* Merges a {@link DownloadRequest} into a {@link DefaultDownloadIndex}.
*
* @param request The request to be merged.
* @param downloadIndex The index into which the request will be merged.
* @param addNewDownloadAsCompleted Whether to add new downloads as completed.
* @throws IOException If an error occurs merging the request.
*/
/* package */ static void mergeRequest(
DownloadRequest request,
DefaultDownloadIndex downloadIndex,
boolean addNewDownloadAsCompleted,
long nowMs)
throws IOException {
@Nullable Download download = downloadIndex.getDownload(request.id);
if (download != null) {
download = DownloadManager.mergeRequest(download, request, download.stopReason, nowMs);
} else {
download =
new Download(
request,
addNewDownloadAsCompleted ? Download.STATE_COMPLETED : STATE_QUEUED,
/* startTimeMs= */ nowMs,
/* updateTimeMs= */ nowMs,
/* contentLength= */ C.LENGTH_UNSET,
Download.STOP_REASON_NONE,
Download.FAILURE_REASON_NONE);
}
downloadIndex.putDownload(download);
}
}

View File

@ -1,133 +0,0 @@
/*
* Copyright (C) 2017 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 androidx.media3.exoplayer.offline;
import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Util;
import androidx.media3.test.utils.TestUtil;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit tests for {@link ActionFile}. */
@SuppressWarnings("deprecation")
@RunWith(AndroidJUnit4.class)
public class ActionFileTest {
private File tempFile;
private DownloadRequest expectedAction1;
private DownloadRequest expectedAction2;
@Before
public void setUp() throws Exception {
tempFile = Util.createTempFile(ApplicationProvider.getApplicationContext(), "ExoPlayerTest");
expectedAction1 =
buildExpectedRequest(Uri.parse("http://test1.uri"), TestUtil.buildTestData(16));
expectedAction2 =
buildExpectedRequest(Uri.parse("http://test2.uri"), TestUtil.buildTestData(32));
}
@After
public void tearDown() throws Exception {
tempFile.delete();
}
@Test
public void loadNoDataThrowsIOException() throws Exception {
ActionFile actionFile = getActionFile("media/offline/action_file_no_data.exi");
try {
actionFile.load();
Assert.fail();
} catch (IOException e) {
// Expected exception.
}
}
@Test
public void loadIncompleteHeaderThrowsIOException() throws Exception {
ActionFile actionFile = getActionFile("media/offline/action_file_incomplete_header.exi");
try {
actionFile.load();
Assert.fail();
} catch (IOException e) {
// Expected exception.
}
}
@Test
public void loadZeroActions() throws Exception {
ActionFile actionFile = getActionFile("media/offline/action_file_zero_actions.exi");
DownloadRequest[] actions = actionFile.load();
assertThat(actions).isNotNull();
assertThat(actions).hasLength(0);
}
@Test
public void loadOneAction() throws Exception {
ActionFile actionFile = getActionFile("media/offline/action_file_one_action.exi");
DownloadRequest[] actions = actionFile.load();
assertThat(actions).hasLength(1);
assertThat(actions[0]).isEqualTo(expectedAction1);
}
@Test
public void loadTwoActions() throws Exception {
ActionFile actionFile = getActionFile("media/offline/action_file_two_actions.exi");
DownloadRequest[] actions = actionFile.load();
assertThat(actions).hasLength(2);
assertThat(actions[0]).isEqualTo(expectedAction1);
assertThat(actions[1]).isEqualTo(expectedAction2);
}
@Test
public void loadUnsupportedVersion() throws Exception {
ActionFile actionFile = getActionFile("media/offline/action_file_unsupported_version.exi");
try {
actionFile.load();
Assert.fail();
} catch (IOException e) {
// Expected exception.
}
}
private ActionFile getActionFile(String fileName) throws IOException {
// Copy the test data from the asset to where the ActionFile expects it to be.
byte[] actionFileBytes =
TestUtil.getByteArray(ApplicationProvider.getApplicationContext(), fileName);
try (FileOutputStream output = new FileOutputStream(tempFile)) {
output.write(actionFileBytes);
}
// Load the action file.
return new ActionFile(tempFile);
}
private static DownloadRequest buildExpectedRequest(Uri uri, byte[] data) {
return new DownloadRequest.Builder(/* id= */ uri.toString(), uri)
.setMimeType(MimeTypes.VIDEO_UNKNOWN)
.setData(data)
.build();
}
}

View File

@ -1,309 +0,0 @@
/*
* Copyright (C) 2019 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 androidx.media3.exoplayer.offline;
import static com.google.common.truth.Truth.assertThat;
import android.net.Uri;
import androidx.media3.common.MimeTypes;
import androidx.media3.common.StreamKey;
import androidx.media3.common.util.Util;
import androidx.media3.database.StandaloneDatabaseProvider;
import androidx.media3.test.utils.TestUtil;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.common.collect.ImmutableList;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit tests for {@link ActionFileUpgradeUtil}. */
@RunWith(AndroidJUnit4.class)
public class ActionFileUpgradeUtilTest {
private static final long NOW_MS = 1234;
private File tempFile;
private StandaloneDatabaseProvider databaseProvider;
private DefaultDownloadIndex downloadIndex;
@Before
public void setUp() throws Exception {
tempFile = Util.createTempFile(ApplicationProvider.getApplicationContext(), "ExoPlayerTest");
databaseProvider = new StandaloneDatabaseProvider(ApplicationProvider.getApplicationContext());
downloadIndex = new DefaultDownloadIndex(databaseProvider);
}
@After
public void tearDown() {
databaseProvider.close();
tempFile.delete();
}
@Test
public void upgradeAndDelete_progressiveActionFile_createsDownloads() throws IOException {
byte[] actionFileBytes =
TestUtil.getByteArray(
ApplicationProvider.getApplicationContext(),
"media/offline/action_file_for_download_index_upgrade_progressive.exi");
try (FileOutputStream output = new FileOutputStream(tempFile)) {
output.write(actionFileBytes);
}
DownloadRequest expectedRequest1 =
new DownloadRequest.Builder(
/* id= */ "http://www.test.com/1/video.mp4",
Uri.parse("http://www.test.com/1/video.mp4"))
.setMimeType(MimeTypes.VIDEO_UNKNOWN)
.build();
DownloadRequest expectedRequest2 =
new DownloadRequest.Builder(
/* id= */ "customCacheKey", Uri.parse("http://www.test.com/2/video.mp4"))
.setMimeType(MimeTypes.VIDEO_UNKNOWN)
.setCustomCacheKey("customCacheKey")
.setData(new byte[] {0, 1, 2, 3})
.build();
ActionFileUpgradeUtil.upgradeAndDelete(
tempFile,
/* downloadIdProvider= */ null,
downloadIndex,
/* deleteOnFailure= */ true,
/* addNewDownloadsAsCompleted= */ false);
assertThat(tempFile.exists()).isFalse();
assertDownloadIndexContainsRequest(expectedRequest1, Download.STATE_QUEUED);
assertDownloadIndexContainsRequest(expectedRequest2, Download.STATE_QUEUED);
}
@Test
public void upgradeAndDelete_dashActionFile_createsDownloads() throws IOException {
byte[] actionFileBytes =
TestUtil.getByteArray(
ApplicationProvider.getApplicationContext(),
"media/offline/action_file_for_download_index_upgrade_dash.exi");
try (FileOutputStream output = new FileOutputStream(tempFile)) {
output.write(actionFileBytes);
}
DownloadRequest expectedRequest1 =
new DownloadRequest.Builder(
/* id= */ "http://www.test.com/1/manifest.mpd",
Uri.parse("http://www.test.com/1/manifest.mpd"))
.setMimeType(MimeTypes.APPLICATION_MPD)
.build();
DownloadRequest expectedRequest2 =
new DownloadRequest.Builder(
/* id= */ "http://www.test.com/2/manifest.mpd",
Uri.parse("http://www.test.com/2/manifest.mpd"))
.setMimeType(MimeTypes.APPLICATION_MPD)
.setStreamKeys(
ImmutableList.of(
new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0),
new StreamKey(/* groupIndex= */ 1, /* trackIndex= */ 1)))
.setData(new byte[] {0, 1, 2, 3})
.build();
ActionFileUpgradeUtil.upgradeAndDelete(
tempFile,
/* downloadIdProvider= */ null,
downloadIndex,
/* deleteOnFailure= */ true,
/* addNewDownloadsAsCompleted= */ false);
assertThat(tempFile.exists()).isFalse();
assertDownloadIndexContainsRequest(expectedRequest1, Download.STATE_QUEUED);
assertDownloadIndexContainsRequest(expectedRequest2, Download.STATE_QUEUED);
}
@Test
public void upgradeAndDelete_hlsActionFile_createsDownloads() throws IOException {
byte[] actionFileBytes =
TestUtil.getByteArray(
ApplicationProvider.getApplicationContext(),
"media/offline/action_file_for_download_index_upgrade_hls.exi");
try (FileOutputStream output = new FileOutputStream(tempFile)) {
output.write(actionFileBytes);
}
DownloadRequest expectedRequest1 =
new DownloadRequest.Builder(
/* id= */ "http://www.test.com/1/manifest.m3u8",
Uri.parse("http://www.test.com/1/manifest.m3u8"))
.setMimeType(MimeTypes.APPLICATION_M3U8)
.build();
DownloadRequest expectedRequest2 =
new DownloadRequest.Builder(
/* id= */ "http://www.test.com/2/manifest.m3u8",
Uri.parse("http://www.test.com/2/manifest.m3u8"))
.setMimeType(MimeTypes.APPLICATION_M3U8)
.setStreamKeys(
ImmutableList.of(
new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0),
new StreamKey(/* groupIndex= */ 1, /* trackIndex= */ 1)))
.setData(new byte[] {0, 1, 2, 3})
.build();
ActionFileUpgradeUtil.upgradeAndDelete(
tempFile,
/* downloadIdProvider= */ null,
downloadIndex,
/* deleteOnFailure= */ true,
/* addNewDownloadsAsCompleted= */ false);
assertThat(tempFile.exists()).isFalse();
assertDownloadIndexContainsRequest(expectedRequest1, Download.STATE_QUEUED);
assertDownloadIndexContainsRequest(expectedRequest2, Download.STATE_QUEUED);
}
@Test
public void upgradeAndDelete_smoothStreamingActionFile_createsDownloads() throws IOException {
byte[] actionFileBytes =
TestUtil.getByteArray(
ApplicationProvider.getApplicationContext(),
"media/offline/action_file_for_download_index_upgrade_ss.exi");
try (FileOutputStream output = new FileOutputStream(tempFile)) {
output.write(actionFileBytes);
}
DownloadRequest expectedRequest1 =
new DownloadRequest.Builder(
/* id= */ "http://www.test.com/1/video.ism/manifest",
Uri.parse("http://www.test.com/1/video.ism/manifest"))
.setMimeType(MimeTypes.APPLICATION_SS)
.build();
DownloadRequest expectedRequest2 =
new DownloadRequest.Builder(
/* id= */ "http://www.test.com/2/video.ism/manifest",
Uri.parse("http://www.test.com/2/video.ism/manifest"))
.setMimeType(MimeTypes.APPLICATION_SS)
.setStreamKeys(
ImmutableList.of(
new StreamKey(/* groupIndex= */ 0, /* trackIndex= */ 0),
new StreamKey(/* groupIndex= */ 1, /* trackIndex= */ 1)))
.setData(new byte[] {0, 1, 2, 3})
.build();
ActionFileUpgradeUtil.upgradeAndDelete(
tempFile,
/* downloadIdProvider= */ null,
downloadIndex,
/* deleteOnFailure= */ true,
/* addNewDownloadsAsCompleted= */ false);
assertThat(tempFile.exists()).isFalse();
assertDownloadIndexContainsRequest(expectedRequest1, Download.STATE_QUEUED);
assertDownloadIndexContainsRequest(expectedRequest2, Download.STATE_QUEUED);
}
@Test
public void mergeRequest_nonExistingDownload_createsNewDownload() throws IOException {
DownloadRequest request =
new DownloadRequest.Builder(/* id= */ "id", Uri.parse("https://www.test.com/download"))
.setStreamKeys(
ImmutableList.of(
new StreamKey(/* periodIndex= */ 0, /* groupIndex= */ 1, /* trackIndex= */ 2),
new StreamKey(/* periodIndex= */ 3, /* groupIndex= */ 4, /* trackIndex= */ 5)))
.setKeySetId(new byte[] {1, 2, 3, 4})
.setCustomCacheKey("key123")
.setData(new byte[] {1, 2, 3, 4})
.build();
ActionFileUpgradeUtil.mergeRequest(
request, downloadIndex, /* addNewDownloadAsCompleted= */ false, NOW_MS);
assertDownloadIndexContainsRequest(request, Download.STATE_QUEUED);
}
@Test
public void mergeRequest_existingDownload_createsMergedDownload() throws IOException {
StreamKey streamKey1 =
new StreamKey(/* periodIndex= */ 3, /* groupIndex= */ 4, /* trackIndex= */ 5);
StreamKey streamKey2 =
new StreamKey(/* periodIndex= */ 0, /* groupIndex= */ 1, /* trackIndex= */ 2);
DownloadRequest request1 =
new DownloadRequest.Builder(/* id= */ "id", Uri.parse("https://www.test.com/download1"))
.setStreamKeys(ImmutableList.of(streamKey1))
.setKeySetId(new byte[] {1, 2, 3, 4})
.setCustomCacheKey("key123")
.setData(new byte[] {1, 2, 3, 4})
.build();
DownloadRequest request2 =
new DownloadRequest.Builder(/* id= */ "id", Uri.parse("https://www.test.com/download2"))
.setMimeType(MimeTypes.APPLICATION_MP4)
.setStreamKeys(ImmutableList.of(streamKey2))
.setKeySetId(new byte[] {5, 4, 3, 2, 1})
.setCustomCacheKey("key345")
.setData(new byte[] {5, 4, 3, 2, 1})
.build();
ActionFileUpgradeUtil.mergeRequest(
request1, downloadIndex, /* addNewDownloadAsCompleted= */ false, NOW_MS);
ActionFileUpgradeUtil.mergeRequest(
request2, downloadIndex, /* addNewDownloadAsCompleted= */ false, NOW_MS);
Download download = downloadIndex.getDownload(request2.id);
assertThat(download).isNotNull();
assertThat(download.request.mimeType).isEqualTo(MimeTypes.APPLICATION_MP4);
assertThat(download.request.customCacheKey).isEqualTo(request2.customCacheKey);
assertThat(download.request.data).isEqualTo(request2.data);
assertThat(download.request.uri).isEqualTo(request2.uri);
assertThat(download.request.streamKeys).containsExactly(streamKey1, streamKey2);
assertThat(download.request.keySetId).isEqualTo(request2.keySetId);
assertThat(download.state).isEqualTo(Download.STATE_QUEUED);
}
@Test
public void mergeRequest_addNewDownloadAsCompleted() throws IOException {
StreamKey streamKey1 =
new StreamKey(/* periodIndex= */ 3, /* groupIndex= */ 4, /* trackIndex= */ 5);
StreamKey streamKey2 =
new StreamKey(/* periodIndex= */ 0, /* groupIndex= */ 1, /* trackIndex= */ 2);
DownloadRequest request1 =
new DownloadRequest.Builder(/* id= */ "id1", Uri.parse("https://www.test.com/download1"))
.setStreamKeys(ImmutableList.of(streamKey1))
.setKeySetId(new byte[] {1, 2, 3, 4})
.setCustomCacheKey("key123")
.setData(new byte[] {1, 2, 3, 4})
.build();
DownloadRequest request2 =
new DownloadRequest.Builder(/* id= */ "id2", Uri.parse("https://www.test.com/download2"))
.setStreamKeys(ImmutableList.of(streamKey2))
.setKeySetId(new byte[] {5, 4, 3, 2, 1})
.setCustomCacheKey("key456")
.setData(new byte[] {5, 4, 3, 2, 1})
.build();
ActionFileUpgradeUtil.mergeRequest(
request1, downloadIndex, /* addNewDownloadAsCompleted= */ false, NOW_MS);
// Merging existing download, keeps it queued.
ActionFileUpgradeUtil.mergeRequest(
request1, downloadIndex, /* addNewDownloadAsCompleted= */ true, NOW_MS);
assertThat(downloadIndex.getDownload(request1.id).state).isEqualTo(Download.STATE_QUEUED);
// New download is merged as completed.
ActionFileUpgradeUtil.mergeRequest(
request2, downloadIndex, /* addNewDownloadAsCompleted= */ true, NOW_MS);
assertThat(downloadIndex.getDownload(request2.id).state).isEqualTo(Download.STATE_COMPLETED);
}
private void assertDownloadIndexContainsRequest(DownloadRequest request, int state)
throws IOException {
Download download = downloadIndex.getDownload(request.id);
assertThat(download.request).isEqualTo(request);
assertThat(download.state).isEqualTo(state);
}
}

View File

@ -41,8 +41,7 @@ import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
/** Unit tests for {@link ActionFile}. */ /** Unit tests for {@link ProgressiveDownloader}. */
@SuppressWarnings("deprecation")
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class ProgressiveDownloaderTest { public class ProgressiveDownloaderTest {