Basic plumbing to retrieve metadata from the native player.

IMediaPlayer.h
Added a getMetadata method that mirrors the on in MediaPlayer.java.

MediaPlayer.java
Added a native method to get the metadata from the native player.
Parse the parcel into a Metadata object.

Metadata.java
Added a stub to parse the Parcel returned by the native player into
a set of metadata.

android_media_MediaPlayer.cpp
JNI call to forward the getMetadata call.

MediaPlayerService.cpp
MediaPlayerService::Client implements the new getMetadata method added in IMediaPlayer.h
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 074125f..b6f654f 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -59,6 +59,23 @@
     // @param filter A set of allow and drop rules serialized in a Parcel.
     // @return OK if the invocation was made successfully.
     virtual status_t        setMetadataFilter(const Parcel& filter) = 0;
+
+    // Retrieve a set of metadata.
+    // @param update_only Include only the metadata that have changed
+    //                    since the last invocation of getMetadata.
+    //                    The set is built using the unfiltered
+    //                    notifications the native player sent to the
+    //                    MediaPlayerService during that period of
+    //                    time. If false, all the metadatas are considered.
+    // @param apply_filter If true, once the metadata set has been built based
+    //                     on the value update_only, the current filter is
+    //                     applied.
+    // @param[out] metadata On exit contains a set (possibly empty) of metadata.
+    //                      Valid only if the call returned OK.
+    // @return OK if the invocation was made successfully.
+    virtual status_t        getMetadata(bool update_only,
+                                        bool apply_filter,
+                                        Parcel *metadata) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 8326a21..26b054bd 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -155,6 +155,7 @@
     static  sp<IMemory>     decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
             status_t        invoke(const Parcel& request, Parcel *reply);
             status_t        setMetadataFilter(const Parcel& filter);
+            status_t        getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
 private:
             void            clear_l();
             status_t        seekTo_l(int msec);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 306ea81..a23f535 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -930,8 +930,21 @@
      */
     public Metadata getMetadata(final boolean update_only,
                                 final boolean apply_filter) {
-        // FIXME: Implement.
-        return new Metadata();
+        Parcel reply = Parcel.obtain();
+        Metadata data = new Metadata();
+
+        if (!native_getMetadata(update_only, apply_filter, reply)) {
+            reply.recycle();
+            return null;
+        }
+
+        // Metadata takes over the parcel, don't recycle it unless
+        // there is an error.
+        if (!data.parse(reply)) {
+            reply.recycle();
+            return null;
+        }
+        return data;
     }
 
     /**
@@ -1064,11 +1077,29 @@
      * @param request Parcel destinated to the media player. The
      *                Interface token must be set to the IMediaPlayer
      *                one to be routed correctly through the system.
-     * @param reply Parcel that will contain the reply.
+     * @param reply[out] Parcel that will contain the reply.
      * @return The status code.
      */
     private native final int native_invoke(Parcel request, Parcel reply);
 
+
+    /**
+     * @param update_only If true fetch only the set of metadata that have
+     *                    changed since the last invocation of getMetadata.
+     *                    The set is built using the unfiltered
+     *                    notifications the native player sent to the
+     *                    MediaPlayerService during that period of
+     *                    time. If false, all the metadatas are considered.
+     * @param apply_filter  If true, once the metadata set has been built based on
+     *                     the value update_only, the current filter is applied.
+     * @param reply[out] On return contains the serialized
+     *                   metadata. Valid only if the call was successful.
+     * @return The status code.
+     */
+    private native final boolean native_getMetadata(boolean update_only,
+                                                    boolean apply_filter,
+                                                    Parcel reply);
+
     /**
      * @param request Parcel with the 2 serialized lists of allowed
      *                metadata types followed by the one to be
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
index 7bc4e9c..6525109 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.graphics.Bitmap;
+import android.os.Parcel;
 import android.util.Log;
 
 import java.util.Collections;
@@ -24,6 +25,7 @@
 import java.util.Iterator;
 import java.util.Set;
 
+
 /**
    Class to hold the media's metadata.  Metadata are used
    for human consumption and can be embedded in the media (e.g
@@ -100,6 +102,12 @@
     public static final Set<Integer> MATCH_NONE = Collections.EMPTY_SET;
     public static final Set<Integer> MATCH_ALL = Collections.singleton(ANY);
 
+    private static final int STRING_VAL = 1;
+    private static final int INTEGER_VAL = 2;
+    private static final int LONG_VAL = 3;
+    private static final int DOUBLE_VAL = 4;
+    private static final int TIMED_TEXT_VAL = 2;
+
     /**
      * Helper class to hold a pair (time, text). Can be used to implement caption.
      */
@@ -119,6 +127,11 @@
 
     /* package */ Metadata() {}
 
+    /* package */ boolean parse(Parcel data) {
+        // FIXME: Implement.
+        return true;
+    }
+
     /**
      * @return the number of element in this metadata set.
      */
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 19a2a41..b173129 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -479,9 +479,39 @@
 
     Parcel *filter = parcelForJavaObject(env, request);
 
+    if (filter == NULL ) {
+        jniThrowException(env, "java/lang/RuntimeException", "Filter is null");
+        return UNKNOWN_ERROR;
+    }
+
     return media_player->setMetadataFilter(*filter);
 }
 
+static jboolean
+android_media_MediaPlayer_getMetadata(JNIEnv *env, jobject thiz, jboolean update_only,
+                                      jboolean apply_filter, jobject reply)
+{
+    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
+    if (media_player == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return false;
+    }
+
+    Parcel *metadata = parcelForJavaObject(env, reply);
+
+    if (metadata == NULL ) {
+        jniThrowException(env, "java/lang/RuntimeException", "Reply parcel is null");
+        return false;
+    }
+
+    metadata->freeData();
+    // On return metadata is positioned at the beginning of the
+    // metadata. Note however that the parcel actually starts with the
+    // return code so you should not rewind the parcel using
+    // setDataPosition(0).
+    return media_player->getMetadata(update_only, apply_filter, metadata) == OK;
+}
+
 
 static void
 android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
@@ -546,6 +576,7 @@
     {"getFrameAt",          "(I)Landroid/graphics/Bitmap;",     (void *)android_media_MediaPlayer_getFrameAt},
     {"native_invoke",       "(Landroid/os/Parcel;Landroid/os/Parcel;)I",(void *)android_media_MediaPlayer_invoke},
     {"native_setMetadataFilter", "(Landroid/os/Parcel;)I",      (void *)android_media_MediaPlayer_setMetadataFilter},
+    {"native_getMetadata", "(ZZLandroid/os/Parcel;)Z",          (void *)android_media_MediaPlayer_getMetadata},
     {"native_setup",        "(Ljava/lang/Object;)V",            (void *)android_media_MediaPlayer_native_setup},
     {"native_finalize",     "()V",                              (void *)android_media_MediaPlayer_native_finalize},
 };
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 131e510..5d9db10 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -42,6 +42,7 @@
     SET_VOLUME,
     INVOKE,
     SET_METADATA_FILTER,
+    GET_METADATA,
 };
 
 class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -176,8 +177,7 @@
     status_t invoke(const Parcel& request, Parcel *reply)
     { // Avoid doing any extra copy. The interface descriptor should
       // have been set by MediaPlayer.java.
-        status_t retcode = remote()->transact(INVOKE, request, reply);
-        return retcode;
+        return remote()->transact(INVOKE, request, reply);
     }
 
     status_t setMetadataFilter(const Parcel& request)
@@ -188,6 +188,17 @@
         remote()->transact(SET_METADATA_FILTER, request, &reply);
         return reply.readInt32();
     }
+
+    status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply)
+    {
+        Parcel request;
+        request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+        // TODO: Burning 2 ints for 2 boolean. Should probably use flags in an int here.
+        request.writeInt32(update_only);
+        request.writeInt32(apply_filter);
+        remote()->transact(GET_METADATA, request, reply);
+        return reply->readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -288,6 +299,14 @@
             reply->writeInt32(setMetadataFilter(data));
             return NO_ERROR;
         } break;
+        case GET_METADATA: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            const status_t retcode = getMetadata(data.readInt32(), data.readInt32(), reply);
+            reply->setDataPosition(0);
+            reply->writeInt32(retcode);
+            reply->setDataPosition(0);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index d8c622f..6b35fa7 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -211,14 +211,23 @@
 status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
 {
     LOGD("setMetadataFilter");
-    Mutex::Autolock _l(mLock);
-    if (mPlayer == NULL)
-    {
+    Mutex::Autolock lock(mLock);
+    if (mPlayer == NULL) {
         return NO_INIT;
     }
     return mPlayer->setMetadataFilter(filter);
 }
 
+status_t MediaPlayer::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
+{
+    LOGD("getMetadata");
+    Mutex::Autolock lock(mLock);
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+    return mPlayer->getMetadata(update_only, apply_filter, metadata);
+}
+
 status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
 {
     LOGV("setVideoSurface");
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 3adbfac..04aab81 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -846,6 +846,16 @@
     return status;
 }
 
+status_t MediaPlayerService::Client::getMetadata(bool update_only, bool apply_filter, Parcel *metadata)
+{
+    status_t status;
+    metadata->writeInt32(-1);  // Placeholder for the return code
+
+    // FIXME: Implement, query the native player and do the optional filtering, etc...
+    status = OK;
+    return status;
+}
+
 status_t MediaPlayerService::Client::prepareAsync()
 {
     LOGV("[%d] prepareAsync", mConnId);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index b915e86..7920559 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -191,6 +191,7 @@
         virtual status_t        setVolume(float leftVolume, float rightVolume);
         virtual status_t        invoke(const Parcel& request, Parcel *reply);
         virtual status_t        setMetadataFilter(const Parcel& filter);
+        virtual status_t        getMetadata(bool update_only, bool apply_filter, Parcel *metadata);
 
         sp<MediaPlayerBase>     createPlayer(player_type playerType);
                 status_t        setDataSource(const char *url);