Consolidate builder classes for DataSourceDesc
Test: MediaPlayer2Test MediaPlayer2DrmTest Bug: 128461237 Change-Id: I86a3d43c2ceccf97b64018156aacba6c8b744203
This commit is contained in:
@@ -23706,17 +23706,6 @@ package android.media {
|
||||
method public void onTearDown(@NonNull android.media.AudioTrack);
|
||||
}
|
||||
|
||||
public class CallbackDataSourceDesc extends android.media.DataSourceDesc {
|
||||
method @NonNull public android.media.DataSourceCallback getDataSourceCallback();
|
||||
}
|
||||
|
||||
public static class CallbackDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase<android.media.CallbackDataSourceDesc.Builder> {
|
||||
ctor public CallbackDataSourceDesc.Builder();
|
||||
ctor public CallbackDataSourceDesc.Builder(@Nullable android.media.CallbackDataSourceDesc);
|
||||
method @NonNull public android.media.CallbackDataSourceDesc build();
|
||||
method @NonNull public android.media.CallbackDataSourceDesc.Builder setDataSource(@NonNull android.media.DataSourceCallback);
|
||||
}
|
||||
|
||||
public class CamcorderProfile {
|
||||
method public static android.media.CamcorderProfile get(int);
|
||||
method public static android.media.CamcorderProfile get(int, int);
|
||||
@@ -23783,10 +23772,18 @@ package android.media {
|
||||
field public static final long POSITION_UNKNOWN = 576460752303423L; // 0x20c49ba5e353fL
|
||||
}
|
||||
|
||||
protected static class DataSourceDesc.BuilderBase<T extends android.media.DataSourceDesc.BuilderBase> {
|
||||
method @NonNull public T setEndPosition(long);
|
||||
method @NonNull public T setMediaId(@Nullable String);
|
||||
method @NonNull public T setStartPosition(long);
|
||||
public static final class DataSourceDesc.Builder {
|
||||
ctor public DataSourceDesc.Builder();
|
||||
ctor public DataSourceDesc.Builder(@Nullable android.media.DataSourceDesc);
|
||||
method @NonNull public android.media.DataSourceDesc build();
|
||||
method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.net.Uri);
|
||||
method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.net.Uri, @Nullable java.util.Map<java.lang.String,java.lang.String>, @Nullable java.util.List<java.net.HttpCookie>);
|
||||
method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor);
|
||||
method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor, long, long);
|
||||
method @NonNull public android.media.DataSourceDesc.Builder setDataSource(@NonNull android.media.DataSourceCallback);
|
||||
method @NonNull public android.media.DataSourceDesc.Builder setEndPosition(long);
|
||||
method @NonNull public android.media.DataSourceDesc.Builder setMediaId(@Nullable String);
|
||||
method @NonNull public android.media.DataSourceDesc.Builder setStartPosition(long);
|
||||
}
|
||||
|
||||
public final class DeniedByServerException extends android.media.MediaDrmException {
|
||||
@@ -23991,21 +23988,6 @@ package android.media {
|
||||
field public static final int EULER_Z = 2; // 0x2
|
||||
}
|
||||
|
||||
public class FileDataSourceDesc extends android.media.DataSourceDesc {
|
||||
method public long getLength();
|
||||
method public long getOffset();
|
||||
method @NonNull public android.os.ParcelFileDescriptor getParcelFileDescriptor();
|
||||
field public static final long FD_LENGTH_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL
|
||||
}
|
||||
|
||||
public static class FileDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase<android.media.FileDataSourceDesc.Builder> {
|
||||
ctor public FileDataSourceDesc.Builder();
|
||||
ctor public FileDataSourceDesc.Builder(@Nullable android.media.FileDataSourceDesc);
|
||||
method @NonNull public android.media.FileDataSourceDesc build();
|
||||
method @NonNull public android.media.FileDataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor);
|
||||
method @NonNull public android.media.FileDataSourceDesc.Builder setDataSource(@NonNull android.os.ParcelFileDescriptor, long, long);
|
||||
}
|
||||
|
||||
public abstract class Image implements java.lang.AutoCloseable {
|
||||
method public abstract void close();
|
||||
method public android.graphics.Rect getCropRect();
|
||||
@@ -26639,21 +26621,6 @@ package android.media {
|
||||
ctor public UnsupportedSchemeException(String);
|
||||
}
|
||||
|
||||
public class UriDataSourceDesc extends android.media.DataSourceDesc {
|
||||
method @NonNull public android.content.Context getContext();
|
||||
method @Nullable public java.util.List<java.net.HttpCookie> getCookies();
|
||||
method @Nullable public java.util.Map<java.lang.String,java.lang.String> getHeaders();
|
||||
method @NonNull public android.net.Uri getUri();
|
||||
}
|
||||
|
||||
public static class UriDataSourceDesc.Builder extends android.media.DataSourceDesc.BuilderBase<android.media.UriDataSourceDesc.Builder> {
|
||||
ctor public UriDataSourceDesc.Builder();
|
||||
ctor public UriDataSourceDesc.Builder(@Nullable android.media.UriDataSourceDesc);
|
||||
method @NonNull public android.media.UriDataSourceDesc build();
|
||||
method @NonNull public android.media.UriDataSourceDesc.Builder setDataSource(@NonNull android.content.Context, @NonNull android.net.Uri);
|
||||
method @NonNull public android.media.UriDataSourceDesc.Builder setDataSource(@NonNull android.content.Context, @NonNull android.net.Uri, @Nullable java.util.Map<java.lang.String,java.lang.String>, @Nullable java.util.List<java.net.HttpCookie>);
|
||||
}
|
||||
|
||||
public interface VolumeAutomation {
|
||||
method @NonNull public android.media.VolumeShaper createVolumeShaper(@NonNull android.media.VolumeShaper.Configuration);
|
||||
}
|
||||
|
||||
@@ -1077,6 +1077,17 @@ package android.media {
|
||||
method public android.media.BufferingParams.Builder setResumePlaybackMarkMs(int);
|
||||
}
|
||||
|
||||
public class CallbackDataSourceDesc extends android.media.DataSourceDesc {
|
||||
method @NonNull public android.media.DataSourceCallback getDataSourceCallback();
|
||||
}
|
||||
|
||||
public class FileDataSourceDesc extends android.media.DataSourceDesc {
|
||||
method public long getLength();
|
||||
method public long getOffset();
|
||||
method @NonNull public android.os.ParcelFileDescriptor getParcelFileDescriptor();
|
||||
field public static final long FD_LENGTH_UNKNOWN = 576460752303423487L; // 0x7ffffffffffffffL
|
||||
}
|
||||
|
||||
public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
|
||||
ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int, int, @NonNull android.util.Size);
|
||||
ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint, @NonNull android.util.Size);
|
||||
@@ -1101,6 +1112,12 @@ package android.media {
|
||||
method public android.media.PlaybackParams setAudioStretchMode(int);
|
||||
}
|
||||
|
||||
public class UriDataSourceDesc extends android.media.DataSourceDesc {
|
||||
method @Nullable public java.util.List<java.net.HttpCookie> getCookies();
|
||||
method @Nullable public java.util.Map<java.lang.String,java.lang.String> getHeaders();
|
||||
method @NonNull public android.net.Uri getUri();
|
||||
}
|
||||
|
||||
public static final class VolumeShaper.Configuration.Builder {
|
||||
method @NonNull public android.media.VolumeShaper.Configuration.Builder setOptionFlags(int);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package android.media;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.TestApi;
|
||||
|
||||
/**
|
||||
* Structure of data source descriptor for sources using callback.
|
||||
@@ -26,12 +26,16 @@ import android.annotation.Nullable;
|
||||
* {@link MediaPlayer2#setNextDataSources} to set data source for playback.
|
||||
*
|
||||
* <p>Users should use {@link Builder} to create {@link CallbackDataSourceDesc}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public class CallbackDataSourceDesc extends DataSourceDesc {
|
||||
private DataSourceCallback mDataSourceCallback;
|
||||
|
||||
private CallbackDataSourceDesc() {
|
||||
CallbackDataSourceDesc(String mediaId, long startPositionMs, long endPositionMs,
|
||||
DataSourceCallback dataSourceCallback) {
|
||||
super(mediaId, startPositionMs, endPositionMs);
|
||||
mDataSourceCallback = dataSourceCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,75 +45,4 @@ public class CallbackDataSourceDesc extends DataSourceDesc {
|
||||
public @NonNull DataSourceCallback getDataSourceCallback() {
|
||||
return mDataSourceCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for {@link CallbackDataSourceDesc} objects.
|
||||
* <p> Here is an example where <code>Builder</code> is used to define the
|
||||
* {@link CallbackDataSourceDesc} to be used by a {@link MediaPlayer2} instance:
|
||||
*
|
||||
* <pre class="prettyprint">
|
||||
* CallbackDataSourceDesc newDSD = new CallbackDataSourceDesc.Builder()
|
||||
* .setDataSource(media2DataSource)
|
||||
* .setStartPosition(1000)
|
||||
* .setEndPosition(15000)
|
||||
* .build();
|
||||
* mediaplayer2.setDataSourceDesc(newDSD);
|
||||
* </pre>
|
||||
*/
|
||||
public static class Builder extends BuilderBase<Builder> {
|
||||
private DataSourceCallback mDataSourceCallback;
|
||||
|
||||
/**
|
||||
* Constructs a new Builder with the defaults.
|
||||
*/
|
||||
public Builder() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Builder from a given {@link CallbackDataSourceDesc} instance
|
||||
* @param dsd the {@link CallbackDataSourceDesc} object whose data will be reused
|
||||
* in the new Builder.
|
||||
*/
|
||||
public Builder(@Nullable CallbackDataSourceDesc dsd) {
|
||||
super(dsd);
|
||||
if (dsd == null) {
|
||||
return; // use default
|
||||
}
|
||||
mDataSourceCallback = dsd.mDataSourceCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines all of the fields that have been set and return a new
|
||||
* {@link CallbackDataSourceDesc} object. <code>IllegalStateException</code> will be
|
||||
* thrown if there is conflict between fields.
|
||||
*
|
||||
* @return a new {@link CallbackDataSourceDesc} object
|
||||
*/
|
||||
public @NonNull CallbackDataSourceDesc build() {
|
||||
if (mDataSourceCallback == null) {
|
||||
throw new IllegalStateException(
|
||||
"DataSourceCallback should not be null");
|
||||
}
|
||||
|
||||
CallbackDataSourceDesc dsd = new CallbackDataSourceDesc();
|
||||
super.build(dsd);
|
||||
dsd.mDataSourceCallback = mDataSourceCallback;
|
||||
|
||||
return dsd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source (DataSourceCallback) to use.
|
||||
*
|
||||
* @param dscb the DataSourceCallback for the media to play
|
||||
* @return the same Builder instance.
|
||||
* @throws NullPointerException if dscb is null.
|
||||
*/
|
||||
public @NonNull Builder setDataSource(@NonNull DataSourceCallback dscb) {
|
||||
Media2Utils.checkArgument(dscb != null, "data source cannot be null.");
|
||||
mDataSourceCallback = dscb;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,15 +18,22 @@ package android.media;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.net.Uri;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base class of data source descriptor.
|
||||
* Data source descriptor.
|
||||
*
|
||||
* Used by {@link MediaPlayer2#setDataSource}, {@link MediaPlayer2#setNextDataSource} and
|
||||
* {@link MediaPlayer2#setNextDataSources} to set data source for playback.
|
||||
*
|
||||
* <p>Users should use subclasses' builder to change {@link DataSourceDesc}.
|
||||
*
|
||||
*/
|
||||
public class DataSourceDesc {
|
||||
// intentionally less than long.MAX_VALUE
|
||||
@@ -45,7 +52,10 @@ public class DataSourceDesc {
|
||||
private long mStartPositionMs = 0;
|
||||
private long mEndPositionMs = POSITION_UNKNOWN;
|
||||
|
||||
DataSourceDesc() {
|
||||
DataSourceDesc(String mediaId, long startPositionMs, long endPositionMs) {
|
||||
mMediaId = mediaId;
|
||||
mStartPositionMs = startPositionMs;
|
||||
mEndPositionMs = endPositionMs;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,17 +107,48 @@ public class DataSourceDesc {
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for Builders in the subclasses of {@link DataSourceDesc}.
|
||||
* Builder for {@link DataSourceDesc}.
|
||||
* <p>
|
||||
* Here is an example where <code>Builder</code> is used to define the
|
||||
* {@link DataSourceDesc} to be used by a {@link MediaPlayer2} instance:
|
||||
*
|
||||
* <pre class="prettyprint">
|
||||
* DataSourceDesc newDSD = new DataSourceDesc.Builder()
|
||||
* .setDataSource(context, uri, headers, cookies)
|
||||
* .setStartPosition(1000)
|
||||
* .setEndPosition(15000)
|
||||
* .build();
|
||||
* mediaplayer2.setDataSourceDesc(newDSD);
|
||||
* </pre>
|
||||
*/
|
||||
protected static class BuilderBase<T extends BuilderBase> {
|
||||
public static final class Builder {
|
||||
private static final int SOURCE_TYPE_UNKNOWN = 0;
|
||||
private static final int SOURCE_TYPE_URI = 1;
|
||||
private static final int SOURCE_TYPE_FILE = 2;
|
||||
private static final int SOURCE_TYPE_CALLBACK = 3;
|
||||
|
||||
private int mSourceType = SOURCE_TYPE_UNKNOWN;
|
||||
private String mMediaId;
|
||||
private long mStartPositionMs = 0;
|
||||
private long mEndPositionMs = POSITION_UNKNOWN;
|
||||
|
||||
// For UriDataSourceDesc
|
||||
private Uri mUri;
|
||||
private Map<String, String> mHeader;
|
||||
private List<HttpCookie> mCookies;
|
||||
|
||||
// For FileDataSourceDesc
|
||||
private ParcelFileDescriptor mPFD;
|
||||
private long mOffset = 0;
|
||||
private long mLength = FileDataSourceDesc.FD_LENGTH_UNKNOWN;
|
||||
|
||||
// For CallbackDataSourceDesc
|
||||
private DataSourceCallback mDataSourceCallback;
|
||||
|
||||
/**
|
||||
* Constructs a new BuilderBase with the defaults.
|
||||
*/
|
||||
BuilderBase() {
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -115,33 +156,61 @@ public class DataSourceDesc {
|
||||
* @param dsd the {@link DataSourceDesc} object whose data will be reused
|
||||
* in the new BuilderBase.
|
||||
*/
|
||||
BuilderBase(DataSourceDesc dsd) {
|
||||
public Builder(@Nullable DataSourceDesc dsd) {
|
||||
if (dsd == null) {
|
||||
return;
|
||||
}
|
||||
mMediaId = dsd.mMediaId;
|
||||
mStartPositionMs = dsd.mStartPositionMs;
|
||||
mEndPositionMs = dsd.mEndPositionMs;
|
||||
if (dsd instanceof FileDataSourceDesc) {
|
||||
mSourceType = SOURCE_TYPE_FILE;
|
||||
mPFD = ((FileDataSourceDesc) dsd).getParcelFileDescriptor();
|
||||
mOffset = ((FileDataSourceDesc) dsd).getOffset();
|
||||
mLength = ((FileDataSourceDesc) dsd).getLength();
|
||||
} else if (dsd instanceof UriDataSourceDesc) {
|
||||
mSourceType = SOURCE_TYPE_URI;
|
||||
mUri = ((UriDataSourceDesc) dsd).getUri();
|
||||
mHeader = ((UriDataSourceDesc) dsd).getHeaders();
|
||||
mCookies = ((UriDataSourceDesc) dsd).getCookies();
|
||||
} else if (dsd instanceof CallbackDataSourceDesc) {
|
||||
mSourceType = SOURCE_TYPE_CALLBACK;
|
||||
mDataSourceCallback = ((CallbackDataSourceDesc) dsd).getDataSourceCallback();
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown source type:" + mSourceType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all fields that have been set in the {@link DataSourceDesc} object.
|
||||
* <code>IllegalStateException</code> will be thrown if there is conflict between fields.
|
||||
*
|
||||
* @param dsd an instance of subclass of {@link DataSourceDesc} whose data will be set
|
||||
* @return the same instance of subclass of {@link DataSourceDesc}
|
||||
* @return {@link DataSourceDesc}
|
||||
*/
|
||||
void build(@NonNull DataSourceDesc dsd) {
|
||||
Media2Utils.checkArgument(dsd != null, "dsd cannot be null.");
|
||||
|
||||
@NonNull
|
||||
public DataSourceDesc build() {
|
||||
if (mSourceType == SOURCE_TYPE_UNKNOWN) {
|
||||
throw new IllegalStateException("Source is not set.");
|
||||
}
|
||||
if (mStartPositionMs > mEndPositionMs) {
|
||||
throw new IllegalStateException("Illegal start/end position: "
|
||||
+ mStartPositionMs + " : " + mEndPositionMs);
|
||||
}
|
||||
|
||||
dsd.mMediaId = mMediaId;
|
||||
dsd.mStartPositionMs = mStartPositionMs;
|
||||
dsd.mEndPositionMs = mEndPositionMs;
|
||||
DataSourceDesc desc;
|
||||
if (mSourceType == SOURCE_TYPE_FILE) {
|
||||
desc = new FileDataSourceDesc(
|
||||
mMediaId, mStartPositionMs, mEndPositionMs, mPFD, mOffset, mLength);
|
||||
} else if (mSourceType == SOURCE_TYPE_URI) {
|
||||
desc = new UriDataSourceDesc(
|
||||
mMediaId, mStartPositionMs, mEndPositionMs, mUri, mHeader, mCookies);
|
||||
} else if (mSourceType == SOURCE_TYPE_CALLBACK) {
|
||||
desc = new CallbackDataSourceDesc(
|
||||
mMediaId, mStartPositionMs, mEndPositionMs, mDataSourceCallback);
|
||||
} else {
|
||||
throw new IllegalStateException("Unknown source type:" + mSourceType);
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,9 +219,10 @@ public class DataSourceDesc {
|
||||
* @param mediaId the media Id of this data source
|
||||
* @return the same Builder instance.
|
||||
*/
|
||||
public @NonNull T setMediaId(@Nullable String mediaId) {
|
||||
@NonNull
|
||||
public Builder setMediaId(@Nullable String mediaId) {
|
||||
mMediaId = mediaId;
|
||||
return (T) this;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,12 +233,13 @@ public class DataSourceDesc {
|
||||
* @return the same Builder instance.
|
||||
*
|
||||
*/
|
||||
public @NonNull T setStartPosition(long position) {
|
||||
@NonNull
|
||||
public Builder setStartPosition(long position) {
|
||||
if (position < 0) {
|
||||
position = 0;
|
||||
}
|
||||
mStartPositionMs = position;
|
||||
return (T) this;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,12 +250,155 @@ public class DataSourceDesc {
|
||||
* @param position the end position in milliseconds at which the playback will end
|
||||
* @return the same Builder instance.
|
||||
*/
|
||||
public @NonNull T setEndPosition(long position) {
|
||||
@NonNull
|
||||
public Builder setEndPosition(long position) {
|
||||
if (position < 0) {
|
||||
position = LONG_MAX_TIME_MS;
|
||||
}
|
||||
mEndPositionMs = position;
|
||||
return (T) this;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source as a content Uri.
|
||||
*
|
||||
* @param uri the Content URI of the data you want to play
|
||||
* @return the same Builder instance.
|
||||
* @throws NullPointerException if context or uri is null.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setDataSource(@NonNull Uri uri) {
|
||||
setSourceType(SOURCE_TYPE_URI);
|
||||
Media2Utils.checkArgument(uri != null, "uri cannot be null");
|
||||
mUri = uri;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source as a content Uri.
|
||||
*
|
||||
* To provide cookies for the subsequent HTTP requests, you can install your own default
|
||||
* cookie handler and use other variants of setDataSource APIs instead. Alternatively, you
|
||||
* can use this API to pass the cookies as a list of HttpCookie. If the app has not
|
||||
* installed a CookieHandler already, {@link MediaPlayer2} will create a CookieManager
|
||||
* and populates its CookieStore with the provided cookies when this data source is passed
|
||||
* to {@link MediaPlayer2}. If the app has installed its own handler already, the handler
|
||||
* is required to be of CookieManager type such that {@link MediaPlayer2} can update the
|
||||
* manager’s CookieStore.
|
||||
*
|
||||
* <p><strong>Note</strong> that the cross domain redirection is allowed by default,
|
||||
* but that can be changed with key/value pairs through the headers parameter with
|
||||
* "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to
|
||||
* disallow or allow cross domain redirection.
|
||||
*
|
||||
* @param uri the Content URI of the data you want to play
|
||||
* @param headers the headers to be sent together with the request for the data
|
||||
* The headers must not include cookies. Instead, use the cookies param.
|
||||
* @param cookies the cookies to be sent together with the request
|
||||
* @return the same Builder instance.
|
||||
* @throws NullPointerException if context or uri is null.
|
||||
* @throws IllegalArgumentException if the cookie handler is not of CookieManager type
|
||||
* when cookies are provided.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setDataSource(@NonNull Uri uri, @Nullable Map<String, String> headers,
|
||||
@Nullable List<HttpCookie> cookies) {
|
||||
setSourceType(SOURCE_TYPE_URI);
|
||||
Media2Utils.checkArgument(uri != null, "uri cannot be null");
|
||||
if (cookies != null) {
|
||||
CookieHandler cookieHandler = CookieHandler.getDefault();
|
||||
if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) {
|
||||
throw new IllegalArgumentException(
|
||||
"The cookie handler has to be of CookieManager type "
|
||||
+ "when cookies are provided.");
|
||||
}
|
||||
}
|
||||
|
||||
mUri = uri;
|
||||
if (headers != null) {
|
||||
mHeader = new HashMap<String, String>(headers);
|
||||
}
|
||||
if (cookies != null) {
|
||||
mCookies = new ArrayList<HttpCookie>(cookies);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
|
||||
* seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc}
|
||||
* created by this builder is passed to {@link MediaPlayer2} via
|
||||
* {@link MediaPlayer2#setDataSource},
|
||||
* {@link MediaPlayer2#setNextDataSource} or
|
||||
* {@link MediaPlayer2#setNextDataSources}, MediaPlayer2 will
|
||||
* close the ParcelFileDescriptor.
|
||||
*
|
||||
* @param pfd the ParcelFileDescriptor for the file to play
|
||||
* @return the same Builder instance.
|
||||
* @throws NullPointerException if pfd is null.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setDataSource(@NonNull ParcelFileDescriptor pfd) {
|
||||
setSourceType(SOURCE_TYPE_FILE);
|
||||
Media2Utils.checkArgument(pfd != null, "pfd cannot be null.");
|
||||
mPFD = pfd;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
|
||||
* seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc}
|
||||
* created by this builder is passed to {@link MediaPlayer2} via
|
||||
* {@link MediaPlayer2#setDataSource},
|
||||
* {@link MediaPlayer2#setNextDataSource} or
|
||||
* {@link MediaPlayer2#setNextDataSources}, MediaPlayer2 will
|
||||
* close the ParcelFileDescriptor.
|
||||
*
|
||||
* Any negative number for offset is treated as 0.
|
||||
* Any negative number for length is treated as maximum length of the data source.
|
||||
*
|
||||
* @param pfd the ParcelFileDescriptor for the file to play
|
||||
* @param offset the offset into the file where the data to be played starts, in bytes
|
||||
* @param length the length in bytes of the data to be played
|
||||
* @return the same Builder instance.
|
||||
* @throws NullPointerException if pfd is null.
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setDataSource(
|
||||
@NonNull ParcelFileDescriptor pfd, long offset, long length) {
|
||||
setSourceType(SOURCE_TYPE_FILE);
|
||||
Media2Utils.checkArgument(pfd != null, "pfd cannot be null.");
|
||||
if (offset < 0) {
|
||||
offset = 0;
|
||||
}
|
||||
if (length < 0) {
|
||||
length = FileDataSourceDesc.FD_LENGTH_UNKNOWN;
|
||||
}
|
||||
mPFD = pfd;
|
||||
mOffset = offset;
|
||||
mLength = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source (DataSourceCallback) to use.
|
||||
*
|
||||
* @param dscb the DataSourceCallback for the media to play
|
||||
* @return the same Builder instance.
|
||||
* @throws NullPointerException if dscb is null.
|
||||
*/
|
||||
public @NonNull Builder setDataSource(@NonNull DataSourceCallback dscb) {
|
||||
setSourceType(SOURCE_TYPE_CALLBACK);
|
||||
Media2Utils.checkArgument(dscb != null, "data source cannot be null.");
|
||||
mDataSourceCallback = dscb;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void setSourceType(int type) {
|
||||
if (mSourceType != SOURCE_TYPE_UNKNOWN) {
|
||||
throw new IllegalStateException("Source is already set. type=" + mSourceType);
|
||||
}
|
||||
mSourceType = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package android.media;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.TestApi;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -30,8 +30,9 @@ import java.io.IOException;
|
||||
* {@link MediaPlayer2#setNextDataSources} to set data source for playback.
|
||||
*
|
||||
* <p>Users should use {@link Builder} to create {@link FileDataSourceDesc}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public class FileDataSourceDesc extends DataSourceDesc {
|
||||
private static final String TAG = "FileDataSourceDesc";
|
||||
|
||||
@@ -48,8 +49,12 @@ public class FileDataSourceDesc extends DataSourceDesc {
|
||||
private int mCount = 0;
|
||||
private boolean mClosed = false;
|
||||
|
||||
private FileDataSourceDesc() {
|
||||
super();
|
||||
FileDataSourceDesc(String mediaId, long startPositionMs, long endPositionMs,
|
||||
ParcelFileDescriptor pfd, long offset, long length) {
|
||||
super(mediaId, startPositionMs, endPositionMs);
|
||||
mPFD = pfd;
|
||||
mOffset = offset;
|
||||
mLength = length;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,133 +133,4 @@ public class FileDataSourceDesc extends DataSourceDesc {
|
||||
public long getLength() {
|
||||
return mLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for {@link FileDataSourceDesc} objects.
|
||||
* <p> Here is an example where <code>Builder</code> is used to define the
|
||||
* {@link FileDataSourceDesc} to be used by a {@link MediaPlayer2} instance:
|
||||
*
|
||||
* <pre class="prettyprint">
|
||||
* FileDataSourceDesc newDSD = new FileDataSourceDesc.Builder()
|
||||
* .setDataSource(pfd, 0, srcLength)
|
||||
* .setStartPosition(1000)
|
||||
* .setEndPosition(15000)
|
||||
* .build();
|
||||
* mediaplayer2.setDataSourceDesc(newDSD);
|
||||
* </pre>
|
||||
*/
|
||||
public static class Builder extends BuilderBase<Builder> {
|
||||
private ParcelFileDescriptor mPFD;
|
||||
private long mOffset = 0;
|
||||
private long mLength = FD_LENGTH_UNKNOWN;
|
||||
|
||||
/**
|
||||
* Constructs a new Builder with the defaults.
|
||||
*/
|
||||
public Builder() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Builder from a given {@link FileDataSourceDesc} instance
|
||||
* @param dsd the {@link FileDataSourceDesc} object whose data will be reused
|
||||
* in the new Builder.
|
||||
*/
|
||||
public Builder(@Nullable FileDataSourceDesc dsd) {
|
||||
super(dsd);
|
||||
if (dsd == null) {
|
||||
return; // use default
|
||||
}
|
||||
mPFD = dsd.mPFD;
|
||||
mOffset = dsd.mOffset;
|
||||
mLength = dsd.mLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines all of the fields that have been set and return a new
|
||||
* {@link FileDataSourceDesc} object. <code>IllegalStateException</code> will be
|
||||
* thrown if there is conflict between fields.
|
||||
*
|
||||
* @return a new {@link FileDataSourceDesc} object
|
||||
*/
|
||||
public @NonNull FileDataSourceDesc build() {
|
||||
if (mPFD == null) {
|
||||
throw new IllegalStateException(
|
||||
"underline ParcelFileDescriptor should not be null");
|
||||
}
|
||||
try {
|
||||
mPFD.getFd();
|
||||
} catch (IllegalStateException e) {
|
||||
throw new IllegalStateException("ParcelFileDescriptor has been closed");
|
||||
}
|
||||
|
||||
FileDataSourceDesc dsd = new FileDataSourceDesc();
|
||||
super.build(dsd);
|
||||
dsd.mPFD = mPFD;
|
||||
dsd.mOffset = mOffset;
|
||||
dsd.mLength = mLength;
|
||||
|
||||
return dsd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
|
||||
* seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc}
|
||||
* created by this builder is passed to {@link MediaPlayer2} via
|
||||
* {@link MediaPlayer2#setDataSource},
|
||||
* {@link MediaPlayer2#setNextDataSource} or
|
||||
* {@link MediaPlayer2#setNextDataSources}, MediaPlayer2 will
|
||||
* close the ParcelFileDescriptor.
|
||||
*
|
||||
* @param pfd the ParcelFileDescriptor for the file to play
|
||||
* @return the same Builder instance.
|
||||
* @throws NullPointerException if pfd is null.
|
||||
*/
|
||||
public @NonNull Builder setDataSource(@NonNull ParcelFileDescriptor pfd) {
|
||||
Media2Utils.checkArgument(pfd != null, "pfd cannot be null.");
|
||||
resetDataSource();
|
||||
mPFD = pfd;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source (ParcelFileDescriptor) to use. The ParcelFileDescriptor must be
|
||||
* seekable (N.B. a LocalSocket is not seekable). When the {@link FileDataSourceDesc}
|
||||
* created by this builder is passed to {@link MediaPlayer2} via
|
||||
* {@link MediaPlayer2#setDataSource},
|
||||
* {@link MediaPlayer2#setNextDataSource} or
|
||||
* {@link MediaPlayer2#setNextDataSources}, MediaPlayer2 will
|
||||
* close the ParcelFileDescriptor.
|
||||
*
|
||||
* Any negative number for offset is treated as 0.
|
||||
* Any negative number for length is treated as maximum length of the data source.
|
||||
*
|
||||
* @param pfd the ParcelFileDescriptor for the file to play
|
||||
* @param offset the offset into the file where the data to be played starts, in bytes
|
||||
* @param length the length in bytes of the data to be played
|
||||
* @return the same Builder instance.
|
||||
* @throws NullPointerException if pfd is null.
|
||||
*/
|
||||
public @NonNull Builder setDataSource(
|
||||
@NonNull ParcelFileDescriptor pfd, long offset, long length) {
|
||||
Media2Utils.checkArgument(pfd != null, "pfd cannot be null.");
|
||||
if (offset < 0) {
|
||||
offset = 0;
|
||||
}
|
||||
if (length < 0) {
|
||||
length = FD_LENGTH_UNKNOWN;
|
||||
}
|
||||
resetDataSource();
|
||||
mPFD = pfd;
|
||||
mOffset = offset;
|
||||
mLength = length;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void resetDataSource() {
|
||||
mPFD = null;
|
||||
mOffset = 0;
|
||||
mLength = FD_LENGTH_UNKNOWN;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -898,7 +898,7 @@ public class MediaPlayer2 implements AutoCloseable, AudioRouting {
|
||||
UriDataSourceDesc uriDSD = (UriDataSourceDesc) dsd;
|
||||
handleDataSource(isCurrent,
|
||||
srcId,
|
||||
uriDSD.getContext(),
|
||||
mContext,
|
||||
uriDSD.getUri(),
|
||||
uriDSD.getHeaders(),
|
||||
uriDSD.getCookies(),
|
||||
|
||||
@@ -18,11 +18,9 @@ package android.media;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.annotation.TestApi;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.net.CookieHandler;
|
||||
import java.net.CookieManager;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -36,15 +34,20 @@ import java.util.Map;
|
||||
* {@link MediaPlayer2#setNextDataSources} to set data source for playback.
|
||||
*
|
||||
* <p>Users should use {@link Builder} to change {@link UriDataSourceDesc}.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
@TestApi
|
||||
public class UriDataSourceDesc extends DataSourceDesc {
|
||||
private Uri mUri;
|
||||
private Map<String, String> mHeader;
|
||||
private List<HttpCookie> mCookies;
|
||||
private Context mContext;
|
||||
|
||||
private UriDataSourceDesc() {
|
||||
UriDataSourceDesc(String mediaId, long startPositionMs, long endPositionMs,
|
||||
Uri uri, Map<String, String> header, List<HttpCookie> cookies) {
|
||||
super(mediaId, startPositionMs, endPositionMs);
|
||||
mUri = uri;
|
||||
mHeader = header;
|
||||
mCookies = cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -76,155 +79,4 @@ public class UriDataSourceDesc extends DataSourceDesc {
|
||||
}
|
||||
return new ArrayList<HttpCookie>(mCookies);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Context used for resolving the Uri of this data source.
|
||||
* @return the Context used for resolving the Uri of this data source
|
||||
*/
|
||||
public @NonNull Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder class for {@link UriDataSourceDesc} objects.
|
||||
* <p> Here is an example where <code>Builder</code> is used to define the
|
||||
* {@link UriDataSourceDesc} to be used by a {@link MediaPlayer2} instance:
|
||||
*
|
||||
* <pre class="prettyprint">
|
||||
* UriDataSourceDesc newDSD = new UriDataSourceDesc.Builder()
|
||||
* .setDataSource(context, uri, headers, cookies)
|
||||
* .setStartPosition(1000)
|
||||
* .setEndPosition(15000)
|
||||
* .build();
|
||||
* mediaplayer2.setDataSourceDesc(newDSD);
|
||||
* </pre>
|
||||
*/
|
||||
public static class Builder extends BuilderBase<Builder> {
|
||||
private Uri mUri;
|
||||
private Map<String, String> mHeader;
|
||||
private List<HttpCookie> mCookies;
|
||||
private Context mContext;
|
||||
|
||||
/**
|
||||
* Constructs a new Builder with the defaults.
|
||||
*/
|
||||
public Builder() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Builder from a given {@link UriDataSourceDesc} instance
|
||||
* @param dsd the {@link UriDataSourceDesc} object whose data will be reused
|
||||
* in the new Builder.
|
||||
*/
|
||||
public Builder(@Nullable UriDataSourceDesc dsd) {
|
||||
super(dsd);
|
||||
if (dsd == null) {
|
||||
return; // use default
|
||||
}
|
||||
mUri = dsd.mUri;
|
||||
mHeader = dsd.mHeader;
|
||||
mCookies = dsd.mCookies;
|
||||
mContext = dsd.mContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Combines all of the fields that have been set and return a new
|
||||
* {@link UriDataSourceDesc} object. <code>IllegalStateException</code> will be
|
||||
* thrown if there is conflict between fields.
|
||||
*
|
||||
* @return a new {@link UriDataSourceDesc} object
|
||||
*/
|
||||
public @NonNull UriDataSourceDesc build() {
|
||||
if (mUri == null || mContext == null) {
|
||||
throw new IllegalStateException(
|
||||
"Uri and Context should not be null");
|
||||
}
|
||||
|
||||
UriDataSourceDesc dsd = new UriDataSourceDesc();
|
||||
super.build(dsd);
|
||||
dsd.mUri = mUri;
|
||||
dsd.mHeader = mHeader;
|
||||
dsd.mCookies = mCookies;
|
||||
dsd.mContext = mContext;
|
||||
|
||||
return dsd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source as a content Uri.
|
||||
*
|
||||
* @param context the Context to use when resolving the Uri
|
||||
* @param uri the Content URI of the data you want to play
|
||||
* @return the same Builder instance.
|
||||
* @throws NullPointerException if context or uri is null.
|
||||
*/
|
||||
public @NonNull Builder setDataSource(@NonNull Context context, @NonNull Uri uri) {
|
||||
Media2Utils.checkArgument(context != null, "context cannot be null");
|
||||
Media2Utils.checkArgument(uri != null, "uri cannot be null");
|
||||
resetDataSource();
|
||||
mUri = uri;
|
||||
mContext = context;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data source as a content Uri.
|
||||
*
|
||||
* To provide cookies for the subsequent HTTP requests, you can install your own default
|
||||
* cookie handler and use other variants of setDataSource APIs instead. Alternatively, you
|
||||
* can use this API to pass the cookies as a list of HttpCookie. If the app has not
|
||||
* installed a CookieHandler already, {@link MediaPlayer2} will create a CookieManager
|
||||
* and populates its CookieStore with the provided cookies when this data source is passed
|
||||
* to {@link MediaPlayer2}. If the app has installed its own handler already, the handler
|
||||
* is required to be of CookieManager type such that {@link MediaPlayer2} can update the
|
||||
* manager’s CookieStore.
|
||||
*
|
||||
* <p><strong>Note</strong> that the cross domain redirection is allowed by default,
|
||||
* but that can be changed with key/value pairs through the headers parameter with
|
||||
* "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value to
|
||||
* disallow or allow cross domain redirection.
|
||||
*
|
||||
* @param context the Context to use when resolving the Uri
|
||||
* @param uri the Content URI of the data you want to play
|
||||
* @param headers the headers to be sent together with the request for the data
|
||||
* The headers must not include cookies. Instead, use the cookies param.
|
||||
* @param cookies the cookies to be sent together with the request
|
||||
* @return the same Builder instance.
|
||||
* @throws NullPointerException if context or uri is null.
|
||||
* @throws IllegalArgumentException if the cookie handler is not of CookieManager type
|
||||
* when cookies are provided.
|
||||
*/
|
||||
public @NonNull Builder setDataSource(@NonNull Context context, @NonNull Uri uri,
|
||||
@Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies) {
|
||||
Media2Utils.checkArgument(context != null, "context cannot be null");
|
||||
Media2Utils.checkArgument(uri != null, "uri cannot be null");
|
||||
if (cookies != null) {
|
||||
CookieHandler cookieHandler = CookieHandler.getDefault();
|
||||
if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) {
|
||||
throw new IllegalArgumentException(
|
||||
"The cookie handler has to be of CookieManager type "
|
||||
+ "when cookies are provided.");
|
||||
}
|
||||
}
|
||||
|
||||
resetDataSource();
|
||||
mUri = uri;
|
||||
if (headers != null) {
|
||||
mHeader = new HashMap<String, String>(headers);
|
||||
}
|
||||
if (cookies != null) {
|
||||
mCookies = new ArrayList<HttpCookie>(cookies);
|
||||
}
|
||||
mContext = context;
|
||||
return this;
|
||||
}
|
||||
|
||||
private void resetDataSource() {
|
||||
mUri = null;
|
||||
mHeader = null;
|
||||
mCookies = null;
|
||||
mContext = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user