Created
May 14, 2018 21:01
-
-
Save JesusMartinAlonso/967c06e3e6b0e3ca5c66896156d12451 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import android.content.Context; | |
import android.net.Uri; | |
import android.util.Log; | |
import com.android.vending.expansion.zipfile.APKExpansionSupport; | |
import com.android.vending.expansion.zipfile.ZipResourceFile; | |
import com.google.android.exoplayer2.C; | |
import com.google.android.exoplayer2.upstream.DataSource; | |
import com.google.android.exoplayer2.upstream.DataSpec; | |
import com.google.android.exoplayer2.upstream.TransferListener; | |
import java.io.EOFException; | |
import java.io.IOException; | |
import java.io.InputStream; | |
/** | |
* A {@link DataSource} for reading from the APK Expansion file | |
*/ | |
public final class OBBDataSource implements DataSource { | |
/** | |
* Thrown when an {@link IOException} is encountered reading an OBB asset. | |
*/ | |
public static final class OBBDataSourceException extends IOException { | |
public OBBDataSourceException(IOException cause) { | |
super(cause); | |
} | |
} | |
private final TransferListener<? super OBBDataSource> listener; | |
private Uri uri; | |
private InputStream inputStream; | |
private long bytesRemaining; | |
private boolean opened; | |
private Context context; | |
private String TAG = "OBB_DATA_SOURCE"; | |
/** | |
* @param context A context. | |
*/ | |
public OBBDataSource(Context context) { | |
this(context, null); | |
this.context = context; | |
} | |
/** | |
* @param context A context. | |
* @param listener An optional listener. | |
*/ | |
public OBBDataSource(Context context, TransferListener<? super OBBDataSource> listener) { | |
this.context = context; | |
this.listener = listener; | |
} | |
@Override | |
public long open(DataSpec dataSpec) throws OBBDataSourceException { | |
try { | |
uri = dataSpec.uri; | |
String path = uri.getPath(); | |
if (path.startsWith("/android_asset/")) { | |
path = path.substring(15); | |
} else if (path.startsWith("/")) { | |
path = path.substring(1); | |
} | |
inputStream = getInputStreamFromExpansionAPKFile(path); | |
long skipped = inputStream.skip(dataSpec.position); | |
if (skipped < dataSpec.position) { | |
// assetManager.open() returns an AssetInputStream, whose skip() implementation only skips | |
// fewer bytes than requested if the skip is beyond the end of the asset's data. | |
throw new EOFException(); | |
} | |
if (dataSpec.length != C.LENGTH_UNSET) { | |
bytesRemaining = dataSpec.length; | |
} else { | |
bytesRemaining = inputStream.available(); | |
if (bytesRemaining == Integer.MAX_VALUE) { | |
// assetManager.open() returns an AssetInputStream, whose available() implementation | |
// returns Integer.MAX_VALUE if the remaining length is greater than (or equal to) | |
// Integer.MAX_VALUE. We don't know the true length in this case, so treat as unbounded. | |
bytesRemaining = C.LENGTH_UNSET; | |
} | |
} | |
} catch (IOException e) { | |
throw new OBBDataSourceException(e); | |
} | |
opened = true; | |
if (listener != null) { | |
listener.onTransferStart(this, dataSpec); | |
} | |
return bytesRemaining; | |
} | |
@Override | |
public int read(byte[] buffer, int offset, int readLength) throws OBBDataSourceException { | |
if (readLength == 0) { | |
return 0; | |
} else if (bytesRemaining == 0) { | |
return C.RESULT_END_OF_INPUT; | |
} | |
int bytesRead; | |
try { | |
int bytesToRead = bytesRemaining == C.LENGTH_UNSET ? readLength | |
: (int) Math.min(bytesRemaining, readLength); | |
bytesRead = inputStream.read(buffer, offset, bytesToRead); | |
} catch (IOException e) { | |
throw new OBBDataSourceException(e); | |
} | |
if (bytesRead == -1) { | |
if (bytesRemaining != C.LENGTH_UNSET) { | |
// End of stream reached having not read sufficient data. | |
throw new OBBDataSourceException(new EOFException()); | |
} | |
return C.RESULT_END_OF_INPUT; | |
} | |
if (bytesRemaining != C.LENGTH_UNSET) { | |
bytesRemaining -= bytesRead; | |
} | |
if (listener != null) { | |
listener.onBytesTransferred(this, bytesRead); | |
} | |
return bytesRead; | |
} | |
@Override | |
public Uri getUri() { | |
return uri; | |
} | |
@Override | |
public void close() throws OBBDataSourceException { | |
uri = null; | |
try { | |
if (inputStream != null) { | |
inputStream.close(); | |
} | |
} catch (IOException e) { | |
throw new OBBDataSourceException(e); | |
} finally { | |
inputStream = null; | |
if (opened) { | |
opened = false; | |
if (listener != null) { | |
listener.onTransferEnd(this); | |
} | |
} | |
} | |
} | |
private InputStream getInputStreamFromExpansionAPKFile(String fileName){ | |
// Get a ZipResourceFile representing a merger of both the main and patch files | |
try { | |
ZipResourceFile expansionFile = APKExpansionSupport.getAPKExpansionZipFile(context, BuildConfig.OBB_FILE_VERSION , -1); | |
return expansionFile.getInputStream(fileName); | |
} catch (IOException e) { | |
Log.w(TAG, "Failed to find expansion file", e); | |
return null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment