summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Wei Jia <wjia@google.com> 2018-11-20 22:06:36 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2018-11-20 22:06:36 +0000
commit0a91bc975e73fa1999a57a3ad419cb0099a2f584 (patch)
treea6949841c81cc277f0879f9c9b85c3f3bc36cb50
parent197f2421103e46c78970a61b33ffe3e55b976c81 (diff)
parent1bdf879d5ff031efc1d40647d6ae211c02a6478b (diff)
Merge "DataSourceDesc: refactor to base class and subclasses"
-rw-r--r--media/java/android/media/CallbackDataSourceDesc.java113
-rw-r--r--media/java/android/media/DataSourceDesc.java388
-rw-r--r--media/java/android/media/FileDataSourceDesc.java186
-rw-r--r--media/java/android/media/MediaPlayer2.java60
-rw-r--r--media/java/android/media/UriDataSourceDesc.java228
5 files changed, 594 insertions, 381 deletions
diff --git a/media/java/android/media/CallbackDataSourceDesc.java b/media/java/android/media/CallbackDataSourceDesc.java
new file mode 100644
index 000000000000..a7e168f60ae8
--- /dev/null
+++ b/media/java/android/media/CallbackDataSourceDesc.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2018 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 android.media;
+
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * @hide
+ * Structure for file data source descriptor.
+ *
+ * Used by {@link MediaPlayer2#setDataSource(CallbackDataSourceDesc)}
+ * to set data source for playback.
+ *
+ * <p>Users should use {@link Builder} to create {@link CallbackDataSourceDesc}.
+ *
+ */
+public class CallbackDataSourceDesc extends DataSourceDesc {
+ private Media2DataSource mMedia2DataSource;
+
+ private CallbackDataSourceDesc() {
+ }
+
+ /**
+ * Return the Media2DataSource of this data source.
+ * It's meaningful only when {@code getType} returns {@link #TYPE_CALLBACK}.
+ * @return the Media2DataSource of this data source
+ */
+ public Media2DataSource getMedia2DataSource() {
+ return mMedia2DataSource;
+ }
+
+ /**
+ * 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 Media2DataSource mMedia2DataSource;
+
+ /**
+ * 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(CallbackDataSourceDesc dsd) {
+ super(dsd);
+ if (dsd == null) {
+ return; // use default
+ }
+ mMedia2DataSource = dsd.mMedia2DataSource;
+ }
+
+ /**
+ * 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() {
+ CallbackDataSourceDesc dsd = new CallbackDataSourceDesc();
+ super.build(dsd);
+ dsd.mMedia2DataSource = mMedia2DataSource;
+
+ return dsd;
+ }
+
+ /**
+ * Sets the data source (Media2DataSource) to use.
+ *
+ * @param m2ds the Media2DataSource for the media to play
+ * @return the same Builder instance.
+ * @throws NullPointerException if m2ds is null.
+ */
+ public @NonNull Builder setDataSource(@NonNull Media2DataSource m2ds) {
+ Preconditions.checkNotNull(m2ds);
+ mMedia2DataSource = m2ds;
+ return this;
+ }
+ }
+}
diff --git a/media/java/android/media/DataSourceDesc.java b/media/java/android/media/DataSourceDesc.java
index afc99a08ce3c..aed3f84a9eb2 100644
--- a/media/java/android/media/DataSourceDesc.java
+++ b/media/java/android/media/DataSourceDesc.java
@@ -16,49 +16,21 @@
package android.media;
-import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
import com.android.internal.util.Preconditions;
-import java.io.FileDescriptor;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-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;
-
/**
* @hide
- * Structure for data source descriptor.
+ * Base class of data source descriptor.
*
* Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}
* to set data source for playback.
*
- * <p>Users should use {@link Builder} to change {@link DataSourceDesc}.
+ * <p>Users should use subclasses' builder to change {@link DataSourceDesc}.
*
*/
-public final class DataSourceDesc {
- /* No data source has been set yet */
- public static final int TYPE_NONE = 0;
- /* data source is type of MediaDataSource */
- public static final int TYPE_CALLBACK = 1;
- /* data source is type of FileDescriptor */
- public static final int TYPE_FD = 2;
- /* data source is type of Uri */
- public static final int TYPE_URI = 3;
-
+public class DataSourceDesc {
// intentionally less than long.MAX_VALUE
public static final long LONG_MAX = 0x7ffffffffffffffL;
@@ -66,25 +38,13 @@ public final class DataSourceDesc {
public static final long LONG_MAX_TIME_MS = LONG_MAX / 1000;
public static final long LONG_MAX_TIME_US = LONG_MAX_TIME_MS * 1000;
-
- private int mType = TYPE_NONE;
-
- private Media2DataSource mMedia2DataSource;
-
- private FileDescriptor mFD;
- private long mFDOffset = 0;
- private long mFDLength = LONG_MAX;
-
- private Uri mUri;
- private Map<String, String> mUriHeader;
- private List<HttpCookie> mUriCookies;
- private Context mUriContext;
+ public static final long POSITION_UNKNOWN = LONG_MAX_TIME_MS;
private String mMediaId;
private long mStartPositionMs = 0;
- private long mEndPositionMs = LONG_MAX_TIME_MS;
+ private long mEndPositionMs = POSITION_UNKNOWN;
- private DataSourceDesc() {
+ DataSourceDesc() {
}
/**
@@ -105,194 +65,69 @@ public final class DataSourceDesc {
/**
* Return the position in milliseconds at which the playback will end.
- * -1 means ending at the end of source content.
+ * {@link #POSITION_UNKNOWN} means ending at the end of source content.
* @return the position in milliseconds at which the playback will end
*/
public long getEndPosition() {
return mEndPositionMs;
}
- /**
- * Return the type of data source.
- * @return the type of data source
- */
- public int getType() {
- return mType;
- }
-
- /**
- * Return the Media2DataSource of this data source.
- * It's meaningful only when {@code getType} returns {@link #TYPE_CALLBACK}.
- * @return the Media2DataSource of this data source
- */
- public Media2DataSource getMedia2DataSource() {
- return mMedia2DataSource;
- }
-
- /**
- * Return the FileDescriptor of this data source.
- * It's meaningful only when {@code getType} returns {@link #TYPE_FD}.
- * @return the FileDescriptor of this data source
- */
- public FileDescriptor getFileDescriptor() {
- return mFD;
- }
-
- /**
- * Return the offset associated with the FileDescriptor of this data source.
- * It's meaningful only when {@code getType} returns {@link #TYPE_FD} and it has
- * been set by the {@link Builder}.
- * @return the offset associated with the FileDescriptor of this data source
- */
- public long getFileDescriptorOffset() {
- return mFDOffset;
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("DataSourceDesc{");
+ sb.append("mMediaId=").append(mMediaId);
+ sb.append(", mStartPositionMs=").append(mStartPositionMs);
+ sb.append(", mEndPositionMs=").append(mEndPositionMs);
+ sb.append('}');
+ return sb.toString();
}
/**
- * Return the content length associated with the FileDescriptor of this data source.
- * It's meaningful only when {@code getType} returns {@link #TYPE_FD}.
- * -1 means same as the length of source content.
- * @return the content length associated with the FileDescriptor of this data source
+ * Base class for Builders in the subclasses of {@link DataSourceDesc}.
*/
- public long getFileDescriptorLength() {
- return mFDLength;
- }
-
- /**
- * Return the Uri of this data source.
- * It's meaningful only when {@code getType} returns {@link #TYPE_URI}.
- * @return the Uri of this data source
- */
- public Uri getUri() {
- return mUri;
- }
-
- /**
- * Return the Uri headers of this data source.
- * It's meaningful only when {@code getType} returns {@link #TYPE_URI}.
- * @return the Uri headers of this data source
- */
- public Map<String, String> getUriHeaders() {
- if (mUriHeader == null) {
- return null;
- }
- return new HashMap<String, String>(mUriHeader);
- }
-
- /**
- * Return the Uri cookies of this data source.
- * It's meaningful only when {@code getType} returns {@link #TYPE_URI}.
- * @return the Uri cookies of this data source
- */
- public List<HttpCookie> getUriCookies() {
- if (mUriCookies == null) {
- return null;
- }
- return new ArrayList<HttpCookie>(mUriCookies);
- }
-
- /**
- * Return the Context used for resolving the Uri of this data source.
- * It's meaningful only when {@code getType} returns {@link #TYPE_URI}.
- * @return the Context used for resolving the Uri of this data source
- */
- public Context getUriContext() {
- return mUriContext;
- }
-
- /**
- * Builder class for {@link DataSourceDesc} objects.
- * <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 oldDSD = mediaplayer2.getDataSourceDesc();
- * DataSourceDesc newDSD = new DataSourceDesc.Builder(oldDSD)
- * .setStartPosition(1000)
- * .setEndPosition(15000)
- * .build();
- * mediaplayer2.setDataSourceDesc(newDSD);
- * </pre>
- */
- public static class Builder {
- private int mType = TYPE_NONE;
-
- private Media2DataSource mMedia2DataSource;
-
- private FileDescriptor mFD;
- private long mFDOffset = 0;
- private long mFDLength = LONG_MAX;
-
- private Uri mUri;
- private Map<String, String> mUriHeader;
- private List<HttpCookie> mUriCookies;
- private Context mUriContext;
-
+ protected static class BuilderBase<T extends BuilderBase> {
private String mMediaId;
private long mStartPositionMs = 0;
- private long mEndPositionMs = LONG_MAX_TIME_MS;
+ private long mEndPositionMs = POSITION_UNKNOWN;
/**
- * Constructs a new Builder with the defaults.
+ * Constructs a new BuilderBase with the defaults.
*/
- public Builder() {
+ BuilderBase() {
}
/**
- * Constructs a new Builder from a given {@link DataSourceDesc} instance
+ * Constructs a new BuilderBase from a given {@link DataSourceDesc} instance
* @param dsd the {@link DataSourceDesc} object whose data will be reused
- * in the new Builder.
+ * in the new BuilderBase.
*/
- public Builder(DataSourceDesc dsd) {
- mType = dsd.mType;
- mMedia2DataSource = dsd.mMedia2DataSource;
- mFD = dsd.mFD;
- mFDOffset = dsd.mFDOffset;
- mFDLength = dsd.mFDLength;
- mUri = dsd.mUri;
- mUriHeader = dsd.mUriHeader;
- mUriCookies = dsd.mUriCookies;
- mUriContext = dsd.mUriContext;
-
+ BuilderBase(DataSourceDesc dsd) {
+ if (dsd == null) {
+ return;
+ }
mMediaId = dsd.mMediaId;
mStartPositionMs = dsd.mStartPositionMs;
mEndPositionMs = dsd.mEndPositionMs;
}
/**
- * Combines all of the fields that have been set and return a new
- * {@link DataSourceDesc} object. <code>IllegalStateException</code> will be
- * thrown if there is conflict between fields.
+ * Sets all fields that have been set in the {@link DataSourceDesc} object.
+ * <code>IllegalStateException</code> will be thrown if there is conflict between fields.
*
- * @return a new {@link DataSourceDesc} object
+ * @param dsd an instance of subclass of {@link DataSourceDesc} whose data will be set
+ * @return the same instance of subclass of {@link DataSourceDesc}
*/
- public DataSourceDesc build() {
- if (mType != TYPE_CALLBACK
- && mType != TYPE_FD
- && mType != TYPE_URI) {
- throw new IllegalStateException("Illegal type: " + mType);
- }
+ void build(@NonNull DataSourceDesc dsd) {
+ Preconditions.checkNotNull(dsd);
+
if (mStartPositionMs > mEndPositionMs) {
throw new IllegalStateException("Illegal start/end position: "
+ mStartPositionMs + " : " + mEndPositionMs);
}
- DataSourceDesc dsd = new DataSourceDesc();
- dsd.mType = mType;
- dsd.mMedia2DataSource = mMedia2DataSource;
- dsd.mFD = mFD;
- dsd.mFDOffset = mFDOffset;
- dsd.mFDLength = mFDLength;
- dsd.mUri = mUri;
- dsd.mUriHeader = mUriHeader;
- dsd.mUriCookies = mUriCookies;
- dsd.mUriContext = mUriContext;
-
dsd.mMediaId = mMediaId;
dsd.mStartPositionMs = mStartPositionMs;
dsd.mEndPositionMs = mEndPositionMs;
-
- return dsd;
}
/**
@@ -301,9 +136,9 @@ public final class DataSourceDesc {
* @param mediaId the media Id of this data source
* @return the same Builder instance.
*/
- public Builder setMediaId(String mediaId) {
+ public @NonNull T setMediaId(String mediaId) {
mMediaId = mediaId;
- return this;
+ return (T) this;
}
/**
@@ -314,12 +149,12 @@ public final class DataSourceDesc {
* @return the same Builder instance.
*
*/
- public Builder setStartPosition(long position) {
+ public @NonNull T setStartPosition(long position) {
if (position < 0) {
position = 0;
}
mStartPositionMs = position;
- return this;
+ return (T) this;
}
/**
@@ -329,157 +164,12 @@ public final class DataSourceDesc {
* @param position the end position in milliseconds at which the playback will end
* @return the same Builder instance.
*/
- public Builder setEndPosition(long position) {
+ public @NonNull T setEndPosition(long position) {
if (position < 0) {
position = LONG_MAX_TIME_MS;
}
mEndPositionMs = position;
- return this;
- }
-
- /**
- * Sets the data source (Media2DataSource) to use.
- *
- * @param m2ds the Media2DataSource for the media you want to play
- * @return the same Builder instance.
- * @throws NullPointerException if m2ds is null.
- */
- public Builder setDataSource(Media2DataSource m2ds) {
- Preconditions.checkNotNull(m2ds);
- resetDataSource();
- mType = TYPE_CALLBACK;
- mMedia2DataSource = m2ds;
- return this;
- }
-
- /**
- * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
- * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
- * to close the file descriptor after the source has been used.
- *
- * @param fd the FileDescriptor for the file you want to play
- * @return the same Builder instance.
- * @throws NullPointerException if fd is null.
- */
- public Builder setDataSource(FileDescriptor fd) {
- Preconditions.checkNotNull(fd);
- resetDataSource();
- mType = TYPE_FD;
- mFD = fd;
- return this;
- }
-
- /**
- * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
- * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
- * to close the file descriptor after the source has been used.
- *
- * Any negative number for offset is treated as 0.
- * Any negative number for length is treated as maximum length of the data source.
- *
- * @param fd the FileDescriptor for the file you want 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 fd is null.
- */
- public Builder setDataSource(FileDescriptor fd, long offset, long length) {
- Preconditions.checkNotNull(fd);
- if (offset < 0) {
- offset = 0;
- }
- if (length < 0) {
- length = LONG_MAX;
- }
- resetDataSource();
- mType = TYPE_FD;
- mFD = fd;
- mFDOffset = offset;
- mFDLength = length;
- return this;
- }
-
- /**
- * 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 Builder setDataSource(@NonNull Context context, @NonNull Uri uri) {
- Preconditions.checkNotNull(context, "context cannot be null");
- Preconditions.checkNotNull(uri, "uri cannot be null");
- resetDataSource();
- mType = TYPE_URI;
- mUri = uri;
- mUriContext = 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 Builder setDataSource(@NonNull Context context, @NonNull Uri uri,
- @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies) {
- Preconditions.checkNotNull(context, "context cannot be null");
- Preconditions.checkNotNull(uri);
- 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();
- mType = TYPE_URI;
- mUri = uri;
- if (headers != null) {
- mUriHeader = new HashMap<String, String>(headers);
- }
- if (cookies != null) {
- mUriCookies = new ArrayList<HttpCookie>(cookies);
- }
- mUriContext = context;
- return this;
- }
-
- private void resetDataSource() {
- mType = TYPE_NONE;
- mMedia2DataSource = null;
- mFD = null;
- mFDOffset = 0;
- mFDLength = LONG_MAX;
- mUri = null;
- mUriHeader = null;
- mUriCookies = null;
- mUriContext = null;
+ return (T) this;
}
}
}
diff --git a/media/java/android/media/FileDataSourceDesc.java b/media/java/android/media/FileDataSourceDesc.java
new file mode 100644
index 000000000000..5d8ff4913fb5
--- /dev/null
+++ b/media/java/android/media/FileDataSourceDesc.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2018 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 android.media;
+
+import android.annotation.NonNull;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.FileDescriptor;
+
+/**
+ * @hide
+ * Structure for data source descriptor.
+ *
+ * Used by {@link MediaPlayer2#setDataSource(DataSourceDesc)}
+ * to set data source for playback.
+ *
+ * <p>Users should use {@link Builder} to create {@link FileDataSourceDesc}.
+ *
+ */
+public class FileDataSourceDesc extends DataSourceDesc {
+ /**
+ * Used when the length of file descriptor is unknown.
+ *
+ * @see #getLength()
+ */
+ public static final long FD_LENGTH_UNKNOWN = LONG_MAX;
+
+ private FileDescriptor mFD;
+ private long mOffset = 0;
+ private long mLength = FD_LENGTH_UNKNOWN;
+
+ private FileDataSourceDesc() {
+ }
+
+ /**
+ * Return the FileDescriptor of this data source.
+ * @return the FileDescriptor of this data source
+ */
+ public FileDescriptor getFileDescriptor() {
+ return mFD;
+ }
+
+ /**
+ * Return the offset associated with the FileDescriptor of this data source.
+ * It's meaningful only when it has been set by the {@link Builder}.
+ * @return the offset associated with the FileDescriptor of this data source
+ */
+ public long getOffset() {
+ return mOffset;
+ }
+
+ /**
+ * Return the content length associated with the FileDescriptor of this data source.
+ * {@link #FD_LENGTH_UNKNOWN} means same as the length of source content.
+ * @return the content length associated with the FileDescriptor of this data source
+ */
+ 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(fd, 0, srcLength)
+ * .setStartPosition(1000)
+ * .setEndPosition(15000)
+ * .build();
+ * mediaplayer2.setDataSourceDesc(newDSD);
+ * </pre>
+ */
+ public static class Builder extends BuilderBase<Builder> {
+ private FileDescriptor mFD;
+ 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(FileDataSourceDesc dsd) {
+ super(dsd);
+ if (dsd == null) {
+ return; // use default
+ }
+ mFD = dsd.mFD;
+ 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() {
+ FileDataSourceDesc dsd = new FileDataSourceDesc();
+ super.build(dsd);
+ dsd.mFD = mFD;
+ dsd.mOffset = mOffset;
+ dsd.mLength = mLength;
+
+ return dsd;
+ }
+
+ /**
+ * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
+ * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
+ * to close the file descriptor after the source has been used.
+ *
+ * @param fd the FileDescriptor for the file to play
+ * @return the same Builder instance.
+ * @throws NullPointerException if fd is null.
+ */
+ public @NonNull Builder setDataSource(@NonNull FileDescriptor fd) {
+ Preconditions.checkNotNull(fd);
+ resetDataSource();
+ mFD = fd;
+ return this;
+ }
+
+ /**
+ * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
+ * seekable (N.B. a LocalSocket is not seekable). It is the caller's responsibility
+ * to close the file descriptor after the source has been used.
+ *
+ * Any negative number for offset is treated as 0.
+ * Any negative number for length is treated as maximum length of the data source.
+ *
+ * @param fd the FileDescriptor 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 fd is null.
+ */
+ public @NonNull Builder setDataSource(
+ @NonNull FileDescriptor fd, long offset, long length) {
+ Preconditions.checkNotNull(fd);
+ if (offset < 0) {
+ offset = 0;
+ }
+ if (length < 0) {
+ length = FD_LENGTH_UNKNOWN;
+ }
+ resetDataSource();
+ mFD = fd;
+ mOffset = offset;
+ mLength = length;
+ return this;
+ }
+
+ private void resetDataSource() {
+ mFD = null;
+ mOffset = 0;
+ mLength = FD_LENGTH_UNKNOWN;
+ }
+ }
+}
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index a80511a118cf..548dc881d733 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -790,38 +790,34 @@ public class MediaPlayer2 implements AutoCloseable
throws IOException {
checkArgument(dsd != null, "the DataSourceDesc cannot be null");
- switch (dsd.getType()) {
- case DataSourceDesc.TYPE_CALLBACK:
- handleDataSource(isCurrent,
- srcId,
- dsd.getMedia2DataSource(),
- dsd.getStartPosition(),
- dsd.getEndPosition());
- break;
-
- case DataSourceDesc.TYPE_FD:
- handleDataSource(isCurrent,
- srcId,
- dsd.getFileDescriptor(),
- dsd.getFileDescriptorOffset(),
- dsd.getFileDescriptorLength(),
- dsd.getStartPosition(),
- dsd.getEndPosition());
- break;
-
- case DataSourceDesc.TYPE_URI:
- handleDataSource(isCurrent,
- srcId,
- dsd.getUriContext(),
- dsd.getUri(),
- dsd.getUriHeaders(),
- dsd.getUriCookies(),
- dsd.getStartPosition(),
- dsd.getEndPosition());
- break;
-
- default:
- break;
+ if (dsd instanceof CallbackDataSourceDesc) {
+ CallbackDataSourceDesc cbDSD = (CallbackDataSourceDesc) dsd;
+ handleDataSource(isCurrent,
+ srcId,
+ cbDSD.getMedia2DataSource(),
+ cbDSD.getStartPosition(),
+ cbDSD.getEndPosition());
+ } else if (dsd instanceof FileDataSourceDesc) {
+ FileDataSourceDesc fileDSD = (FileDataSourceDesc) dsd;
+ handleDataSource(isCurrent,
+ srcId,
+ fileDSD.getFileDescriptor(),
+ fileDSD.getOffset(),
+ fileDSD.getLength(),
+ fileDSD.getStartPosition(),
+ fileDSD.getEndPosition());
+ } else if (dsd instanceof UriDataSourceDesc) {
+ UriDataSourceDesc uriDSD = (UriDataSourceDesc) dsd;
+ handleDataSource(isCurrent,
+ srcId,
+ uriDSD.getContext(),
+ uriDSD.getUri(),
+ uriDSD.getHeaders(),
+ uriDSD.getCookies(),
+ uriDSD.getStartPosition(),
+ uriDSD.getEndPosition());
+ } else {
+ throw new IllegalArgumentException("Unsupported DataSourceDesc. " + dsd.toString());
}
}
diff --git a/media/java/android/media/UriDataSourceDesc.java b/media/java/android/media/UriDataSourceDesc.java
new file mode 100644
index 000000000000..e6f39e0bc8fb
--- /dev/null
+++ b/media/java/android/media/UriDataSourceDesc.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2018 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 android.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.net.Uri;
+
+import com.android.internal.util.Preconditions;
+
+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;
+
+/**
+ * @hide
+ * Structure for data source descriptor.
+ *
+ * Used by {@link MediaPlayer2#setDataSource(UriDataSourceDesc)}
+ * to set data source for playback.
+ *
+ * <p>Users should use {@link Builder} to change {@link UriDataSourceDesc}.
+ *
+ */
+public class UriDataSourceDesc extends DataSourceDesc {
+ private Uri mUri;
+ private Map<String, String> mHeader;
+ private List<HttpCookie> mCookies;
+ private Context mContext;
+
+ private UriDataSourceDesc() {
+ }
+
+ /**
+ * Return the Uri of this data source.
+ * @return the Uri of this data source
+ */
+ public Uri getUri() {
+ return mUri;
+ }
+
+ /**
+ * Return the Uri headers of this data source.
+ * @return the Uri headers of this data source
+ */
+ public Map<String, String> getHeaders() {
+ if (mHeader == null) {
+ return null;
+ }
+ return new HashMap<String, String>(mHeader);
+ }
+
+ /**
+ * Return the Uri cookies of this data source.
+ * @return the Uri cookies of this data source
+ */
+ public List<HttpCookie> getCookies() {
+ if (mCookies == null) {
+ return null;
+ }
+ 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 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(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() {
+ 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) {
+ Preconditions.checkNotNull(context, "context cannot be null");
+ Preconditions.checkNotNull(uri, "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) {
+ Preconditions.checkNotNull(context, "context cannot be null");
+ Preconditions.checkNotNull(uri);
+ 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;
+ }
+ }
+}