Implemented the metadata changed notification filters.

IMediaPlayer:
new setMetadataFilter method so set a filter (2 lists of allowed and blocked metadata type)
serialized in a Parcel.

MediaPlayer.java/android_media_MediaPlayer.cpp/mediaplayer.cpp
new setMetadataFilter that passes the filter down to the MediaPlayerService's binder interface.

MediaPlayerService.cpp
The Client inner class holds the allowed and blocked metadata types.
These are in 2 vectors that get populated in the setMetadataFilter.

A new shourldDropMetadata method returns true if a type of metadata should be dropped according
to the filters.

The notify method in run the metadata update notifications thru the filter and possibly drop them.
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index 85aeb30..074125f 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -52,8 +52,13 @@
     // @param request Parcel that must start with the media player
     // interface token.
     // @param[out] reply Parcel to hold the reply data. Cannot be null.
-    // @return OK if the invocation was made. PERMISSION_DENIED otherwise.
+    // @return OK if the invocation was made successfully.
     virtual status_t        invoke(const Parcel& request, Parcel *reply) = 0;
+
+    // Set a new metadata filter.
+    // @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;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index dd8ea19..8326a21 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -97,6 +97,8 @@
     MEDIA_INFO_BAD_INTERLEAVING = 800,
     // The media is not seekable (e.g live stream).
     MEDIA_INFO_NOT_SEEKABLE = 801,
+    // New media metadata is available.
+    MEDIA_INFO_METADATA_UPDATE = 802,
 };
 
 
@@ -152,6 +154,7 @@
     static  sp<IMemory>     decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
     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);
 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 139fb41..306ea81 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -937,25 +937,49 @@
     /**
      * Set a filter for the metadata update notification and update
      * retrieval. The caller provides 2 set of metadata keys, allowed
-     * and disallowed. The disallow set always takes the precedence
-     * over the allowed one.
+     * and blocked. The blocked set always takes precedence over the
+     * allowed one.
      * Metadata.MATCH_ALL and Metadata.MATCH_NONE are 2 sets available as
-     * shorthands to allow/disallow all or no metadata.
+     * shorthands to allow/block all or no metadata.
      *
      * By default, there is no filter set.
      *
      * @param allow Is the set of metadata the client is interested
-     *              receiving new notifications for.
-     * @param disallow Is the set of metadata the client is not interested
-     *                 receiving new notifications for.
+     *              in receiving new notifications for.
+     * @param block Is the set of metadata the client is not interested
+     *              in receiving new notifications for.
      * @return The call status code.
      *
      // FIXME: unhide.
      * {@hide}
      */
-    public int setMetadataFilter(Set<Integer> allow, Set<Integer> disallow) {
-        // FIXME: Implement.
-        return 0;
+    public int setMetadataFilter(Set<Integer> allow, Set<Integer> block) {
+        // Do our serialization manually instead of calling
+        // Parcel.writeArray since the sets are made of the same type
+        // we avoid paying the price of calling writeValue (used by
+        // writeArray) which burns an extra int per element to encode
+        // the type.
+        Parcel request =  newRequest();
+
+        // The parcel starts already with an interface token. There
+        // are 2 filters. Each one starts with a 4bytes number to
+        // store the len followed by a number of int (4 bytes as well)
+        // representing the metadata type.
+        int capacity = request.dataSize() + 4 * (1 + allow.size() + 1 + block.size());
+
+        if (request.dataCapacity() < capacity) {
+            request.setDataCapacity(capacity);
+        }
+
+        request.writeInt(allow.size());
+        for(Integer t: allow) {
+            request.writeInt(t);
+        }
+        request.writeInt(block.size());
+        for(Integer t: block) {
+            request.writeInt(t);
+        }
+        return native_setMetadataFilter(request);
     }
 
     /**
@@ -1045,6 +1069,15 @@
      */
     private native final int native_invoke(Parcel request, Parcel reply);
 
+    /**
+     * @param request Parcel with the 2 serialized lists of allowed
+     *                metadata types followed by the one to be
+     *                dropped. Each list starts with an integer
+     *                indicating the number of metadata type elements.
+     * @return The status code.
+     */
+    private native final int native_setMetadataFilter(Parcel request);
+
     private native final void native_setup(Object mediaplayer_this);
     private native final void native_finalize();
 
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
index 80748a9..7bc4e9c 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -56,6 +56,7 @@
     //
 
     public static final int ANY = 0;  // Never used for metadata returned, only for filtering.
+                                      // Keep in sync with kAny in MediaPlayerService.cpp
 
     // TODO: Should we use numbers compatible with the metadata retriever?
     public static final int TITLE = 1;           // String
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 2c08c16..19a2a41 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -455,18 +455,34 @@
     sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
     if (media_player == NULL ) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return UNKNOWN_ERROR;
     }
 
 
     Parcel *request = parcelForJavaObject(env, java_request);
     Parcel *reply = parcelForJavaObject(env, java_reply);
 
-    const status_t status = media_player->invoke(*request, reply);
     // Don't use process_media_player_call which use the async loop to
     // report errors, instead returns the status.
-    return status;
+    return media_player->invoke(*request, reply);
 }
 
+// Sends the new filter to the client.
+static jint
+android_media_MediaPlayer_setMetadataFilter(JNIEnv *env, jobject thiz, jobject request)
+{
+    sp<MediaPlayer> media_player = getMediaPlayer(env, thiz);
+    if (media_player == NULL ) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return UNKNOWN_ERROR;
+    }
+
+    Parcel *filter = parcelForJavaObject(env, request);
+
+    return media_player->setMetadataFilter(*filter);
+}
+
+
 static void
 android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
 {
@@ -529,6 +545,7 @@
     {"setVolume",           "(FF)V",                            (void *)android_media_MediaPlayer_setVolume},
     {"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_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 3f278f4..131e510 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -41,6 +41,7 @@
     SET_LOOPING,
     SET_VOLUME,
     INVOKE,
+    SET_METADATA_FILTER,
 };
 
 class BpMediaPlayer: public BpInterface<IMediaPlayer>
@@ -178,6 +179,15 @@
         status_t retcode = remote()->transact(INVOKE, request, reply);
         return retcode;
     }
+
+    status_t setMetadataFilter(const Parcel& request)
+    {
+        Parcel reply;
+        // Avoid doing any extra copy of the request. The interface
+        // descriptor should have been set by MediaPlayer.java.
+        remote()->transact(SET_METADATA_FILTER, request, &reply);
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -273,6 +283,11 @@
             invoke(data, reply);
             return NO_ERROR;
         } break;
+        case SET_METADATA_FILTER: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            reply->writeInt32(setMetadataFilter(data));
+            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 4683166..d8c622f 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -208,7 +208,16 @@
     return INVALID_OPERATION;
 }
 
-
+status_t MediaPlayer::setMetadataFilter(const Parcel& filter)
+{
+    LOGD("setMetadataFilter");
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL)
+    {
+        return NO_INIT;
+    }
+    return mPlayer->setMetadataFilter(filter);
+}
 
 status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface)
 {
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index c4dccdf..3adbfac 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -69,6 +69,150 @@
 #undef __KERNEL__
 #endif
 
+namespace {
+using android::status_t;
+using android::OK;
+using android::BAD_VALUE;
+using android::NOT_ENOUGH_DATA;
+using android::Parcel;
+using android::Vector;
+
+// Max number of entries in the filter.
+const int kMaxFilterSize = 64;  // I pulled that out of thin air.
+
+// Keep in sync with ANY in Metadata.java
+const int32_t kAny = 0;
+
+// To order the metadata types in the vector-filter.
+int lessThan(const int32_t *lhs, const int32_t *rhs)
+{
+    return *lhs < *rhs ? 0 : 1;
+}
+
+// Unmarshall a filter from a Parcel.
+// Filter format in a parcel:
+//
+//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       number of entries (n)                   |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       metadata type 1                         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       metadata type 2                         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//  ....
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |                       metadata type n                         |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+//
+// @param p Parcel that should start with a filter.
+// @param[out] filter On exit contains the list of metadata type to be
+//                    filtered.
+// @param[out] status On exit contains the status code to be returned.
+// @return true if the parcel starts with a valid filter.
+bool unmarshallFilter(const Parcel& p,
+                      Vector<int32_t> *filter,
+                      status_t *status)
+{
+    int32_t s;
+    if (p.readInt32(&s) != OK)
+    {
+        LOGE("Failed to read filter's length");
+        *status = NOT_ENOUGH_DATA;
+        return false;
+    }
+
+    if( s > kMaxFilterSize || s < 0)
+    {
+        LOGE("Invalid filter len %d", s);
+        *status = BAD_VALUE;
+        return false;
+    }
+
+    size_t size = s;
+
+    filter->clear();
+    filter->setCapacity(size);
+
+    s *= sizeof(int32_t);
+
+    if (p.dataAvail() < static_cast<size_t>(s))
+    {
+        LOGE("Filter too short expected %d but got %d", s, p.dataAvail());
+        *status = NOT_ENOUGH_DATA;
+        return false;
+    }
+
+    const int32_t *data = static_cast<const int32_t*>(p.readInplace(s));
+
+    if (NULL == data )
+    {
+        LOGE("Filter had no data");
+        *status = BAD_VALUE;
+        return false;
+    }
+
+    // TODO: The stl impl of vector would be more efficient here
+    // because it degenerates into a memcpy on pod types. Try to
+    // replace later or use stl::set.
+    for (size_t i = 0; i < size; ++i)
+    {
+        filter->push(*data);
+        ++data;
+    }
+    *status = OK;
+    return true;
+}
+
+bool unmarshallBothFilters(const Parcel& p,
+                           Vector<int32_t> *allow,
+                           Vector<int32_t> *block,
+                           status_t *status)
+{
+    if (!(unmarshallFilter(p, allow, status) && unmarshallFilter(p, block, status)))
+    {
+        return false;
+    }
+    allow->sort(lessThan);
+    block->sort(lessThan);
+    return true;
+}
+
+// @param filter Should be sorted in ascending order.
+// @param val To be searched.
+// @return true if a match was found.
+bool findMetadata(const Vector<int32_t> filter, const int32_t val)
+{
+    // Deal with empty and ANY right away
+    if (filter.isEmpty()) return false;
+    if (filter[0] == kAny) return true;
+
+    ssize_t min = 0;
+    ssize_t max = filter.size() - 1;
+    ssize_t mid;
+    do
+    {
+        mid = (min + max) / 2;
+        if (val > filter[mid])
+        {
+            min = mid + 1;
+        }
+        else
+        {
+            max = mid - 1;
+        }
+        if (filter[mid] == val)
+        {
+            return true;
+        }
+    }
+    while(min <= max);
+    return false;
+}
+
+}  // anonymous namespace
+
+
 namespace android {
 
 // TODO: Temp hack until we can register players
@@ -686,6 +830,22 @@
     return p->invoke(request, reply);
 }
 
+// This call doesn't need to access the native player.
+status_t MediaPlayerService::Client::setMetadataFilter(const Parcel& filter)
+{
+    status_t status;
+    Vector<int32_t> allow, drop;
+
+    if (unmarshallBothFilters(filter, &allow, &drop, &status))
+    {
+        Mutex::Autolock l(mLock);
+
+        mMetadataAllow = allow;
+        mMetadataDrop = drop;
+    }
+    return status;
+}
+
 status_t MediaPlayerService::Client::prepareAsync()
 {
     LOGV("[%d] prepareAsync", mConnId);
@@ -808,10 +968,35 @@
 void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2)
 {
     Client* client = static_cast<Client*>(cookie);
+
+    if (MEDIA_INFO == msg &&
+        MEDIA_INFO_METADATA_UPDATE == ext1 &&
+        client->shouldDropMetadata(ext2 /* metadata type */)) {
+        return;
+    }
     LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
     client->mClient->notify(msg, ext1, ext2);
 }
 
+bool MediaPlayerService::Client::shouldDropMetadata(int code) const
+{
+    Mutex::Autolock l(mLock);
+
+    if (findMetadata(mMetadataDrop, code))
+    {
+        return true;
+    }
+
+    if (mMetadataAllow.isEmpty() || findMetadata(mMetadataAllow, code))
+    {
+        return false;
+    }
+    else
+    {
+        return true;
+    }
+}
+
 #if CALLBACK_ANTAGONIZER
 const int Antagonizer::interval = 10000; // 10 msecs
 
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 12f2231..b915e86 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/Vector.h>
 #include <ui/SurfaceComposerClient.h>
 
 #include <media/IMediaPlayerService.h>
@@ -143,7 +144,7 @@
         sp<MemoryHeapBase>  mHeap;
         float               mMsecsPerFrame;
         uint16_t            mChannelCount;
-        uint16_t			mFormat;
+        uint16_t            mFormat;
         ssize_t             mFrameCount;
         uint32_t            mSampleRate;
         uint32_t            mSize;
@@ -168,6 +169,7 @@
 
             void                removeClient(wp<Client> client);
 
+
 private:
 
     class Client : public BnMediaPlayer {
@@ -188,6 +190,7 @@
         virtual status_t        setLooping(int loop);
         virtual status_t        setVolume(float leftVolume, float rightVolume);
         virtual status_t        invoke(const Parcel& request, Parcel *reply);
+        virtual status_t        setMetadataFilter(const Parcel& filter);
 
         sp<MediaPlayerBase>     createPlayer(player_type playerType);
                 status_t        setDataSource(const char *url);
@@ -210,6 +213,12 @@
 
         sp<MediaPlayerBase>     getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; }
 
+
+        /**
+         * @return true if the metadata should be dropped.
+         */
+        bool shouldDropMetadata(int code) const;
+
         mutable     Mutex                       mLock;
                     sp<MediaPlayerBase>         mPlayer;
                     sp<MediaPlayerService>      mService;
@@ -219,6 +228,10 @@
                     status_t                    mStatus;
                     bool                        mLoop;
                     int32_t                     mConnId;
+        // FIXME: Replace Vector<> with std::set<> when available. std::set support find.
+        // Metadata filters.
+                    Vector<int32_t>             mMetadataAllow;  // protected by mLock
+                    Vector<int32_t>             mMetadataDrop;  // protected by mLock
 #if CALLBACK_ANTAGONIZER
                     Antagonizer*                mAntagonizer;
 #endif