mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Add OkHttp extension to V2.
------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=118775995
This commit is contained in:
parent
b041b72bae
commit
e4d815d164
7 changed files with 508 additions and 0 deletions
9
extensions/okhttp/README.md
Normal file
9
extensions/okhttp/README.md
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# ExoPlayer OkHttp Extension #
|
||||||
|
|
||||||
|
## Description ##
|
||||||
|
|
||||||
|
The OkHttp Extension is an [HttpDataSource][] implementation using Square's [OkHttp][].
|
||||||
|
|
||||||
|
[HttpDataSource]: https://google.github.io/ExoPlayer/doc/reference/com/google/android/exoplayer/upstream/HttpDataSource.html
|
||||||
|
[OkHttp]: https://square.github.io/okhttp/
|
||||||
|
|
||||||
42
extensions/okhttp/build.gradle
Normal file
42
extensions/okhttp/build.gradle
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright (C) 2014 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.
|
||||||
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 23
|
||||||
|
buildToolsVersion "23.0.1"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion 9
|
||||||
|
targetSdkVersion 23
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile project(':library')
|
||||||
|
compile('com.squareup.okhttp3:okhttp:+') {
|
||||||
|
exclude group: 'org.json'
|
||||||
|
}
|
||||||
|
}
|
||||||
10
extensions/okhttp/src/main/.classpath
Normal file
10
extensions/okhttp/src/main/.classpath
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
|
||||||
|
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
|
||||||
|
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
|
||||||
|
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/ExoPlayerLib"/>
|
||||||
|
<classpathentry kind="src" path="java"/>
|
||||||
|
<classpathentry kind="src" path="gen"/>
|
||||||
|
<classpathentry kind="output" path="bin/classes"/>
|
||||||
|
</classpath>
|
||||||
33
extensions/okhttp/src/main/.project
Normal file
33
extensions/okhttp/src/main/.project
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>ExoPlayerExt-OkHttp</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
22
extensions/okhttp/src/main/AndroidManifest.xml
Normal file
22
extensions/okhttp/src/main/AndroidManifest.xml
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Copyright (C) 2014 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.google.android.exoplayer.ext.okhttp">
|
||||||
|
|
||||||
|
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="23"/>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
|
|
@ -0,0 +1,376 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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.exoplayer.ext.okhttp;
|
||||||
|
|
||||||
|
import com.google.android.exoplayer.C;
|
||||||
|
import com.google.android.exoplayer.upstream.DataSpec;
|
||||||
|
import com.google.android.exoplayer.upstream.HttpDataSource;
|
||||||
|
import com.google.android.exoplayer.upstream.TransferListener;
|
||||||
|
import com.google.android.exoplayer.util.Assertions;
|
||||||
|
import com.google.android.exoplayer.util.Predicate;
|
||||||
|
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import okhttp3.CacheControl;
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
|
import okhttp3.MediaType;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.RequestBody;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
import java.io.EOFException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InterruptedIOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link HttpDataSource} that delegates to Square's {@link OkHttpClient}.
|
||||||
|
*/
|
||||||
|
public class OkHttpDataSource implements HttpDataSource {
|
||||||
|
|
||||||
|
private static final AtomicReference<byte[]> skipBufferReference = new AtomicReference<>();
|
||||||
|
|
||||||
|
private final OkHttpClient okHttpClient;
|
||||||
|
private final String userAgent;
|
||||||
|
private final Predicate<String> contentTypePredicate;
|
||||||
|
private final TransferListener listener;
|
||||||
|
private final CacheControl cacheControl;
|
||||||
|
private final HashMap<String, String> requestProperties;
|
||||||
|
|
||||||
|
private DataSpec dataSpec;
|
||||||
|
private Response response;
|
||||||
|
private InputStream responseByteStream;
|
||||||
|
private boolean opened;
|
||||||
|
|
||||||
|
private long bytesToSkip;
|
||||||
|
private long bytesToRead;
|
||||||
|
|
||||||
|
private long bytesSkipped;
|
||||||
|
private long bytesRead;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param client An {@link OkHttpClient} for use by the source.
|
||||||
|
* @param userAgent The User-Agent string that should be used.
|
||||||
|
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
|
||||||
|
* predicate then a
|
||||||
|
* {@link com.google.android.exoplayer.upstream.HttpDataSource.InvalidContentTypeException} is
|
||||||
|
* thrown from {@link #open(DataSpec)}.
|
||||||
|
*/
|
||||||
|
public OkHttpDataSource(OkHttpClient client, String userAgent,
|
||||||
|
Predicate<String> contentTypePredicate) {
|
||||||
|
this(client, userAgent, contentTypePredicate, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param client An {@link OkHttpClient} for use by the source.
|
||||||
|
* @param userAgent The User-Agent string that should be used.
|
||||||
|
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
|
||||||
|
* predicate then a
|
||||||
|
* {@link com.google.android.exoplayer.upstream.HttpDataSource.InvalidContentTypeException} is
|
||||||
|
* thrown from {@link #open(DataSpec)}.
|
||||||
|
* @param listener An optional listener.
|
||||||
|
*/
|
||||||
|
public OkHttpDataSource(OkHttpClient client, String userAgent,
|
||||||
|
Predicate<String> contentTypePredicate, TransferListener listener) {
|
||||||
|
this(client, userAgent, contentTypePredicate, listener, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param client An {@link OkHttpClient} for use by the source.
|
||||||
|
* @param userAgent The User-Agent string that should be used.
|
||||||
|
* @param contentTypePredicate An optional {@link Predicate}. If a content type is rejected by the
|
||||||
|
* predicate then a
|
||||||
|
* {@link com.google.android.exoplayer.upstream.HttpDataSource.InvalidContentTypeException} is
|
||||||
|
* thrown from {@link #open(DataSpec)}.
|
||||||
|
* @param listener An optional listener.
|
||||||
|
* @param cacheControl An optional {@link CacheControl} which sets all requests' Cache-Control
|
||||||
|
* header. For example, you could force the network response for all requests.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public OkHttpDataSource(OkHttpClient client, String userAgent,
|
||||||
|
Predicate<String> contentTypePredicate, TransferListener listener,
|
||||||
|
CacheControl cacheControl) {
|
||||||
|
this.okHttpClient = Assertions.checkNotNull(client);
|
||||||
|
this.userAgent = Assertions.checkNotEmpty(userAgent);
|
||||||
|
this.contentTypePredicate = contentTypePredicate;
|
||||||
|
this.listener = listener;
|
||||||
|
this.cacheControl = cacheControl;
|
||||||
|
this.requestProperties = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Uri getUri() {
|
||||||
|
return response == null ? null : Uri.parse(response.request().url().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<String>> getResponseHeaders() {
|
||||||
|
return response == null ? null : response.headers().toMultimap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRequestProperty(String name, String value) {
|
||||||
|
Assertions.checkNotNull(name);
|
||||||
|
Assertions.checkNotNull(value);
|
||||||
|
synchronized (requestProperties) {
|
||||||
|
requestProperties.put(name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearRequestProperty(String name) {
|
||||||
|
Assertions.checkNotNull(name);
|
||||||
|
synchronized (requestProperties) {
|
||||||
|
requestProperties.remove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearAllRequestProperties() {
|
||||||
|
synchronized (requestProperties) {
|
||||||
|
requestProperties.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long open(DataSpec dataSpec) throws HttpDataSourceException {
|
||||||
|
this.dataSpec = dataSpec;
|
||||||
|
this.bytesRead = 0;
|
||||||
|
this.bytesSkipped = 0;
|
||||||
|
Request request = makeRequest(dataSpec);
|
||||||
|
try {
|
||||||
|
response = okHttpClient.newCall(request).execute();
|
||||||
|
responseByteStream = response.body().byteStream();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new HttpDataSourceException("Unable to connect to " + dataSpec.uri.toString(), e,
|
||||||
|
dataSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
int responseCode = response.code();
|
||||||
|
|
||||||
|
// Check for a valid response code.
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
Map<String, List<String>> headers = request.headers().toMultimap();
|
||||||
|
closeConnectionQuietly();
|
||||||
|
throw new InvalidResponseCodeException(responseCode, headers, dataSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for a valid content type.
|
||||||
|
MediaType mediaType = response.body().contentType();
|
||||||
|
String contentType = mediaType != null ? mediaType.toString() : null;
|
||||||
|
if (contentTypePredicate != null && !contentTypePredicate.evaluate(contentType)) {
|
||||||
|
closeConnectionQuietly();
|
||||||
|
throw new InvalidContentTypeException(contentType, dataSpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we requested a range starting from a non-zero position and received a 200 rather than a
|
||||||
|
// 206, then the server does not support partial requests. We'll need to manually skip to the
|
||||||
|
// requested position.
|
||||||
|
bytesToSkip = responseCode == 200 && dataSpec.position != 0 ? dataSpec.position : 0;
|
||||||
|
|
||||||
|
// Determine the length of the data to be read, after skipping.
|
||||||
|
long contentLength = response.body().contentLength();
|
||||||
|
bytesToRead = dataSpec.length != C.LENGTH_UNBOUNDED ? dataSpec.length
|
||||||
|
: contentLength != -1 ? contentLength - bytesToSkip
|
||||||
|
: C.LENGTH_UNBOUNDED;
|
||||||
|
|
||||||
|
opened = true;
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onTransferStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesToRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] buffer, int offset, int readLength) throws HttpDataSourceException {
|
||||||
|
try {
|
||||||
|
skipInternal();
|
||||||
|
return readInternal(buffer, offset, readLength);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new HttpDataSourceException(e, dataSpec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws HttpDataSourceException {
|
||||||
|
if (opened) {
|
||||||
|
opened = false;
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onTransferEnd();
|
||||||
|
}
|
||||||
|
closeConnectionQuietly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that have been skipped since the most recent call to
|
||||||
|
* {@link #open(DataSpec)}.
|
||||||
|
*
|
||||||
|
* @return The number of bytes skipped.
|
||||||
|
*/
|
||||||
|
protected final long bytesSkipped() {
|
||||||
|
return bytesSkipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that have been read since the most recent call to
|
||||||
|
* {@link #open(DataSpec)}.
|
||||||
|
*
|
||||||
|
* @return The number of bytes read.
|
||||||
|
*/
|
||||||
|
protected final long bytesRead() {
|
||||||
|
return bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes that are still to be read for the current {@link DataSpec}.
|
||||||
|
* <p>
|
||||||
|
* If the total length of the data being read is known, then this length minus {@code bytesRead()}
|
||||||
|
* is returned. If the total length is unknown, {@link C#LENGTH_UNBOUNDED} is returned.
|
||||||
|
*
|
||||||
|
* @return The remaining length, or {@link C#LENGTH_UNBOUNDED}.
|
||||||
|
*/
|
||||||
|
protected final long bytesRemaining() {
|
||||||
|
return bytesToRead == C.LENGTH_UNBOUNDED ? bytesToRead : bytesToRead - bytesRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Establishes a connection.
|
||||||
|
*/
|
||||||
|
private Request makeRequest(DataSpec dataSpec) {
|
||||||
|
long position = dataSpec.position;
|
||||||
|
long length = dataSpec.length;
|
||||||
|
boolean allowGzip = (dataSpec.flags & DataSpec.FLAG_ALLOW_GZIP) != 0;
|
||||||
|
|
||||||
|
HttpUrl url = HttpUrl.parse(dataSpec.uri.toString());
|
||||||
|
Request.Builder builder = new Request.Builder().url(url);
|
||||||
|
if (cacheControl != null) {
|
||||||
|
builder.cacheControl(cacheControl);
|
||||||
|
}
|
||||||
|
synchronized (requestProperties) {
|
||||||
|
for (Map.Entry<String, String> property : requestProperties.entrySet()) {
|
||||||
|
builder.addHeader(property.getKey(), property.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(position == 0 && length == C.LENGTH_UNBOUNDED)) {
|
||||||
|
String rangeRequest = "bytes=" + position + "-";
|
||||||
|
if (length != C.LENGTH_UNBOUNDED) {
|
||||||
|
rangeRequest += (position + length - 1);
|
||||||
|
}
|
||||||
|
builder.addHeader("Range", rangeRequest);
|
||||||
|
}
|
||||||
|
builder.addHeader("User-Agent", userAgent);
|
||||||
|
if (!allowGzip) {
|
||||||
|
builder.addHeader("Accept-Encoding", "identity");
|
||||||
|
}
|
||||||
|
if (dataSpec.postBody != null) {
|
||||||
|
builder.post(RequestBody.create(null, dataSpec.postBody));
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skips any bytes that need skipping. Else does nothing.
|
||||||
|
* <p>
|
||||||
|
* This implementation is based roughly on {@code libcore.io.Streams.skipByReading()}.
|
||||||
|
*
|
||||||
|
* @throws InterruptedIOException If the thread is interrupted during the operation.
|
||||||
|
* @throws EOFException If the end of the input stream is reached before the bytes are skipped.
|
||||||
|
*/
|
||||||
|
private void skipInternal() throws IOException {
|
||||||
|
if (bytesSkipped == bytesToSkip) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire the shared skip buffer.
|
||||||
|
byte[] skipBuffer = skipBufferReference.getAndSet(null);
|
||||||
|
if (skipBuffer == null) {
|
||||||
|
skipBuffer = new byte[4096];
|
||||||
|
}
|
||||||
|
|
||||||
|
while (bytesSkipped != bytesToSkip) {
|
||||||
|
int readLength = (int) Math.min(bytesToSkip - bytesSkipped, skipBuffer.length);
|
||||||
|
int read = responseByteStream.read(skipBuffer, 0, readLength);
|
||||||
|
if (Thread.interrupted()) {
|
||||||
|
throw new InterruptedIOException();
|
||||||
|
}
|
||||||
|
if (read == -1) {
|
||||||
|
throw new EOFException();
|
||||||
|
}
|
||||||
|
bytesSkipped += read;
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onBytesTransferred(read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the shared skip buffer.
|
||||||
|
skipBufferReference.set(skipBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads up to {@code length} bytes of data and stores them into {@code buffer}, starting at
|
||||||
|
* index {@code offset}.
|
||||||
|
* <p>
|
||||||
|
* This method blocks until at least one byte of data can be read, the end of the opened range is
|
||||||
|
* detected, or an exception is thrown.
|
||||||
|
*
|
||||||
|
* @param buffer The buffer into which the read data should be stored.
|
||||||
|
* @param offset The start offset into {@code buffer} at which data should be written.
|
||||||
|
* @param readLength The maximum number of bytes to read.
|
||||||
|
* @return The number of bytes read, or {@link C#RESULT_END_OF_INPUT} if the end of the opened
|
||||||
|
* range is reached.
|
||||||
|
* @throws IOException If an error occurs reading from the source.
|
||||||
|
*/
|
||||||
|
private int readInternal(byte[] buffer, int offset, int readLength) throws IOException {
|
||||||
|
readLength = bytesToRead == C.LENGTH_UNBOUNDED ? readLength
|
||||||
|
: (int) Math.min(readLength, bytesToRead - bytesRead);
|
||||||
|
if (readLength == 0) {
|
||||||
|
// We've read all of the requested data.
|
||||||
|
return C.RESULT_END_OF_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read = responseByteStream.read(buffer, offset, readLength);
|
||||||
|
if (read == -1) {
|
||||||
|
if (bytesToRead != C.LENGTH_UNBOUNDED && bytesToRead != bytesRead) {
|
||||||
|
// The server closed the connection having not sent sufficient data.
|
||||||
|
throw new EOFException();
|
||||||
|
}
|
||||||
|
return C.RESULT_END_OF_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytesRead += read;
|
||||||
|
if (listener != null) {
|
||||||
|
listener.onBytesTransferred(read);
|
||||||
|
}
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the current connection quietly, if there is one.
|
||||||
|
*/
|
||||||
|
private void closeConnectionQuietly() {
|
||||||
|
response.body().close();
|
||||||
|
response = null;
|
||||||
|
responseByteStream = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
extensions/okhttp/src/main/project.properties
Normal file
16
extensions/okhttp/src/main/project.properties
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
# This file is automatically generated by Android Tools.
|
||||||
|
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||||
|
#
|
||||||
|
# This file must be checked in Version Control Systems.
|
||||||
|
#
|
||||||
|
# To customize properties used by the Ant build system edit
|
||||||
|
# "ant.properties", and override values to adapt the script to your
|
||||||
|
# project structure.
|
||||||
|
#
|
||||||
|
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||||
|
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||||
|
|
||||||
|
# Project target.
|
||||||
|
target=android-23
|
||||||
|
android.library=true
|
||||||
|
android.library.reference.1=../../../../library/src/main
|
||||||
Loading…
Reference in a new issue