Merge "MediaPlayer: initial timed id3 support"
diff --git a/api/current.txt b/api/current.txt
index 8f9641c..5bf0fbe 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15996,6 +15996,7 @@
     method public void setOnInfoListener(android.media.MediaPlayer.OnInfoListener);
     method public void setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener);
     method public void setOnSeekCompleteListener(android.media.MediaPlayer.OnSeekCompleteListener);
+    method public void setOnTimedMetaDataListener(android.media.MediaPlayer.OnTimedMetaDataListener);
     method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
     method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
     method public void setPlaybackRate(float, int);
@@ -16053,6 +16054,10 @@
     method public abstract void onSeekComplete(android.media.MediaPlayer);
   }
 
+  public static abstract interface MediaPlayer.OnTimedMetaDataListener {
+    method public abstract void onTimedMetaData(android.media.MediaPlayer, android.media.TimedMetaData);
+  }
+
   public static abstract interface MediaPlayer.OnTimedTextListener {
     method public abstract void onTimedText(android.media.MediaPlayer, android.media.TimedText);
   }
@@ -16068,6 +16073,7 @@
     method public int getTrackType();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int MEDIA_TRACK_TYPE_AUDIO = 2; // 0x2
+    field public static final int MEDIA_TRACK_TYPE_METADATA = 5; // 0x5
     field public static final int MEDIA_TRACK_TYPE_SUBTITLE = 4; // 0x4
     field public static final int MEDIA_TRACK_TYPE_TIMEDTEXT = 3; // 0x3
     field public static final int MEDIA_TRACK_TYPE_UNKNOWN = 0; // 0x0
@@ -16542,6 +16548,11 @@
     field public static final int OPTIONS_RECYCLE_INPUT = 2; // 0x2
   }
 
+  public class TimedMetaData {
+    method public byte[] getRawData();
+    method public long getTimeUs();
+  }
+
   public final class TimedText {
     method public android.graphics.Rect getBounds();
     method public java.lang.String getText();
diff --git a/api/system-current.txt b/api/system-current.txt
index 0f837c2..44bbe5f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -17209,6 +17209,7 @@
     method public void setOnInfoListener(android.media.MediaPlayer.OnInfoListener);
     method public void setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener);
     method public void setOnSeekCompleteListener(android.media.MediaPlayer.OnSeekCompleteListener);
+    method public void setOnTimedMetaDataListener(android.media.MediaPlayer.OnTimedMetaDataListener);
     method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
     method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
     method public void setPlaybackRate(float, int);
@@ -17266,6 +17267,10 @@
     method public abstract void onSeekComplete(android.media.MediaPlayer);
   }
 
+  public static abstract interface MediaPlayer.OnTimedMetaDataListener {
+    method public abstract void onTimedMetaData(android.media.MediaPlayer, android.media.TimedMetaData);
+  }
+
   public static abstract interface MediaPlayer.OnTimedTextListener {
     method public abstract void onTimedText(android.media.MediaPlayer, android.media.TimedText);
   }
@@ -17281,6 +17286,7 @@
     method public int getTrackType();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int MEDIA_TRACK_TYPE_AUDIO = 2; // 0x2
+    field public static final int MEDIA_TRACK_TYPE_METADATA = 5; // 0x5
     field public static final int MEDIA_TRACK_TYPE_SUBTITLE = 4; // 0x4
     field public static final int MEDIA_TRACK_TYPE_TIMEDTEXT = 3; // 0x3
     field public static final int MEDIA_TRACK_TYPE_UNKNOWN = 0; // 0x0
@@ -17757,6 +17763,11 @@
     field public static final int OPTIONS_RECYCLE_INPUT = 2; // 0x2
   }
 
+  public class TimedMetaData {
+    method public byte[] getRawData();
+    method public long getTimeUs();
+  }
+
   public final class TimedText {
     method public android.graphics.Rect getBounds();
     method public java.lang.String getText();
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index cb80bc4..210d08f 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1837,6 +1837,7 @@
         public static final int MEDIA_TRACK_TYPE_AUDIO = 2;
         public static final int MEDIA_TRACK_TYPE_TIMEDTEXT = 3;
         public static final int MEDIA_TRACK_TYPE_SUBTITLE = 4;
+        public static final int MEDIA_TRACK_TYPE_METADATA = 5;
 
         final int mTrackType;
         final MediaFormat mFormat;
@@ -2577,6 +2578,7 @@
     private static final int MEDIA_ERROR = 100;
     private static final int MEDIA_INFO = 200;
     private static final int MEDIA_SUBTITLE_DATA = 201;
+    private static final int MEDIA_META_DATA = 202;
 
     private TimeProvider mTimeProvider;
 
@@ -2724,6 +2726,18 @@
                 }
                 return;
 
+            case MEDIA_META_DATA:
+                if (mOnTimedMetaDataListener == null) {
+                    return;
+                }
+                if (msg.obj instanceof Parcel) {
+                    Parcel parcel = (Parcel) msg.obj;
+                    TimedMetaData data = TimedMetaData.createTimedMetaDataFromParcel(parcel);
+                    parcel.recycle();
+                    mOnTimedMetaDataListener.onTimedMetaData(mMediaPlayer, data);
+                }
+                return;
+
             case MEDIA_NOP: // interface test message - ignore
                 break;
 
@@ -2960,6 +2974,46 @@
 
     private OnSubtitleDataListener mOnSubtitleDataListener;
 
+    /**
+     * Interface definition of a callback to be invoked when a
+     * track has timed metadata available.
+     *
+     * @see MediaPlayer#setOnTimedMetaDataListener(OnTimedMetaDataListener)
+     */
+    public interface OnTimedMetaDataListener
+    {
+        /**
+         * Called to indicate avaliable timed metadata
+         * <p>
+         * This method will be called as timed metadata is extracted from the media,
+         * in the same order as it occurs in the media. The timing of this event is
+         * not controlled by the associated timestamp.
+         *
+         * @param mp             the MediaPlayer associated with this callback
+         * @param data           the timed metadata sample associated with this event
+         */
+        public void onTimedMetaData(MediaPlayer mp, TimedMetaData data);
+    }
+
+    /**
+     * Register a callback to be invoked when a selected track has timed metadata available.
+     * <p>
+     * Currently only HTTP live streaming data URI's embedded with timed ID3 tags generates
+     * {@link TimedMetaData}.
+     *
+     * @see MediaPlayer#selectTrack(int)
+     * @see MediaPlayer.OnTimedMetaDataListener
+     * @see TimedMetaData
+     *
+     * @param listener the callback that will be run
+     */
+    public void setOnTimedMetaDataListener(OnTimedMetaDataListener listener)
+    {
+        mOnTimedMetaDataListener = listener;
+    }
+
+    private OnTimedMetaDataListener mOnTimedMetaDataListener;
+
     /* Do not change these values without updating their counterparts
      * in include/media/mediaplayer.h!
      */
diff --git a/media/java/android/media/TimedMetaData.java b/media/java/android/media/TimedMetaData.java
new file mode 100644
index 0000000..dceb050
--- /dev/null
+++ b/media/java/android/media/TimedMetaData.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2015 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.os.Parcel;
+
+/**
+ * Class that embodies a piece of timed metadata, including
+ *
+ * <ul>
+ * <li> a time stamp, and </li>
+ * <li> raw uninterpreted byte-array extracted directly from the container. </li>
+ * </ul>
+ *
+ * @see MediaPlayer#setOnTimedMetaDataListener(android.media.MediaPlayer.OnTimedMetaDataListener)
+ */
+
+public class TimedMetaData {
+    private static final String TAG = "TimedMetaData";
+
+    private long mTimeUs;
+    private byte[] mRawData;
+
+    /**
+     * @hide
+     */
+    static TimedMetaData createTimedMetaDataFromParcel(Parcel parcel) {
+        return new TimedMetaData(parcel);
+    }
+
+    private TimedMetaData(Parcel parcel) {
+        if (!parseParcel(parcel)) {
+            throw new IllegalArgumentException("parseParcel() fails");
+        }
+    }
+
+    public long getTimeUs() {
+        return mTimeUs;
+    }
+
+    public byte[] getRawData() {
+        return mRawData;
+    }
+
+    private boolean parseParcel(Parcel parcel) {
+        parcel.setDataPosition(0);
+        if (parcel.dataAvail() == 0) {
+            return false;
+        }
+
+        mTimeUs = parcel.readLong();
+        mRawData = new byte[parcel.readInt()];
+        parcel.readByteArray(mRawData);
+
+        return true;
+    }
+}