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
195d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Cataniaimport android.os.Parcel;
209193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Cataniaimport android.util.Log;
211619ed4706a0bf906d967ab7987cd4c475ac3462Adam Lesinskiimport android.util.MathUtils;
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
351e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang   local (e.g thumbnail stored in the DB) or remote.
369193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
379193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   Metadata is like a Bundle. It is sparse and each key can occur at
389193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   most once. The key is an integer and the value is the actual metadata.
399193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
409193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   The caller is expected to know the type of the metadata and call
419193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   the right get* method to fetch its value.
4248c5fb14933cba4dcf6ba401b895e59bac4a8420Dianne Hackborn
4348c5fb14933cba4dcf6ba401b895e59bac4a8420Dianne Hackborn   @hide
44edb158f55f48a1f7b2cbf30ddec9b8917dc9a619RoboErik   @deprecated Use {@link MediaMetadata}.
459193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania */
46edb158f55f48a1f7b2cbf30ddec9b8917dc9a619RoboErik@Deprecated public class Metadata
479193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania{
489193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // The metadata are keyed using integers rather than more heavy
499193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // weight strings. We considered using Bundle to ship the metadata
509193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // between the native layer and the java layer but dropped that
519193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // option since keeping in sync a native implementation of Bundle
529193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // and the java one would be too burdensome. Besides Bundle uses
539193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // String for its keys.
549193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // The key range [0 8192) is reserved for the system.
559193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    //
569193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // We manually serialize the data in Parcels. For large memory
579193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // blob (bitmaps, raw pictures) we use MemoryFile which allow the
58a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // client to make the data purge-able once it is done with it.
599193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    //
609193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
611e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
621e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
631e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
649193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int ANY = 0;  // Never used for metadata returned, only for filtering.
65b2c693919be966f179080a9ec70a7a82dbf57627Nicolas Catania                                      // Keep in sync with kAny in MediaPlayerService.cpp
669193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
671e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    // Playback capabilities.
681e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
691e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Indicate whether the media can be paused
701e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
711e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int PAUSE_AVAILABLE         = 1; // Boolean
721e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
731e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Indicate whether the media can be backward seeked
741e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
751e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int SEEK_BACKWARD_AVAILABLE = 2; // Boolean
761e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
771e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Indicate whether the media can be forward seeked
781e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
791e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int SEEK_FORWARD_AVAILABLE  = 3; // Boolean
801e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
811e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Indicate whether the media can be seeked
821e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
831e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int SEEK_AVAILABLE          = 4; // Boolean
841e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang
859193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // TODO: Should we use numbers compatible with the metadata retriever?
861e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
871e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
881e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
891e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int TITLE                   = 5; // String
901e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
911e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
921e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
931e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int COMMENT                 = 6; // String
941e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
951e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
961e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
971e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int COPYRIGHT               = 7; // String
981e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
991e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1001e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1011e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int ALBUM                   = 8; // String
1021e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1031e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1041e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1051e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int ARTIST                  = 9; // String
1061e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1071e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1081e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1091e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int AUTHOR                  = 10; // String
1101e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1111e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1121e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1131e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int COMPOSER                = 11; // String
1141e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1151e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1161e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1171e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int GENRE                   = 12; // String
1181e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1191e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1201e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1211e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int DATE                    = 13; // Date
1221e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1231e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1241e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1251e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int DURATION                = 14; // Integer(millisec)
1261e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1271e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1281e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1291e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int CD_TRACK_NUM            = 15; // Integer 1-based
1301e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1311e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1321e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1331e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int CD_TRACK_MAX            = 16; // Integer
1341e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1351e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1361e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1371e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int RATING                  = 17; // String
1381e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1391e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1401e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1411e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int ALBUM_ART               = 18; // byte[]
1421e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1431e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1441e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1451e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int VIDEO_FRAME             = 19; // Bitmap
1469193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
1471e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1481e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1491e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1501e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int BIT_RATE                = 20; // Integer, Aggregate rate of
1511e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang                                                          // all the streams in bps.
1529193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
1531e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1541e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1551e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1561e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int AUDIO_BIT_RATE          = 21; // Integer, bps
1571e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1581e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1591e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1601e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int VIDEO_BIT_RATE          = 22; // Integer, bps
1611e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1621e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1631e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1641e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int AUDIO_SAMPLE_RATE       = 23; // Integer, Hz
1651e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1661e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1671e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1681e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int VIDEO_FRAME_RATE        = 24; // Integer, Hz
169716383a686b086f68533a51785ba77186359ce6bNicolas Catania
1701e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    // See RFC2046 and RFC4281.
1711e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1721e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1731e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1741e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int MIME_TYPE               = 25; // String
1751e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1761e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1771e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1781e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int AUDIO_CODEC             = 26; // String
1791e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1801e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1811e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1821e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int VIDEO_CODEC             = 27; // String
1831e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang
1841e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1851e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1861e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1871e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int VIDEO_HEIGHT            = 28; // Integer
1881e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1891e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1901e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1911e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int VIDEO_WIDTH             = 29; // Integer
1921e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1931e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1941e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1951e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int NUM_TRACKS              = 30; // Integer
1961e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1971e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1981e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1991e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int DRM_CRIPPLED            = 31; // Boolean
200716383a686b086f68533a51785ba77186359ce6bNicolas Catania
2011e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    private static final int LAST_SYSTEM = 31;
202bc7269278042e448299c2e80e4dbb16fed05791dniko    private static final int FIRST_CUSTOM = 8192;
2039193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
2049193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // Shorthands to set the MediaPlayer's metadata filter.
2051e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2061e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2071e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
2089193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final Set<Integer> MATCH_NONE = Collections.EMPTY_SET;
2091e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2101e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2111e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
2129193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final Set<Integer> MATCH_ALL = Collections.singleton(ANY);
2139193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
2141e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2151e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2161e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
217cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int STRING_VAL     = 1;
2181e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2191e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2201e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
221cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int INTEGER_VAL    = 2;
2221e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2231e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2241e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
225cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int BOOLEAN_VAL    = 3;
2261e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2271e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2281e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
229cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int LONG_VAL       = 4;
2301e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2311e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2321e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
233cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int DOUBLE_VAL     = 5;
2341e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2351e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2361e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
2371e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int DATE_VAL       = 6;
2381e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2391e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2401e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
2411e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int BYTE_ARRAY_VAL = 7;
242cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // FIXME: misses a type for shared heap is missing (MemoryFile).
243cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // FIXME: misses a type for bitmaps.
2441e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    private static final int LAST_TYPE = 7;
245a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
246a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private static final String TAG = "media.Metadata";
2476fa41bbb56e0756d3eac15d6314007e4a450c9d3niko    private static final int kInt32Size = 4;
2486fa41bbb56e0756d3eac15d6314007e4a450c9d3niko    private static final int kMetaHeaderSize = 2 * kInt32Size; //  size + marker
2496fa41bbb56e0756d3eac15d6314007e4a450c9d3niko    private static final int kRecordHeaderSize = 3 * kInt32Size; // size + id + type
2506fa41bbb56e0756d3eac15d6314007e4a450c9d3niko
251a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private static final int kMetaMarker = 0x4d455441;  // 'M' 'E' 'T' 'A'
252a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
253a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // After a successful parsing, set the parcel with the serialized metadata.
254a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private Parcel mParcel;
255a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
256a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Map to associate a Metadata key (e.g TITLE) with the offset of
257a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // the record's payload in the parcel.
258a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Used to look up if a key was present too.
259a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Key: Metadata ID
260a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Value: Offset of the metadata type field in the record.
261cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    private final HashMap<Integer, Integer> mKeyToPosMap =
262cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            new HashMap<Integer, Integer>();
2635d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Catania
2649193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    /**
2651e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2669193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     */
267a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public Metadata() { }
2689193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
269a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    /**
270a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * Go over all the records, collecting metadata keys and records'
271a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * type field offset in the Parcel. These are stored in
272a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * mKeyToPosMap for latter retrieval.
273a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * Format of a metadata record:
274a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     <pre>
275a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                         1                   2                   3
276a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas 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
277a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
278a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                     record size                               |
279a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
280a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                     metadata key                              |  // TITLE
281a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
282a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                     metadata type                             |  // STRING_VAL
283a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
284a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                                                               |
285a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                .... metadata payload ....                     |
286a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                                                               |
287a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
288a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     </pre>
289a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @param parcel With the serialized records.
290a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @param bytesLeft How many bytes in the parcel should be processed.
291a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @return false if an error occurred during parsing.
292a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     */
293a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private boolean scanAllRecords(Parcel parcel, int bytesLeft) {
294a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        int recCount = 0;
295a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        boolean error = false;
296a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
297a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        mKeyToPosMap.clear();
298a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        while (bytesLeft > kRecordHeaderSize) {
299a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            final int start = parcel.dataPosition();
300a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Check the size.
301a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            final int size = parcel.readInt();
302a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
303a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            if (size <= kRecordHeaderSize) {  // at least 1 byte should be present.
304a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                Log.e(TAG, "Record is too short");
305a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                error = true;
306a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                break;
307a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            }
308a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
309a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Check the metadata key.
310a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            final int metadataId = parcel.readInt();
311a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            if (!checkMetadataId(metadataId)) {
312a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                error = true;
313a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                break;
314a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            }
315a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
316a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Store the record offset which points to the type
317a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // field so we can later on read/unmarshall the record
318a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // payload.
319a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            if (mKeyToPosMap.containsKey(metadataId)) {
320a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                Log.e(TAG, "Duplicate metadata ID found");
321a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                error = true;
322a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                break;
323a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            }
324a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
325a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            mKeyToPosMap.put(metadataId, parcel.dataPosition());
326a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
327a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Check the metadata type.
328a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            final int metadataType = parcel.readInt();
329a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            if (metadataType <= 0 || metadataType > LAST_TYPE) {
330a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                Log.e(TAG, "Invalid metadata type " + metadataType);
331a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                error = true;
332a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                break;
333a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            }
334a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
335a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Skip to the next one.
3361619ed4706a0bf906d967ab7987cd4c475ac3462Adam Lesinski            try {
3371619ed4706a0bf906d967ab7987cd4c475ac3462Adam Lesinski                parcel.setDataPosition(MathUtils.addOrThrow(start, size));
3381619ed4706a0bf906d967ab7987cd4c475ac3462Adam Lesinski            } catch (IllegalArgumentException e) {
3391619ed4706a0bf906d967ab7987cd4c475ac3462Adam Lesinski                Log.e(TAG, "Invalid size: " + e.getMessage());
3401619ed4706a0bf906d967ab7987cd4c475ac3462Adam Lesinski                error = true;
3411619ed4706a0bf906d967ab7987cd4c475ac3462Adam Lesinski                break;
3421619ed4706a0bf906d967ab7987cd4c475ac3462Adam Lesinski            }
3431619ed4706a0bf906d967ab7987cd4c475ac3462Adam Lesinski
344a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            bytesLeft -= size;
345a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            ++recCount;
346a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
347a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
348a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (0 != bytesLeft || error) {
349a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            Log.e(TAG, "Ran out of data or error on record " + recCount);
350a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            mKeyToPosMap.clear();
351a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
352a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        } else {
353a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return true;
354a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
3555d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Catania    }
3565d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Catania
3579193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    /**
358a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * Check a parcel containing metadata is well formed. The header
359a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * is checked as well as the individual records format. However, the
360a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * data inside the record is not checked because we do lazy access
361a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * (we check/unmarshall only data the user asks for.)
362a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *
363a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * Format of a metadata parcel:
364a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     <pre>
365a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                         1                   2                   3
366a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas 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
367a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
368a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                     metadata total size                       |
369a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
370a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |     'M'       |     'E'       |     'T'       |     'A'       |
371a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
372a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                                                               |
373a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                .... metadata records ....                     |
374a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                                                               |
375a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
376a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     </pre>
377a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *
378a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @param parcel With the serialized data. Metadata keeps a
379a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *               reference on it to access it later on. The caller
380a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *               should not modify the parcel after this call (and
381a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *               not call recycle on it.)
382a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @return false if an error occurred.
3831e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
3849193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     */
385a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public boolean parse(Parcel parcel) {
386a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (parcel.dataAvail() < kMetaHeaderSize) {
387a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            Log.e(TAG, "Not enough data " + parcel.dataAvail());
388a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
389a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
390a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
391a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        final int pin = parcel.dataPosition();  // to roll back in case of errors.
392a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        final int size = parcel.readInt();
393a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
3946fa41bbb56e0756d3eac15d6314007e4a450c9d3niko        // The extra kInt32Size below is to account for the int32 'size' just read.
3956fa41bbb56e0756d3eac15d6314007e4a450c9d3niko        if (parcel.dataAvail() + kInt32Size < size || size < kMetaHeaderSize) {
396c39173be3237be9f39d2b57bb38249126e183c53niko            Log.e(TAG, "Bad size " + size + " avail " + parcel.dataAvail() + " position " + pin);
397a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            parcel.setDataPosition(pin);
398a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
399a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
400a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
401a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        // Checks if the 'M' 'E' 'T' 'A' marker is present.
402a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        final int kShouldBeMetaMarker = parcel.readInt();
403a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (kShouldBeMetaMarker != kMetaMarker ) {
404a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            Log.e(TAG, "Marker missing " + Integer.toHexString(kShouldBeMetaMarker));
405a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            parcel.setDataPosition(pin);
406a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
407a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
408a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
409a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        // Scan the records to collect metadata ids and offsets.
410a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (!scanAllRecords(parcel, size - kMetaHeaderSize)) {
411a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            parcel.setDataPosition(pin);
412a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
413a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
414a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        mParcel = parcel;
415a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        return true;
4169193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4179193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4189193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    /**
419a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @return The set of metadata ID found.
4209193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     */
421a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public Set<Integer> keySet() {
422a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        return mKeyToPosMap.keySet();
4239193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4249193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4259193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    /**
4269193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     * @return true if a value is present for the given key.
4279193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     */
428a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public boolean has(final int metadataId) {
429a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (!checkMetadataId(metadataId)) {
430a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            throw new IllegalArgumentException("Invalid key: " + metadataId);
4319193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania        }
432a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        return mKeyToPosMap.containsKey(metadataId);
4339193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4349193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
435cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // Accessors.
436cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // Caller must make sure the key is present using the {@code has}
437cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // method otherwise a RuntimeException will occur.
438cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
4391e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4401e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4411e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
4429193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public String getString(final int key) {
443cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, STRING_VAL);
444cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readString();
4459193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4469193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4471e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4481e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4491e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
4509193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public int getInt(final int key) {
451cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, INTEGER_VAL);
452cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readInt();
453cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    }
454cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
4551e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4561e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Get the boolean value indicated by key
4571e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
458cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public boolean getBoolean(final int key) {
459cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, BOOLEAN_VAL);
460cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readInt() == 1;
4619193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4629193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4631e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4641e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4651e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
4669193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public long getLong(final int key) {
4671e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang        checkType(key, LONG_VAL);    /**
4681e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4691e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
470cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readLong();
4719193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4729193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4731e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4741e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4751e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
4769193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public double getDouble(final int key) {
477cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, DOUBLE_VAL);
478cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readDouble();
4799193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4809193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4811e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4821e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4831e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
4849193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public byte[] getByteArray(final int key) {
485cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, BYTE_ARRAY_VAL);
486cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.createByteArray();
4879193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4889193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4891e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4901e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4911e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
4929193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public Date getDate(final int key) {
493cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, DATE_VAL);
494cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final long timeSinceEpoch = mParcel.readLong();
495cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final String timeZone = mParcel.readString();
496cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
497cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        if (timeZone.length() == 0) {
498cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            return new Date(timeSinceEpoch);
499cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        } else {
500cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            TimeZone tz = TimeZone.getTimeZone(timeZone);
501cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            Calendar cal = Calendar.getInstance(tz);
502cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
503cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            cal.setTimeInMillis(timeSinceEpoch);
504cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            return cal.getTime();
505cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        }
5069193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
5079193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
5081e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
5091e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * @return the last available system metadata id. Ids are
5101e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     *         1-indexed.
5111e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
5121e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
513a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public static int lastSytemId() { return LAST_SYSTEM; }
514a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
5151e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
5161e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * @return the first available cutom metadata id.
5171e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
5181e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
519a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public static int firstCustomId() { return FIRST_CUSTOM; }
520a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
5211e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
5221e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * @return the last value of known type. Types are 1-indexed.
5231e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
5241e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
525a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public static int lastType() { return LAST_TYPE; }
526a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
5271e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
5281e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Check val is either a system id or a custom one.
5291e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * @param val Metadata key to test.
5301e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * @return true if it is in a valid range.
5311e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     **/
532a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private boolean checkMetadataId(final int val) {
533a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (val <= ANY || (LAST_SYSTEM < val && val < FIRST_CUSTOM)) {
534a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            Log.e(TAG, "Invalid metadata ID " + val);
535a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
536a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
537a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        return true;
538a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    }
539cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
5401e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
5411e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Check the type of the data match what is expected.
5421e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
543cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    private void checkType(final int key, final int expectedType) {
544cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final int pos = mKeyToPosMap.get(key);
545cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
546cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        mParcel.setDataPosition(pos);
547cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
548cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final int type = mParcel.readInt();
549cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        if (type != expectedType) {
550cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            throw new IllegalStateException("Wrong type " + expectedType + " but got " + type);
551cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        }
552cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    }
5539193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania}
554