mirror of
https://github.com/androidx/media.git
synced 2025-05-04 06:00:37 +08:00
Don't use InputStream.available in ContentDataSource
Issue: #3426 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=174700804
This commit is contained in:
parent
585e70c139
commit
e6e75a536a
@ -30,14 +30,14 @@ public final class AssetDataSourceTest extends InstrumentationTestCase {
|
||||
AssetDataSource dataSource = new AssetDataSource(getInstrumentation().getContext());
|
||||
DataSpec dataSpec = new DataSpec(Uri.parse("file:///android_asset/" + DATA_PATH));
|
||||
TestUtil.assertDataSourceContent(dataSource, dataSpec,
|
||||
TestUtil.getByteArray(getInstrumentation(), DATA_PATH));
|
||||
TestUtil.getByteArray(getInstrumentation(), DATA_PATH), true);
|
||||
}
|
||||
|
||||
public void testReadAssetUri() throws Exception {
|
||||
AssetDataSource dataSource = new AssetDataSource(getInstrumentation().getContext());
|
||||
DataSpec dataSpec = new DataSpec(Uri.parse("asset:///" + DATA_PATH));
|
||||
TestUtil.assertDataSourceContent(dataSource, dataSpec,
|
||||
TestUtil.getByteArray(getInstrumentation(), DATA_PATH));
|
||||
TestUtil.getByteArray(getInstrumentation(), DATA_PATH), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,17 +15,22 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.upstream;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.res.AssetFileDescriptor;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.test.InstrumentationTestCase;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
@ -37,23 +42,33 @@ public final class ContentDataSourceTest extends InstrumentationTestCase {
|
||||
private static final String AUTHORITY = "com.google.android.exoplayer2.core.test";
|
||||
private static final String DATA_PATH = "binary/1024_incrementing_bytes.mp3";
|
||||
|
||||
public void testReadValidUri() throws Exception {
|
||||
ContentDataSource dataSource = new ContentDataSource(getInstrumentation().getContext());
|
||||
Uri contentUri = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(AUTHORITY)
|
||||
.path(DATA_PATH).build();
|
||||
DataSpec dataSpec = new DataSpec(contentUri);
|
||||
TestUtil.assertDataSourceContent(dataSource, dataSpec,
|
||||
TestUtil.getByteArray(getInstrumentation(), DATA_PATH));
|
||||
public void testRead() throws Exception {
|
||||
assertData(getInstrumentation(), 0, C.LENGTH_UNSET, false);
|
||||
}
|
||||
|
||||
public void testReadPipeMode() throws Exception {
|
||||
assertData(getInstrumentation(), 0, C.LENGTH_UNSET, true);
|
||||
}
|
||||
|
||||
public void testReadFixedLength() throws Exception {
|
||||
assertData(getInstrumentation(), 0, 100, false);
|
||||
}
|
||||
|
||||
public void testReadFromOffsetToEndOfInput() throws Exception {
|
||||
assertData(getInstrumentation(), 1, C.LENGTH_UNSET, false);
|
||||
}
|
||||
|
||||
public void testReadFromOffsetToEndOfInputPipeMode() throws Exception {
|
||||
assertData(getInstrumentation(), 1, C.LENGTH_UNSET, true);
|
||||
}
|
||||
|
||||
public void testReadFromOffsetFixedLength() throws Exception {
|
||||
assertData(getInstrumentation(), 1, 100, false);
|
||||
}
|
||||
|
||||
public void testReadInvalidUri() throws Exception {
|
||||
ContentDataSource dataSource = new ContentDataSource(getInstrumentation().getContext());
|
||||
Uri contentUri = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(AUTHORITY)
|
||||
.build();
|
||||
Uri contentUri = TestContentProvider.buildUri("does/not.exist", false);
|
||||
DataSpec dataSpec = new DataSpec(contentUri);
|
||||
try {
|
||||
dataSource.open(dataSpec);
|
||||
@ -66,18 +81,16 @@ public final class ContentDataSourceTest extends InstrumentationTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public void testReadFromOffsetToEndOfInput() throws Exception {
|
||||
ContentDataSource dataSource = new ContentDataSource(getInstrumentation().getContext());
|
||||
Uri contentUri = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(AUTHORITY)
|
||||
.path(DATA_PATH).build();
|
||||
private static void assertData(Instrumentation instrumentation, int offset, int length,
|
||||
boolean pipeMode) throws IOException {
|
||||
Uri contentUri = TestContentProvider.buildUri(DATA_PATH, pipeMode);
|
||||
ContentDataSource dataSource = new ContentDataSource(instrumentation.getContext());
|
||||
try {
|
||||
int testOffset = 1;
|
||||
DataSpec dataSpec = new DataSpec(contentUri, testOffset, C.LENGTH_UNSET, null);
|
||||
byte[] completeData = TestUtil.getByteArray(getInstrumentation(), DATA_PATH);
|
||||
byte[] expectedData = Arrays.copyOfRange(completeData, testOffset, completeData.length);
|
||||
TestUtil.assertDataSourceContent(dataSource, dataSpec, expectedData);
|
||||
DataSpec dataSpec = new DataSpec(contentUri, offset, length, null);
|
||||
byte[] completeData = TestUtil.getByteArray(instrumentation, DATA_PATH);
|
||||
byte[] expectedData = Arrays.copyOfRange(completeData, offset,
|
||||
length == C.LENGTH_UNSET ? completeData.length : offset + length);
|
||||
TestUtil.assertDataSourceContent(dataSource, dataSpec, expectedData, !pipeMode);
|
||||
} finally {
|
||||
dataSource.close();
|
||||
}
|
||||
@ -86,7 +99,21 @@ public final class ContentDataSourceTest extends InstrumentationTestCase {
|
||||
/**
|
||||
* A {@link ContentProvider} for the test.
|
||||
*/
|
||||
public static final class TestContentProvider extends ContentProvider {
|
||||
public static final class TestContentProvider extends ContentProvider
|
||||
implements ContentProvider.PipeDataWriter<Object> {
|
||||
|
||||
private static final String PARAM_PIPE_MODE = "pipe-mode";
|
||||
|
||||
public static Uri buildUri(String filePath, boolean pipeMode) {
|
||||
Uri.Builder builder = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(AUTHORITY)
|
||||
.path(filePath);
|
||||
if (pipeMode) {
|
||||
builder.appendQueryParameter(TestContentProvider.PARAM_PIPE_MODE, "1");
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreate() {
|
||||
@ -106,7 +133,14 @@ public final class ContentDataSourceTest extends InstrumentationTestCase {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return getContext().getAssets().openFd(uri.getPath().replaceFirst("/", ""));
|
||||
String fileName = getFileName(uri);
|
||||
boolean pipeMode = uri.getQueryParameter(PARAM_PIPE_MODE) != null;
|
||||
if (pipeMode) {
|
||||
ParcelFileDescriptor fileDescriptor = openPipeHelper(uri, null, null, null, this);
|
||||
return new AssetFileDescriptor(fileDescriptor, 0, C.LENGTH_UNSET);
|
||||
} else {
|
||||
return getContext().getAssets().openFd(fileName);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
FileNotFoundException exception = new FileNotFoundException(e.getMessage());
|
||||
exception.initCause(e);
|
||||
@ -125,15 +159,31 @@ public final class ContentDataSourceTest extends InstrumentationTestCase {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int delete(@NonNull Uri uri, String selection,
|
||||
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(@NonNull Uri uri, ContentValues values, String selection,
|
||||
String[] selectionArgs) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int update(@NonNull Uri uri, ContentValues values,
|
||||
String selection, String[] selectionArgs) {
|
||||
throw new UnsupportedOperationException();
|
||||
public void writeDataToPipe(@NonNull ParcelFileDescriptor output, @NonNull Uri uri,
|
||||
@NonNull String mimeType, @Nullable Bundle opts, @Nullable Object args) {
|
||||
try {
|
||||
byte[] data = TestUtil.getByteArray(getContext(), getFileName(uri));
|
||||
FileOutputStream outputStream = new FileOutputStream(output.getFileDescriptor());
|
||||
outputStream.write(data);
|
||||
outputStream.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error writing to pipe", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getFileName(Uri uri) {
|
||||
return uri.getPath().replaceFirst("/", "");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ import java.io.EOFException;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
/**
|
||||
* A {@link DataSource} for reading from a content URI.
|
||||
@ -47,7 +47,7 @@ public final class ContentDataSource implements DataSource {
|
||||
|
||||
private Uri uri;
|
||||
private AssetFileDescriptor assetFileDescriptor;
|
||||
private InputStream inputStream;
|
||||
private FileInputStream inputStream;
|
||||
private long bytesRemaining;
|
||||
private boolean opened;
|
||||
|
||||
@ -88,14 +88,11 @@ public final class ContentDataSource implements DataSource {
|
||||
} else {
|
||||
long assetFileDescriptorLength = assetFileDescriptor.getLength();
|
||||
if (assetFileDescriptorLength == AssetFileDescriptor.UNKNOWN_LENGTH) {
|
||||
// The asset must extend to the end of the file.
|
||||
bytesRemaining = inputStream.available();
|
||||
if (bytesRemaining == 0) {
|
||||
// FileInputStream.available() returns 0 if the remaining length cannot be determined,
|
||||
// or if it's greater than Integer.MAX_VALUE. We don't know the true length in either
|
||||
// case, so treat as unbounded.
|
||||
bytesRemaining = C.LENGTH_UNSET;
|
||||
}
|
||||
// The asset must extend to the end of the file. If FileInputStream.getChannel().size()
|
||||
// returns 0 then the remaining length cannot be determined.
|
||||
FileChannel channel = inputStream.getChannel();
|
||||
long channelSize = channel.size();
|
||||
bytesRemaining = channelSize == 0 ? C.LENGTH_UNSET : channelSize - channel.position();
|
||||
} else {
|
||||
bytesRemaining = assetFileDescriptorLength - skipped;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
package com.google.android.exoplayer2.testutil;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.content.Context;
|
||||
import android.test.MoreAsserts;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
@ -121,12 +122,20 @@ public class TestUtil {
|
||||
|
||||
public static byte[] getByteArray(Instrumentation instrumentation, String fileName)
|
||||
throws IOException {
|
||||
return Util.toByteArray(getInputStream(instrumentation, fileName));
|
||||
return getByteArray(instrumentation.getContext(), fileName);
|
||||
}
|
||||
|
||||
public static byte[] getByteArray(Context context, String fileName) throws IOException {
|
||||
return Util.toByteArray(getInputStream(context, fileName));
|
||||
}
|
||||
|
||||
public static InputStream getInputStream(Instrumentation instrumentation, String fileName)
|
||||
throws IOException {
|
||||
return instrumentation.getContext().getResources().getAssets().open(fileName);
|
||||
return getInputStream(instrumentation.getContext(), fileName);
|
||||
}
|
||||
|
||||
public static InputStream getInputStream(Context context, String fileName) throws IOException {
|
||||
return context.getResources().getAssets().open(fileName);
|
||||
}
|
||||
|
||||
public static String getString(Instrumentation instrumentation, String fileName)
|
||||
@ -167,13 +176,15 @@ public class TestUtil {
|
||||
* @param dataSource The {@link DataSource} through which to read.
|
||||
* @param dataSpec The {@link DataSpec} to use when opening the {@link DataSource}.
|
||||
* @param expectedData The expected data.
|
||||
* @param expectKnownLength Whether to assert that {@link DataSource#open} returns the expected
|
||||
* data length. If false then it's asserted that {@link C#LENGTH_UNSET} is returned.
|
||||
* @throws IOException If an error occurs reading fom the {@link DataSource}.
|
||||
*/
|
||||
public static void assertDataSourceContent(DataSource dataSource, DataSpec dataSpec,
|
||||
byte[] expectedData) throws IOException {
|
||||
byte[] expectedData, boolean expectKnownLength) throws IOException {
|
||||
try {
|
||||
long length = dataSource.open(dataSpec);
|
||||
Assert.assertEquals(expectedData.length, length);
|
||||
Assert.assertEquals(expectKnownLength ? expectedData.length : C.LENGTH_UNSET, length);
|
||||
byte[] readData = TestUtil.readToEnd(dataSource);
|
||||
MoreAsserts.assertEquals(expectedData, readData);
|
||||
} finally {
|
||||
|
Loading…
x
Reference in New Issue
Block a user