Merge "- Add another parameter in notify() to be able to send timed text sample through listener during video playback. - Add OnTimedTextListener in the MediaPlayer For feature request 800939."
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index bb84bd1..be443d0 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -107,7 +107,7 @@
         : mEOS(false) {
     }
 
-    virtual void notify(int msg, int ext1, int ext2) {
+    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
         Mutex::Autolock autoLock(mLock);
 
         if (msg == MEDIA_ERROR || msg == MEDIA_PLAYBACK_COMPLETE) {
diff --git a/include/media/IMediaPlayerClient.h b/include/media/IMediaPlayerClient.h
index eee6c97..daec1c7 100644
--- a/include/media/IMediaPlayerClient.h
+++ b/include/media/IMediaPlayerClient.h
@@ -28,7 +28,7 @@
 public:
     DECLARE_META_INTERFACE(MediaPlayerClient);
 
-    virtual void notify(int msg, int ext1, int ext2) = 0;
+    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 447942b..e1b6dd6 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -55,7 +55,8 @@
 
 
 // callback mechanism for passing messages to MediaPlayer object
-typedef void (*notify_callback_f)(void* cookie, int msg, int ext1, int ext2);
+typedef void (*notify_callback_f)(void* cookie,
+        int msg, int ext1, int ext2, const Parcel *obj);
 
 // abstract base class - use MediaPlayerInterface
 class MediaPlayerBase : public RefBase
@@ -159,9 +160,10 @@
         mCookie = cookie; mNotify = notifyFunc;
     }
 
-    void        sendEvent(int msg, int ext1=0, int ext2=0) {
+    void        sendEvent(int msg, int ext1=0, int ext2=0,
+                          const Parcel *obj=NULL) {
         Mutex::Autolock autoLock(mNotifyLock);
-        if (mNotify) mNotify(mCookie, msg, ext1, ext2);
+        if (mNotify) mNotify(mCookie, msg, ext1, ext2, obj);
     }
 
 private:
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 528eeb9..748e489 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -37,6 +37,7 @@
     MEDIA_BUFFERING_UPDATE  = 3,
     MEDIA_SEEK_COMPLETE     = 4,
     MEDIA_SET_VIDEO_SIZE    = 5,
+    MEDIA_TIMED_TEXT        = 99,
     MEDIA_ERROR             = 100,
     MEDIA_INFO              = 200,
 };
@@ -129,7 +130,7 @@
 class MediaPlayerListener: virtual public RefBase
 {
 public:
-    virtual void notify(int msg, int ext1, int ext2) = 0;
+    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
 };
 
 class MediaPlayer : public BnMediaPlayerClient,
@@ -166,7 +167,7 @@
             status_t        setLooping(int loop);
             bool            isLooping();
             status_t        setVolume(float leftVolume, float rightVolume);
-            void            notify(int msg, int ext1, int ext2);
+            void            notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
     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);
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 0b0d145a..1e4b585 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1120,6 +1120,7 @@
         mOnErrorListener = null;
         mOnInfoListener = null;
         mOnVideoSizeChangedListener = null;
+        mOnTimedTextListener = null;
         _release();
     }
 
@@ -1301,6 +1302,7 @@
     private static final int MEDIA_BUFFERING_UPDATE = 3;
     private static final int MEDIA_SEEK_COMPLETE = 4;
     private static final int MEDIA_SET_VIDEO_SIZE = 5;
+    private static final int MEDIA_TIMED_TEXT = 99;
     private static final int MEDIA_ERROR = 100;
     private static final int MEDIA_INFO = 200;
 
@@ -1369,6 +1371,11 @@
                 }
                 // No real default action so far.
                 return;
+            case MEDIA_TIMED_TEXT:
+                if (mOnTimedTextListener != null) {
+                    mOnTimedTextListener.onTimedText(mMediaPlayer, (String)msg.obj);
+                }
+                return;
 
             case MEDIA_NOP: // interface test message - ignore
                 break;
@@ -1545,6 +1552,39 @@
 
     private OnVideoSizeChangedListener mOnVideoSizeChangedListener;
 
+    /**
+     * Interface definition of a callback to be invoked when a
+     * timed text is available for display.
+     * {@hide}
+     */
+    public interface OnTimedTextListener
+    {
+        /**
+         * Called to indicate the video size
+         *
+         * @param mp             the MediaPlayer associated with this callback
+         * @param text           the timed text sample which contains the
+         *                       text needed to be displayed.
+         * {@hide}
+         */
+        public void onTimedText(MediaPlayer mp, String text);
+    }
+
+    /**
+     * Register a callback to be invoked when a timed text is available
+     * for display.
+     *
+     * @param listener the callback that will be run
+     * {@hide}
+     */
+    public void setOnTimedTextListener(OnTimedTextListener listener)
+    {
+        mOnTimedTextListener = listener;
+    }
+
+    private OnTimedTextListener mOnTimedTextListener;
+
+
     /* Do not change these values without updating their counterparts
      * in include/media/mediaplayer.h!
      */
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index aa0adf3..23a77d4 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -69,7 +69,7 @@
 public:
     JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
     ~JNIMediaPlayerListener();
-    void notify(int msg, int ext1, int ext2);
+    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
 private:
     JNIMediaPlayerListener();
     jclass      mClass;     // Reference to MediaPlayer class
@@ -102,10 +102,23 @@
     env->DeleteGlobalRef(mClass);
 }
 
-void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2)
+void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, 0);
+    if (obj && obj->dataSize() > 0) {
+        jbyteArray jArray = env->NewByteArray(obj->dataSize());
+        if (jArray != NULL) {
+            jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
+            memcpy(nArray, obj->data(), obj->dataSize());
+            env->ReleaseByteArrayElements(jArray, nArray, 0);
+            env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
+                    msg, ext1, ext2, jArray);
+            env->DeleteLocalRef(jArray);
+        }
+    } else {
+        env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
+                msg, ext1, ext2, NULL);
+    }
 }
 
 // ----------------------------------------------------------------------------
diff --git a/media/libmedia/IMediaPlayerClient.cpp b/media/libmedia/IMediaPlayerClient.cpp
index bf51829..1f135c4 100644
--- a/media/libmedia/IMediaPlayerClient.cpp
+++ b/media/libmedia/IMediaPlayerClient.cpp
@@ -35,13 +35,16 @@
     {
     }
 
-    virtual void notify(int msg, int ext1, int ext2)
+    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());
         data.writeInt32(msg);
         data.writeInt32(ext1);
         data.writeInt32(ext2);
+        if (obj && obj->dataSize() > 0) {
+            data.appendFrom(const_cast<Parcel *>(obj), 0, obj->dataSize());
+        }
         remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
     }
 };
@@ -59,7 +62,12 @@
             int msg = data.readInt32();
             int ext1 = data.readInt32();
             int ext2 = data.readInt32();
-            notify(msg, ext1, ext2);
+            Parcel obj;
+            if (data.dataAvail() > 0) {
+                obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
+            }
+
+            notify(msg, ext1, ext2, &obj);
             return NO_ERROR;
         } break;
         default:
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 0ee0249a..e80e742 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -551,7 +551,7 @@
     return mPlayer->attachAuxEffect(effectId);
 }
 
-void MediaPlayer::notify(int msg, int ext1, int ext2)
+void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
 {
     LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
     bool send = true;
@@ -641,6 +641,9 @@
         mVideoWidth = ext1;
         mVideoHeight = ext2;
         break;
+    case MEDIA_TIMED_TEXT:
+        LOGV("Received timed text message");
+        break;
     default:
         LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
         break;
@@ -653,7 +656,7 @@
     if ((listener != 0) && send) {
         Mutex::Autolock _l(mNotifyLock);
         LOGV("callback application");
-        listener->notify(msg, ext1, ext2);
+        listener->notify(msg, ext1, ext2, obj);
         LOGV("back from callback");
     }
 }
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9c9ac97..6b97708 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1022,7 +1022,8 @@
     return NO_ERROR;
 }
 
-void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2)
+void MediaPlayerService::Client::notify(
+        void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
 {
     Client* client = static_cast<Client*>(cookie);
 
@@ -1039,7 +1040,7 @@
         client->addNewMetadataUpdate(metadata_type);
     }
     LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
-    client->mClient->notify(msg, ext1, ext2);
+    client->mClient->notify(msg, ext1, ext2, obj);
 }
 
 
@@ -1623,7 +1624,8 @@
     return mError;
 }
 
-void MediaPlayerService::AudioCache::notify(void* cookie, int msg, int ext1, int ext2)
+void MediaPlayerService::AudioCache::notify(
+        void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
 {
     LOGV("notify(%p, %d, %d, %d)", cookie, msg, ext1, ext2);
     AudioCache* p = static_cast<AudioCache*>(cookie);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index ff6ccf54..5539a37 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -156,7 +156,8 @@
 
                 sp<IMemoryHeap> getHeap() const { return mHeap; }
 
-        static  void            notify(void* cookie, int msg, int ext1, int ext2);
+        static  void            notify(void* cookie, int msg,
+                                       int ext1, int ext2, const Parcel *obj);
         virtual status_t        dump(int fd, const Vector<String16>& args) const;
 
     private:
@@ -287,7 +288,8 @@
 
                 status_t        setDataSource(const sp<IStreamSource> &source);
 
-        static  void            notify(void* cookie, int msg, int ext1, int ext2);
+        static  void            notify(void* cookie, int msg,
+                                       int ext1, int ext2, const Parcel *obj);
 
                 pid_t           pid() const { return mPid; }
         virtual status_t        dump(int fd, const Vector<String16>& args) const;