API Extension: Support for optionally specifying a map of extra request headers when specifying the uri of media data to be played.

related-to-bug: 2393577

Original change by Andrei Popescu <andreip@google.com>
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 81d60dc..405d471 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -197,7 +197,7 @@
 static sp<MediaPlayer> newMediaPlayer(const char *file)
 {
     sp<MediaPlayer> mp = new MediaPlayer();
-    if (mp->setDataSource(file) == NO_ERROR) {
+    if (mp->setDataSource(file, NULL /* headers */) == NO_ERROR) {
         mp->setAudioStreamType(AudioSystem::ENFORCED_AUDIBLE);
         mp->prepare();
     } else {
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 429b335..85f1d5c 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -73,6 +73,8 @@
     private static final int ENDED             = 201;
     private static final int POSTER_FETCHED    = 202;
 
+    private static final String COOKIE = "Cookie";
+
     // Timer thread -> UI thread
     private static final int TIMEUPDATE = 300;
 
@@ -165,7 +167,15 @@
             mVideoView = new VideoView(proxy.getContext());
             mVideoView.setWillNotDraw(false);
             mVideoView.setMediaController(new MediaController(proxy.getContext()));
-            mVideoView.setVideoURI(Uri.parse(url));
+
+            String cookieValue = CookieManager.getInstance().getCookie(url);
+            Map<String, String> headers = null;
+            if (cookieValue != null) {
+                headers = new HashMap<String, String>();
+                headers.put(COOKIE, cookieValue);
+            }
+
+            mVideoView.setVideoURI(Uri.parse(url), headers);
             mVideoView.setOnCompletionListener(proxy);
             mVideoView.setOnPreparedListener(proxy);
             mVideoView.setOnErrorListener(proxy);
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 8142a82..906bca1c 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -38,6 +38,7 @@
 import android.widget.MediaController.*;
 
 import java.io.IOException;
+import java.util.Map;
 
 /**
  * Displays a video file.  The VideoView class
@@ -50,6 +51,7 @@
     private String TAG = "VideoView";
     // settable by the client
     private Uri         mUri;
+    private Map<String, String> mHeaders;
     private int         mDuration;
 
     // all possible internal states
@@ -90,12 +92,12 @@
         super(context);
         initVideoView();
     }
-    
+
     public VideoView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
         initVideoView();
     }
-    
+
     public VideoView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
         initVideoView();
@@ -122,7 +124,7 @@
         //Log.i("@@@@@@@@@@", "setting size: " + width + 'x' + height);
         setMeasuredDimension(width, height);
     }
-    
+
     public int resolveAdjustedSize(int desiredSize, int measureSpec) {
         int result = desiredSize;
         int specMode = MeasureSpec.getMode(measureSpec);
@@ -137,13 +139,13 @@
                 break;
 
             case MeasureSpec.AT_MOST:
-                /* Parent says we can be as big as we want, up to specSize. 
-                 * Don't be larger than specSize, and don't be larger than 
+                /* Parent says we can be as big as we want, up to specSize.
+                 * Don't be larger than specSize, and don't be larger than
                  * the max size imposed on ourselves.
                  */
                 result = Math.min(desiredSize, specSize);
                 break;
-                
+
             case MeasureSpec.EXACTLY:
                 // No choice. Do what we are told.
                 result = specSize;
@@ -151,7 +153,7 @@
         }
         return result;
 }
-    
+
     private void initVideoView() {
         mVideoWidth = 0;
         mVideoHeight = 0;
@@ -169,13 +171,21 @@
     }
 
     public void setVideoURI(Uri uri) {
+        setVideoURI(uri, null);
+    }
+
+    /**
+     * @hide
+     */
+    public void setVideoURI(Uri uri, Map<String, String> headers) {
         mUri = uri;
+        mHeaders = headers;
         mSeekWhenPrepared = 0;
         openVideo();
         requestLayout();
         invalidate();
     }
-    
+
     public void stopPlayback() {
         if (mMediaPlayer != null) {
             mMediaPlayer.stop();
@@ -191,7 +201,7 @@
             // not ready for playback just yet, will try again later
             return;
         }
-        // Tell the music playback service to pause 
+        // Tell the music playback service to pause
         // TODO: these constants need to be published somewhere in the framework.
         Intent i = new Intent("com.android.music.musicservicecommand");
         i.putExtra("command", "pause");
@@ -209,7 +219,7 @@
             mMediaPlayer.setOnErrorListener(mErrorListener);
             mMediaPlayer.setOnBufferingUpdateListener(mBufferingUpdateListener);
             mCurrentBufferPercentage = 0;
-            mMediaPlayer.setDataSource(mContext, mUri);
+            mMediaPlayer.setDataSource(mContext, mUri, mHeaders);
             mMediaPlayer.setDisplay(mSurfaceHolder);
             mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
             mMediaPlayer.setScreenOnWhilePlaying(true);
@@ -232,7 +242,7 @@
             return;
         }
     }
-    
+
     public void setMediaController(MediaController controller) {
         if (mMediaController != null) {
             mMediaController.hide();
@@ -250,7 +260,7 @@
             mMediaController.setEnabled(isInPlaybackState());
         }
     }
-    
+
     MediaPlayer.OnVideoSizeChangedListener mSizeChangedListener =
         new MediaPlayer.OnVideoSizeChangedListener() {
             public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
@@ -261,7 +271,7 @@
                 }
             }
     };
-    
+
     MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
         public void onPrepared(MediaPlayer mp) {
             mCurrentState = STATE_PREPARED;
@@ -490,7 +500,7 @@
         }
         return false;
     }
-    
+
     @Override
     public boolean onTrackballEvent(MotionEvent ev) {
         if (isInPlaybackState() && mMediaController != null) {
@@ -498,7 +508,7 @@
         }
         return false;
     }
-    
+
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event)
     {
@@ -519,7 +529,7 @@
                     mMediaController.hide();
                 }
                 return true;
-            } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP 
+            } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
                     && mMediaPlayer.isPlaying()) {
                 pause();
                 mMediaController.show();
@@ -532,13 +542,13 @@
     }
 
     private void toggleMediaControlsVisiblity() {
-        if (mMediaController.isShowing()) { 
+        if (mMediaController.isShowing()) {
             mMediaController.hide();
         } else {
             mMediaController.show();
         }
     }
-    
+
     public void start() {
         if (isInPlaybackState()) {
             mMediaPlayer.start();
@@ -546,7 +556,7 @@
         }
         mTargetState = STATE_PLAYING;
     }
-    
+
     public void pause() {
         if (isInPlaybackState()) {
             if (mMediaPlayer.isPlaying()) {
@@ -556,7 +566,7 @@
         }
         mTargetState = STATE_PAUSED;
     }
-    
+
     // cache duration as mDuration for faster access
     public int getDuration() {
         if (isInPlaybackState()) {
@@ -569,14 +579,14 @@
         mDuration = -1;
         return mDuration;
     }
-    
+
     public int getCurrentPosition() {
         if (isInPlaybackState()) {
             return mMediaPlayer.getCurrentPosition();
         }
         return 0;
     }
-    
+
     public void seekTo(int msec) {
         if (isInPlaybackState()) {
             mMediaPlayer.seekTo(msec);
@@ -584,12 +594,12 @@
         } else {
             mSeekWhenPrepared = msec;
         }
-    }    
-            
+    }
+
     public boolean isPlaying() {
         return isInPlaybackState() && mMediaPlayer.isPlaying();
     }
-    
+
     public int getBufferPercentage() {
         if (mMediaPlayer != null) {
             return mCurrentBufferPercentage;
diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h
index d5c1594..31c0991 100644
--- a/include/media/IMediaPlayerService.h
+++ b/include/media/IMediaPlayerService.h
@@ -18,7 +18,9 @@
 #define ANDROID_IMEDIAPLAYERSERVICE_H
 
 #include <utils/Errors.h>  // for status_t
+#include <utils/KeyedVector.h>
 #include <utils/RefBase.h>
+#include <utils/String8.h>
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
 
@@ -38,7 +40,7 @@
 
     virtual sp<IMediaRecorder>  createMediaRecorder(pid_t pid) = 0;
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid) = 0;
-    virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) = 0;
+    virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url, const KeyedVector<String8, String8> *headers = NULL) = 0;
     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) = 0;
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat) = 0;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 588c51a..a5a1bb8 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -21,8 +21,10 @@
 
 #include <sys/types.h>
 #include <ui/ISurface.h>
-#include <utils/RefBase.h>
 #include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/RefBase.h>
 
 #include <media/mediaplayer.h>
 #include <media/AudioSystem.h>
@@ -96,7 +98,11 @@
     virtual             ~MediaPlayerBase() {}
     virtual status_t    initCheck() = 0;
     virtual bool        hardwareOutput() = 0;
-    virtual status_t    setDataSource(const char *url) = 0;
+
+    virtual status_t    setDataSource(
+            const char *url,
+            const KeyedVector<String8, String8> *headers = NULL) = 0;
+
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length) = 0;
     virtual status_t    setVideoSurface(const sp<ISurface>& surface) = 0;
     virtual status_t    prepare() = 0;
diff --git a/include/media/PVPlayer.h b/include/media/PVPlayer.h
index 8a66152..df50981 100644
--- a/include/media/PVPlayer.h
+++ b/include/media/PVPlayer.h
@@ -38,7 +38,10 @@
     virtual             ~PVPlayer();
 
     virtual status_t    initCheck();
-    virtual status_t    setDataSource(const char *url);
+
+    virtual status_t    setDataSource(
+            const char *url, const KeyedVector<String8, String8> *headers);
+
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length);
     virtual status_t    setVideoSurface(const sp<ISurface>& surface);
     virtual status_t    prepare();
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 87d23f6..c9198d6 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -23,6 +23,9 @@
 #include <media/IMediaPlayer.h>
 #include <media/IMediaDeathNotifier.h>
 
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
 namespace android {
 
 enum media_event_type {
@@ -130,7 +133,11 @@
     ~MediaPlayer();
             void            died();
             void            disconnect();
-            status_t        setDataSource(const char *url);
+
+            status_t        setDataSource(
+                    const char *url,
+                    const KeyedVector<String8, String8> *headers);
+
             status_t        setDataSource(int fd, int64_t offset, int64_t length);
             status_t        setVideoSurface(const sp<Surface>& surface);
             status_t        setListener(const sp<MediaPlayerListener>& listener);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 07542ed7..89ee7d3 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -34,6 +34,7 @@
 
 import java.io.FileDescriptor;
 import java.io.IOException;
+import java.util.Map;
 import java.util.Set;
 import java.lang.ref.WeakReference;
 
@@ -665,6 +666,20 @@
      */
     public void setDataSource(Context context, Uri uri)
         throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
+        setDataSource(context, uri, null);
+    }
+
+    /**
+     * 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
+     * @param headers the headers to be sent together with the request for the data
+     * @throws IllegalStateException if it is called in an invalid state
+     * @hide pending API council
+     */
+    public void setDataSource(Context context, Uri uri, Map<String, String> headers)
+        throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
 
         String scheme = uri.getScheme();
         if(scheme == null || scheme.equals("file")) {
@@ -696,7 +711,7 @@
             }
         }
         Log.d(TAG, "Couldn't open file on client side, trying server side");
-        setDataSource(uri.toString());
+        setDataSource(uri.toString(), headers);
         return;
     }
 
@@ -709,6 +724,17 @@
     public native void setDataSource(String path) throws IOException, IllegalArgumentException, IllegalStateException;
 
     /**
+     * Sets the data source (file-path or http/rtsp URL) to use.
+     *
+     * @param path the path of the file, or the http/rtsp URL of the stream you want to play
+     * @param headers the headers associated with the http request for the stream you want to play
+     * @throws IllegalStateException if it is called in an invalid state
+     * @hide pending API council
+     */
+    public native void setDataSource(String path,  Map<String, String> headers)
+            throws IOException, IllegalArgumentException, IllegalStateException;
+
+    /**
      * Sets the data source (FileDescriptor) to use. It is the caller's responsibility
      * to close the file descriptor. It is safe to do so as soon as this call returns.
      *
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 703afd2..27f5668 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -31,6 +31,8 @@
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
 #include "utils/Errors.h"  // for status_t
+#include "utils/KeyedVector.h"
+#include "utils/String8.h"
 #include "android_util_Binder.h"
 #include <binder/Parcel.h>
 
@@ -156,8 +158,8 @@
 }
 
 static void
-android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)
-{
+android_media_MediaPlayer_setDataSourceAndHeaders(
+        JNIEnv *env, jobject thiz, jstring path, jobject headers) {
     sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -174,12 +176,96 @@
         jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
         return;
     }
+
+    // headers is a Map<String, String>.
+    // We build a similar KeyedVector out of it.
+    KeyedVector<String8, String8> headersVector;
+    if (headers) {
+        // Get the Map's entry Set.
+        jclass mapClass = env->FindClass("java/util/Map");
+
+        jmethodID entrySet =
+            env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
+
+        jobject set = env->CallObjectMethod(headers, entrySet);
+        // Obtain an iterator over the Set
+        jclass setClass = env->FindClass("java/util/Set");
+
+        jmethodID iterator =
+            env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
+
+        jobject iter = env->CallObjectMethod(set, iterator);
+        // Get the Iterator method IDs
+        jclass iteratorClass = env->FindClass("java/util/Iterator");
+        jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
+
+        jmethodID next =
+            env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
+
+        // Get the Entry class method IDs
+        jclass entryClass = env->FindClass("java/util/Map$Entry");
+
+        jmethodID getKey =
+            env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
+
+        jmethodID getValue =
+            env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
+
+        // Iterate over the entry Set
+        while (env->CallBooleanMethod(iter, hasNext)) {
+            jobject entry = env->CallObjectMethod(iter, next);
+            jstring key = (jstring) env->CallObjectMethod(entry, getKey);
+            jstring value = (jstring) env->CallObjectMethod(entry, getValue);
+
+            const char* keyStr = env->GetStringUTFChars(key, NULL);
+            if (!keyStr) {  // Out of memory
+                jniThrowException(
+                        env, "java/lang/RuntimeException", "Out of memory");
+                return;
+            }
+
+            const char* valueStr = env->GetStringUTFChars(value, NULL);
+            if (!valueStr) {  // Out of memory
+                jniThrowException(
+                        env, "java/lang/RuntimeException", "Out of memory");
+                return;
+            }
+
+            headersVector.add(String8(keyStr), String8(valueStr));
+
+            env->DeleteLocalRef(entry);
+            env->ReleaseStringUTFChars(key, keyStr);
+            env->DeleteLocalRef(key);
+            env->ReleaseStringUTFChars(value, valueStr);
+            env->DeleteLocalRef(value);
+      }
+
+      env->DeleteLocalRef(entryClass);
+      env->DeleteLocalRef(iteratorClass);
+      env->DeleteLocalRef(iter);
+      env->DeleteLocalRef(setClass);
+      env->DeleteLocalRef(set);
+      env->DeleteLocalRef(mapClass);
+    }
+
     LOGV("setDataSource: path %s", pathStr);
-    status_t opStatus = mp->setDataSource(pathStr);
+    status_t opStatus =
+        mp->setDataSource(
+                String8(pathStr),
+                headers ? &headersVector : NULL);
 
     // Make sure that local ref is released before a potential exception
     env->ReleaseStringUTFChars(path, pathStr);
-    process_media_player_call( env, thiz, opStatus, "java/io/IOException", "setDataSource failed." );
+
+    process_media_player_call(
+            env, thiz, opStatus, "java/io/IOException",
+            "setDataSource failed." );
+}
+
+static void
+android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path)
+{
+    android_media_MediaPlayer_setDataSourceAndHeaders(env, thiz, path, 0);
 }
 
 static void
@@ -610,6 +696,7 @@
 
 static JNINativeMethod gMethods[] = {
     {"setDataSource",       "(Ljava/lang/String;)V",            (void *)android_media_MediaPlayer_setDataSource},
+    {"setDataSource",       "(Ljava/lang/String;Ljava/util/Map;)V",(void *)android_media_MediaPlayer_setDataSourceAndHeaders},
     {"setDataSource",       "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer_setDataSourceFD},
     {"_setVideoSurface",    "()V",                              (void *)android_media_MediaPlayer_setVideoSurface},
     {"prepare",             "()V",                              (void *)android_media_MediaPlayer_prepare},
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index cca3e9b..71c5f86 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -56,13 +56,26 @@
         return interface_cast<IMediaMetadataRetriever>(reply.readStrongBinder());
     }
 
-    virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)
-    {
+    virtual sp<IMediaPlayer> create(
+            pid_t pid, const sp<IMediaPlayerClient>& client,
+            const char* url, const KeyedVector<String8, String8> *headers) {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
         data.writeInt32(pid);
         data.writeStrongBinder(client->asBinder());
         data.writeCString(url);
+
+        if (headers == NULL) {
+            data.writeInt32(0);
+        } else {
+            // serialize the headers
+            data.writeInt32(headers->size());
+            for (size_t i = 0; i < headers->size(); ++i) {
+                data.writeString8(headers->keyAt(i));
+                data.writeString8(headers->valueAt(i));
+            }
+        }
+
         remote()->transact(CREATE_URL, data, &reply);
         return interface_cast<IMediaPlayer>(reply.readStrongBinder());
     }
@@ -142,9 +155,21 @@
         case CREATE_URL: {
             CHECK_INTERFACE(IMediaPlayerService, data, reply);
             pid_t pid = data.readInt32();
-            sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder());
+            sp<IMediaPlayerClient> client =
+                interface_cast<IMediaPlayerClient>(data.readStrongBinder());
             const char* url = data.readCString();
-            sp<IMediaPlayer> player = create(pid, client, url);
+
+            KeyedVector<String8, String8> headers;
+            int32_t numHeaders = data.readInt32();
+            for (int i = 0; i < numHeaders; ++i) {
+                String8 key = data.readString8();
+                String8 value = data.readString8();
+                headers.add(key, value);
+            }
+
+            sp<IMediaPlayer> player = create(
+                    pid, client, url, numHeaders > 0 ? &headers : NULL);
+
             reply->writeStrongBinder(player->asBinder());
             return NO_ERROR;
         } break;
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index c0664f3..cb5ee4b 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -32,6 +32,9 @@
 
 #include <binder/MemoryBase.h>
 
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+
 namespace android {
 
 MediaPlayer::MediaPlayer()
@@ -122,14 +125,16 @@
     return err;
 }
 
-status_t MediaPlayer::setDataSource(const char *url)
+status_t MediaPlayer::setDataSource(
+        const char *url, const KeyedVector<String8, String8> *headers)
 {
     LOGV("setDataSource(%s)", url);
     status_t err = BAD_VALUE;
     if (url != NULL) {
         const sp<IMediaPlayerService>& service(getMediaPlayerService());
         if (service != 0) {
-            sp<IMediaPlayer> player(service->create(getpid(), this, url));
+            sp<IMediaPlayer> player(
+                    service->create(getpid(), this, url, headers));
             err = setDataSource(player);
         }
     }
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 5b061b1..8e61011 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -254,12 +254,14 @@
     return retriever;
 }
 
-sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url)
+sp<IMediaPlayer> MediaPlayerService::create(
+        pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,
+        const KeyedVector<String8, String8> *headers)
 {
     int32_t connId = android_atomic_inc(&mNextConnId);
     sp<Client> c = new Client(this, pid, connId, client);
     LOGV("Create new client(%d) from pid %d, url=%s, connId=%d", connId, pid, url, connId);
-    if (NO_ERROR != c->setDataSource(url))
+    if (NO_ERROR != c->setDataSource(url, headers))
     {
         c.clear();
         return c;
@@ -803,7 +805,8 @@
     return p;
 }
 
-status_t MediaPlayerService::Client::setDataSource(const char *url)
+status_t MediaPlayerService::Client::setDataSource(
+        const char *url, const KeyedVector<String8, String8> *headers)
 {
     LOGV("setDataSource(%s)", url);
     if (url == NULL)
@@ -838,7 +841,7 @@
 
         // now set data source
         LOGV(" setDataSource");
-        mStatus = p->setDataSource(url);
+        mStatus = p->setDataSource(url, headers);
         if (mStatus == NO_ERROR) {
             mPlayer = p;
         } else {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index d243b96..ffe1ba0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -23,6 +23,7 @@
 #include <utils/List.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
+#include <utils/String8.h>
 #include <utils/Vector.h>
 #include <ui/SurfaceComposerClient.h>
 
@@ -181,7 +182,10 @@
     virtual sp<IMediaMetadataRetriever> createMetadataRetriever(pid_t pid);
 
     // House keeping for media player clients
-    virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url);
+    virtual sp<IMediaPlayer>    create(
+            pid_t pid, const sp<IMediaPlayerClient>& client, const char* url,
+            const KeyedVector<String8, String8> *headers);
+
     virtual sp<IMediaPlayer>    create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length);
     virtual sp<IMemory>         decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
     virtual sp<IMemory>         decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
@@ -219,7 +223,11 @@
                                             Parcel *reply);
 
         sp<MediaPlayerBase>     createPlayer(player_type playerType);
-                status_t        setDataSource(const char *url);
+
+                status_t        setDataSource(
+                        const char *url,
+                        const KeyedVector<String8, String8> *headers);
+
                 status_t        setDataSource(int fd, int64_t offset, int64_t length);
         static  void            notify(void* cookie, int msg, int ext1, int ext2);
 
diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp
index e9cbb97..1b0b05f 100644
--- a/media/libmediaplayerservice/MidiFile.cpp
+++ b/media/libmediaplayerservice/MidiFile.cpp
@@ -115,8 +115,8 @@
     release();
 }
 
-status_t MidiFile::setDataSource(const char* path)
-{
+status_t MidiFile::setDataSource(
+        const char* path, const KeyedVector<String8, String8> *) {
     LOGV("MidiFile::setDataSource url=%s", path);
     Mutex::Autolock lock(mMutex);
 
diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h
index 25d4a1b..4a60ece 100644
--- a/media/libmediaplayerservice/MidiFile.h
+++ b/media/libmediaplayerservice/MidiFile.h
@@ -30,7 +30,10 @@
                         ~MidiFile();
 
     virtual status_t    initCheck();
-    virtual status_t    setDataSource(const char* path);
+
+    virtual status_t    setDataSource(
+            const char* path, const KeyedVector<String8, String8> *headers);
+
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length);
     virtual status_t    setVideoSurface(const sp<ISurface>& surface) { return UNKNOWN_ERROR; }
     virtual status_t    prepare();
diff --git a/media/libmediaplayerservice/MidiMetadataRetriever.cpp b/media/libmediaplayerservice/MidiMetadataRetriever.cpp
index 3795b7b..ad95fac 100644
--- a/media/libmediaplayerservice/MidiMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/MidiMetadataRetriever.cpp
@@ -43,7 +43,8 @@
     if (mMidiPlayer == 0) {
         mMidiPlayer = new MidiFile();
     }
-    return mMidiPlayer->setDataSource(url);
+    // TODO: support headers in MetadataRetriever interface!
+    return mMidiPlayer->setDataSource(url, NULL /* headers */);
 }
 
 status_t MidiMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 5915105..3135d0c 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -28,8 +28,9 @@
     return OK;
 }
 
-status_t StagefrightPlayer::setDataSource(const char *url) {
-    LOGV("setDataSource('%s')", url);
+status_t StagefrightPlayer::setDataSource(
+        const char *url, const KeyedVector<String8, String8> *) {
+    LOGI("setDataSource('%s')", url);
     return mPlayer->setDataSource(url);
 }
 
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index 9d005cb..9e6674a 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -30,7 +30,10 @@
     virtual ~StagefrightPlayer();
 
     virtual status_t initCheck();
-    virtual status_t setDataSource(const char *url);
+
+    virtual status_t setDataSource(
+            const char *url, const KeyedVector<String8, String8> *headers);
+
     virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
     virtual status_t setVideoSurface(const sp<ISurface> &surface);
     virtual status_t prepare();
diff --git a/media/libmediaplayerservice/TestPlayerStub.cpp b/media/libmediaplayerservice/TestPlayerStub.cpp
index aa49429..169e49a 100644
--- a/media/libmediaplayerservice/TestPlayerStub.cpp
+++ b/media/libmediaplayerservice/TestPlayerStub.cpp
@@ -112,8 +112,8 @@
 // Load the dynamic library.
 // Create the test player.
 // Call setDataSource on the test player with the url in param.
-status_t TestPlayerStub::setDataSource(const char *url)
-{
+status_t TestPlayerStub::setDataSource(
+        const char *url, const KeyedVector<String8, String8> *headers) {
     if (!isTestUrl(url) || NULL != mHandle) {
         return INVALID_OPERATION;
     }
@@ -162,7 +162,7 @@
     }
 
     mPlayer = (*mNewPlayer)();
-    return mPlayer->setDataSource(mContentUrl);
+    return mPlayer->setDataSource(mContentUrl, headers);
 }
 
 // Internal cleanup.
diff --git a/media/libmediaplayerservice/TestPlayerStub.h b/media/libmediaplayerservice/TestPlayerStub.h
index 80d53a8..6e6c3cd 100644
--- a/media/libmediaplayerservice/TestPlayerStub.h
+++ b/media/libmediaplayerservice/TestPlayerStub.h
@@ -65,7 +65,8 @@
     virtual status_t initCheck();
 
     // @param url Should be a test url. See class comment.
-    virtual status_t setDataSource(const char* url);
+    virtual status_t setDataSource(
+            const char* url, const KeyedVector<String8, String8> *headers);
 
     // Test player for a file descriptor source is not supported.
     virtual status_t setDataSource(int, int64_t, int64_t)  {
diff --git a/media/libmediaplayerservice/VorbisMetadataRetriever.cpp b/media/libmediaplayerservice/VorbisMetadataRetriever.cpp
index e981678..eac74fc 100644
--- a/media/libmediaplayerservice/VorbisMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/VorbisMetadataRetriever.cpp
@@ -39,7 +39,8 @@
     if (mVorbisPlayer == 0) {
         mVorbisPlayer = new VorbisPlayer();
     }
-    return mVorbisPlayer->setDataSource(url);
+    // TODO: support headers in MetadataRetriever interface!
+    return mVorbisPlayer->setDataSource(url, NULL /* headers */);
 }
 
 status_t VorbisMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t length)
diff --git a/media/libmediaplayerservice/VorbisPlayer.cpp b/media/libmediaplayerservice/VorbisPlayer.cpp
index 7f0ef21..8181999 100644
--- a/media/libmediaplayerservice/VorbisPlayer.cpp
+++ b/media/libmediaplayerservice/VorbisPlayer.cpp
@@ -86,9 +86,9 @@
     release();
 }
 
-status_t VorbisPlayer::setDataSource(const char* path)
-{
-    return setdatasource(path, -1, 0, 0x7ffffffffffffffLL); // intentionally less than LONG_MAX
+status_t VorbisPlayer::setDataSource(
+        const char *uri, const KeyedVector<String8, String8> *headers) {
+    return setdatasource(uri, -1, 0, 0x7ffffffffffffffLL); // intentionally less than LONG_MAX
 }
 
 status_t VorbisPlayer::setDataSource(int fd, int64_t offset, int64_t length)
diff --git a/media/libmediaplayerservice/VorbisPlayer.h b/media/libmediaplayerservice/VorbisPlayer.h
index 4024654..4a50835 100644
--- a/media/libmediaplayerservice/VorbisPlayer.h
+++ b/media/libmediaplayerservice/VorbisPlayer.h
@@ -37,7 +37,10 @@
 
     virtual void        onFirstRef();
     virtual status_t    initCheck();
-    virtual status_t    setDataSource(const char* path);
+
+    virtual status_t    setDataSource(
+            const char *uri, const KeyedVector<String8, String8> *headers);
+
     virtual status_t    setDataSource(int fd, int64_t offset, int64_t length);
     virtual status_t    setVideoSurface(const sp<ISurface>& surface) { return UNKNOWN_ERROR; }
     virtual status_t    prepare();
diff --git a/media/tests/players/invoke_mock_media_player.cpp b/media/tests/players/invoke_mock_media_player.cpp
index 77bb5b2..b3cc8b6 100644
--- a/media/tests/players/invoke_mock_media_player.cpp
+++ b/media/tests/players/invoke_mock_media_player.cpp
@@ -35,6 +35,8 @@
 using android::player_type;
 using android::sp;
 using android::status_t;
+using android::String8;
+using android::KeyedVector;
 
 // This file contains a test player that is loaded via the
 // TestPlayerStub class.  The player contains various implementation
@@ -53,7 +55,9 @@
     virtual status_t    initCheck() {return OK;}
     virtual bool        hardwareOutput() {return true;}
 
-    virtual status_t    setDataSource(const char *url) {
+    virtual status_t    setDataSource(
+            const char *url,
+            const KeyedVector<String8, String8> *) {
         LOGV("setDataSource %s", url);
         mTest = TEST_UNKNOWN;
         if (strncmp(url, kPing, strlen(kPing)) == 0) {