Metadata.java revision 6fa41bbb56e0756d3eac15d6314007e4a450c9d3
19193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania/*
29193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania * Copyright (C) 2009 The Android Open Source Project
39193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania *
49193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania * Licensed under the Apache License, Version 2.0 (the "License");
59193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania * you may not use this file except in compliance with the License.
69193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania * You may obtain a copy of the License at
79193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania *
89193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania *      http://www.apache.org/licenses/LICENSE-2.0
99193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania *
109193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania * Unless required by applicable law or agreed to in writing, software
119193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania * distributed under the License is distributed on an "AS IS" BASIS,
129193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania * See the License for the specific language governing permissions and
149193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania * limitations under the License.
159193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania */
169193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
179193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Cataniapackage android.media;
189193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
199193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Cataniaimport android.graphics.Bitmap;
205d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Cataniaimport android.os.Parcel;
219193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Cataniaimport android.util.Log;
229193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
23cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Cataniaimport java.util.Calendar;
249193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Cataniaimport java.util.Collections;
259193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Cataniaimport java.util.Date;
26a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Cataniaimport java.util.HashMap;
27cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Cataniaimport java.util.Set;
28cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Cataniaimport java.util.TimeZone;
299193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
305d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Catania
319193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania/**
329193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   Class to hold the media's metadata.  Metadata are used
339193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   for human consumption and can be embedded in the media (e.g
349193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   shoutcast) or available from an external source. The source can be
359193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   local (e.g thumbnail stored in the DB) or remote (e.g caption
369193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   server).
379193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
389193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   Metadata is like a Bundle. It is sparse and each key can occur at
399193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   most once. The key is an integer and the value is the actual metadata.
409193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
419193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   The caller is expected to know the type of the metadata and call
429193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   the right get* method to fetch its value.
439193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
449193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   // FIXME: unhide.
459193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   {@hide}
469193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania */
479193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Cataniapublic class Metadata
489193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania{
499193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // The metadata are keyed using integers rather than more heavy
509193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // weight strings. We considered using Bundle to ship the metadata
519193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // between the native layer and the java layer but dropped that
529193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // option since keeping in sync a native implementation of Bundle
539193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // and the java one would be too burdensome. Besides Bundle uses
549193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // String for its keys.
559193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // The key range [0 8192) is reserved for the system.
569193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    //
579193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // We manually serialize the data in Parcels. For large memory
589193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // blob (bitmaps, raw pictures) we use MemoryFile which allow the
59a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // client to make the data purge-able once it is done with it.
609193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    //
619193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
629193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int ANY = 0;  // Never used for metadata returned, only for filtering.
63b2c693919be966f179080a9ec70a7a82dbf57627Nicolas Catania                                      // Keep in sync with kAny in MediaPlayerService.cpp
649193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
659193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // TODO: Should we use numbers compatible with the metadata retriever?
669193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int TITLE = 1;           // String
679193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int COMMENT = 2;         // String
689193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int COPYRIGHT = 3;       // String
699193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int ALBUM = 4;           // String
709193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int ARTIST = 5;          // String
719193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int AUTHOR = 6;          // String
729193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int COMPOSER = 7;        // String
739193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int GENRE = 8;           // String
749193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int DATE = 9;            // Date
759193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int DURATION = 10;       // Integer(millisec)
769193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int CD_TRACK_NUM = 11;   // Integer 1-based
779193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int CD_TRACK_MAX = 12;   // Integer
789193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int RATING = 13;         // String
799193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int ALBUM_ART = 14;      // byte[]
809193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int VIDEO_FRAME = 15;    // Bitmap
819193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int CAPTION = 16;        // TimedText
829193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
839193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int BIT_RATE = 17;       // Integer, Aggregate rate of
849193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania                                                 // all the streams in bps.
859193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
869193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int AUDIO_BIT_RATE = 18; // Integer, bps
879193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int VIDEO_BIT_RATE = 19; // Integer, bps
889193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int AUDIO_SAMPLE_RATE = 20; // Integer, Hz
899193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int VIDEO_FRAME_RATE = 21;  // Integer, Hz
909193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
919193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // See RFC2046 and RFC4281.
929193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int MIME_TYPE = 22;      // String
939193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int AUDIO_CODEC = 23;    // String
949193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int VIDEO_CODEC = 24;    // String
959193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
969193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int VIDEO_HEIGHT = 25;   // Integer
979193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int VIDEO_WIDTH = 26;    // Integer
989193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int NUM_TRACKS = 27;     // Integer
999193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int DRM_CRIPPLED = 28;   // Boolean
100716383a686b086f68533a51785ba77186359ce6bNicolas Catania
101716383a686b086f68533a51785ba77186359ce6bNicolas Catania    // Playback capabilities.
102716383a686b086f68533a51785ba77186359ce6bNicolas Catania    public static final int PAUSE_AVAILABLE = 29;         // Boolean
103716383a686b086f68533a51785ba77186359ce6bNicolas Catania    public static final int SEEK_BACKWARD_AVAILABLE = 30; // Boolean
104716383a686b086f68533a51785ba77186359ce6bNicolas Catania    public static final int SEEK_FORWARD_AVAILABLE = 31;  // Boolean
105716383a686b086f68533a51785ba77186359ce6bNicolas Catania
106716383a686b086f68533a51785ba77186359ce6bNicolas Catania    private static final int LAST_SYSTEM = 31;
107a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private static final int FIRST_CUSTOM = 8092;
1089193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
1099193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // Shorthands to set the MediaPlayer's metadata filter.
1109193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final Set<Integer> MATCH_NONE = Collections.EMPTY_SET;
1119193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final Set<Integer> MATCH_ALL = Collections.singleton(ANY);
1129193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
113cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int STRING_VAL     = 1;
114cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int INTEGER_VAL    = 2;
115cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int BOOLEAN_VAL    = 3;
116cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int LONG_VAL       = 4;
117cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int DOUBLE_VAL     = 5;
118cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int TIMED_TEXT_VAL = 6;
119cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int DATE_VAL       = 7;
120cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int BYTE_ARRAY_VAL = 8;
121cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // FIXME: misses a type for shared heap is missing (MemoryFile).
122cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // FIXME: misses a type for bitmaps.
123cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    private static final int LAST_TYPE = 8;
124a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
125a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private static final String TAG = "media.Metadata";
1266fa41bbb56e0756d3eac15d6314007e4a450c9d3niko    private static final int kInt32Size = 4;
1276fa41bbb56e0756d3eac15d6314007e4a450c9d3niko    private static final int kMetaHeaderSize = 2 * kInt32Size; //  size + marker
1286fa41bbb56e0756d3eac15d6314007e4a450c9d3niko    private static final int kRecordHeaderSize = 3 * kInt32Size; // size + id + type
1296fa41bbb56e0756d3eac15d6314007e4a450c9d3niko
130a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private static final int kMetaMarker = 0x4d455441;  // 'M' 'E' 'T' 'A'
131a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
132a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // After a successful parsing, set the parcel with the serialized metadata.
133a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private Parcel mParcel;
134a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
135a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Map to associate a Metadata key (e.g TITLE) with the offset of
136a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // the record's payload in the parcel.
137a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Used to look up if a key was present too.
138a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Key: Metadata ID
139a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Value: Offset of the metadata type field in the record.
140cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    private final HashMap<Integer, Integer> mKeyToPosMap =
141cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            new HashMap<Integer, Integer>();
1425d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Catania
1439193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    /**
144cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania     * Helper class to hold a triple (time, duration, text). Can be used to
145cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania     * implement caption.
1469193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     */
1479193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public class TimedText {
1489193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania        private Date mTime;
149cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        private int mDuration;  // millisec
1509193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania        private String mText;
151cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
152cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        public TimedText(Date time, int duration, String text) {
1539193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania            mTime = time;
154cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            mDuration = duration;
1559193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania            mText = text;
1569193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania        }
157cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
1589193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania        public String toString() {
1599193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania            StringBuilder res = new StringBuilder(80);
160cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            res.append(mTime).append("-").append(mDuration)
161cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania                    .append(":").append(mText);
1629193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania            return res.toString();
1639193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania        }
1649193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
1659193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
166a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public Metadata() { }
1679193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
168a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    /**
169a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * Go over all the records, collecting metadata keys and records'
170a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * type field offset in the Parcel. These are stored in
171a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * mKeyToPosMap for latter retrieval.
172a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * Format of a metadata record:
173a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     <pre>
174a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                         1                   2                   3
175a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      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
176a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
177a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                     record size                               |
178a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
179a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                     metadata key                              |  // TITLE
180a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
181a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                     metadata type                             |  // STRING_VAL
182a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
183a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                                                               |
184a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                .... metadata payload ....                     |
185a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                                                               |
186a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
187a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     </pre>
188a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @param parcel With the serialized records.
189a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @param bytesLeft How many bytes in the parcel should be processed.
190a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @return false if an error occurred during parsing.
191a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     */
192a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private boolean scanAllRecords(Parcel parcel, int bytesLeft) {
193a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        int recCount = 0;
194a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        boolean error = false;
195a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
196a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        mKeyToPosMap.clear();
197a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        while (bytesLeft > kRecordHeaderSize) {
198a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            final int start = parcel.dataPosition();
199a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Check the size.
200a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            final int size = parcel.readInt();
201a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
202a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            if (size <= kRecordHeaderSize) {  // at least 1 byte should be present.
203a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                Log.e(TAG, "Record is too short");
204a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                error = true;
205a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                break;
206a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            }
207a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
208a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Check the metadata key.
209a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            final int metadataId = parcel.readInt();
210a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            if (!checkMetadataId(metadataId)) {
211a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                error = true;
212a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                break;
213a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            }
214a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
215a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Store the record offset which points to the type
216a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // field so we can later on read/unmarshall the record
217a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // payload.
218a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            if (mKeyToPosMap.containsKey(metadataId)) {
219a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                Log.e(TAG, "Duplicate metadata ID found");
220a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                error = true;
221a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                break;
222a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            }
223a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
224a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            mKeyToPosMap.put(metadataId, parcel.dataPosition());
225a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
226a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Check the metadata type.
227a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            final int metadataType = parcel.readInt();
228a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            if (metadataType <= 0 || metadataType > LAST_TYPE) {
229a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                Log.e(TAG, "Invalid metadata type " + metadataType);
230a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                error = true;
231a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                break;
232a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            }
233a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
234a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Skip to the next one.
235a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            parcel.setDataPosition(start + size);
236a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            bytesLeft -= size;
237a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            ++recCount;
238a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
239a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
240a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (0 != bytesLeft || error) {
241a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            Log.e(TAG, "Ran out of data or error on record " + recCount);
242a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            mKeyToPosMap.clear();
243a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
244a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        } else {
245a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return true;
246a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
2475d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Catania    }
2485d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Catania
2499193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    /**
250a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * Check a parcel containing metadata is well formed. The header
251a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * is checked as well as the individual records format. However, the
252a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * data inside the record is not checked because we do lazy access
253a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * (we check/unmarshall only data the user asks for.)
254a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *
255a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * Format of a metadata parcel:
256a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     <pre>
257a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                         1                   2                   3
258a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      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
259a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
260a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                     metadata total size                       |
261a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
262a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |     'M'       |     'E'       |     'T'       |     'A'       |
263a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
264a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                                                               |
265a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                .... metadata records ....                     |
266a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                                                               |
267a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
268a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     </pre>
269a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *
270a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @param parcel With the serialized data. Metadata keeps a
271a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *               reference on it to access it later on. The caller
272a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *               should not modify the parcel after this call (and
273a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *               not call recycle on it.)
274a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @return false if an error occurred.
2759193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     */
276a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public boolean parse(Parcel parcel) {
277a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (parcel.dataAvail() < kMetaHeaderSize) {
278a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            Log.e(TAG, "Not enough data " + parcel.dataAvail());
279a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
280a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
281a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
282a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        final int pin = parcel.dataPosition();  // to roll back in case of errors.
283a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        final int size = parcel.readInt();
284a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
2856fa41bbb56e0756d3eac15d6314007e4a450c9d3niko        // The extra kInt32Size below is to account for the int32 'size' just read.
2866fa41bbb56e0756d3eac15d6314007e4a450c9d3niko        if (parcel.dataAvail() + kInt32Size < size || size < kMetaHeaderSize) {
287c39173be3237be9f39d2b57bb38249126e183c53niko            Log.e(TAG, "Bad size " + size + " avail " + parcel.dataAvail() + " position " + pin);
288a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            parcel.setDataPosition(pin);
289a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
290a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
291a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
292a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        // Checks if the 'M' 'E' 'T' 'A' marker is present.
293a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        final int kShouldBeMetaMarker = parcel.readInt();
294a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (kShouldBeMetaMarker != kMetaMarker ) {
295a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            Log.e(TAG, "Marker missing " + Integer.toHexString(kShouldBeMetaMarker));
296a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            parcel.setDataPosition(pin);
297a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
298a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
299a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
300a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        // Scan the records to collect metadata ids and offsets.
301a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (!scanAllRecords(parcel, size - kMetaHeaderSize)) {
302a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            parcel.setDataPosition(pin);
303a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
304a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
305a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        mParcel = parcel;
306a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        return true;
3079193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
3089193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
3099193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    /**
310a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @return The set of metadata ID found.
3119193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     */
312a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public Set<Integer> keySet() {
313a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        return mKeyToPosMap.keySet();
3149193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
3159193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
3169193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    /**
3179193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     * @return true if a value is present for the given key.
3189193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     */
319a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public boolean has(final int metadataId) {
320a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (!checkMetadataId(metadataId)) {
321a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            throw new IllegalArgumentException("Invalid key: " + metadataId);
3229193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania        }
323a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        return mKeyToPosMap.containsKey(metadataId);
3249193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
3259193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
326cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // Accessors.
327cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // Caller must make sure the key is present using the {@code has}
328cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // method otherwise a RuntimeException will occur.
329cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
3309193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public String getString(final int key) {
331cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, STRING_VAL);
332cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readString();
3339193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
3349193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
3359193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public int getInt(final int key) {
336cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, INTEGER_VAL);
337cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readInt();
338cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    }
339cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
340cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public boolean getBoolean(final int key) {
341cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, BOOLEAN_VAL);
342cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readInt() == 1;
3439193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
3449193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
3459193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public long getLong(final int key) {
346cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, LONG_VAL);
347cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readLong();
3489193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
3499193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
3509193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public double getDouble(final int key) {
351cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, DOUBLE_VAL);
352cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readDouble();
3539193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
3549193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
3559193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public byte[] getByteArray(final int key) {
356cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, BYTE_ARRAY_VAL);
357cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.createByteArray();
3589193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
3599193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
3609193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public Date getDate(final int key) {
361cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, DATE_VAL);
362cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final long timeSinceEpoch = mParcel.readLong();
363cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final String timeZone = mParcel.readString();
364cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
365cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        if (timeZone.length() == 0) {
366cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            return new Date(timeSinceEpoch);
367cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        } else {
368cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            TimeZone tz = TimeZone.getTimeZone(timeZone);
369cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            Calendar cal = Calendar.getInstance(tz);
370cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
371cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            cal.setTimeInMillis(timeSinceEpoch);
372cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            return cal.getTime();
373cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        }
3749193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
3759193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
3769193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public TimedText getTimedText(final int key) {
377cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, TIMED_TEXT_VAL);
378cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final Date startTime = new Date(mParcel.readLong());  // epoch
379cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final int duration = mParcel.readInt();  // millisec
380cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
381cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return new TimedText(startTime,
382cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania                             duration,
383cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania                             mParcel.readString());
3849193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
385a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
386a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // @return the last available system metadata id. Ids are
387a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // 1-indexed.
388a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public static int lastSytemId() { return LAST_SYSTEM; }
389a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
390a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // @return the first available cutom metadata id.
391a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public static int firstCustomId() { return FIRST_CUSTOM; }
392a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
393a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // @return the last value of known type. Types are 1-indexed.
394a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public static int lastType() { return LAST_TYPE; }
395a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
396a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Check val is either a system id or a custom one.
397a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // @param val Metadata key to test.
398a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // @return true if it is in a valid range.
399a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private boolean checkMetadataId(final int val) {
400a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (val <= ANY || (LAST_SYSTEM < val && val < FIRST_CUSTOM)) {
401a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            Log.e(TAG, "Invalid metadata ID " + val);
402a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
403a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
404a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        return true;
405a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    }
406cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
407cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // Check the type of the data match what is expected.
408cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    private void checkType(final int key, final int expectedType) {
409cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final int pos = mKeyToPosMap.get(key);
410cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
411cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        mParcel.setDataPosition(pos);
412cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
413cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final int type = mParcel.readInt();
414cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        if (type != expectedType) {
415cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            throw new IllegalStateException("Wrong type " + expectedType + " but got " + type);
416cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        }
417cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    }
4189193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania}
419