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;
219193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
22cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Cataniaimport java.util.Calendar;
239193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Cataniaimport java.util.Collections;
249193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Cataniaimport java.util.Date;
25a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Cataniaimport java.util.HashMap;
26cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Cataniaimport java.util.Set;
27cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Cataniaimport java.util.TimeZone;
289193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
295d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Catania
309193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania/**
319193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   Class to hold the media's metadata.  Metadata are used
329193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   for human consumption and can be embedded in the media (e.g
339193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   shoutcast) or available from an external source. The source can be
341e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang   local (e.g thumbnail stored in the DB) or remote.
359193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
369193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   Metadata is like a Bundle. It is sparse and each key can occur at
379193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   most once. The key is an integer and the value is the actual metadata.
389193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
399193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   The caller is expected to know the type of the metadata and call
409193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania   the right get* method to fetch its value.
4148c5fb14933cba4dcf6ba401b895e59bac4a8420Dianne Hackborn
4248c5fb14933cba4dcf6ba401b895e59bac4a8420Dianne Hackborn   @hide
43edb158f55f48a1f7b2cbf30ddec9b8917dc9a619RoboErik   @deprecated Use {@link MediaMetadata}.
449193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania */
45edb158f55f48a1f7b2cbf30ddec9b8917dc9a619RoboErik@Deprecated public class Metadata
469193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania{
479193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // The metadata are keyed using integers rather than more heavy
489193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // weight strings. We considered using Bundle to ship the metadata
499193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // between the native layer and the java layer but dropped that
509193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // option since keeping in sync a native implementation of Bundle
519193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // and the java one would be too burdensome. Besides Bundle uses
529193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // String for its keys.
539193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // The key range [0 8192) is reserved for the system.
549193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    //
559193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // We manually serialize the data in Parcels. For large memory
569193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // blob (bitmaps, raw pictures) we use MemoryFile which allow the
57a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // client to make the data purge-able once it is done with it.
589193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    //
599193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
601e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
611e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
621e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
639193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final int ANY = 0;  // Never used for metadata returned, only for filtering.
64b2c693919be966f179080a9ec70a7a82dbf57627Nicolas Catania                                      // Keep in sync with kAny in MediaPlayerService.cpp
659193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
661e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    // Playback capabilities.
671e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
681e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Indicate whether the media can be paused
691e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
701e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int PAUSE_AVAILABLE         = 1; // Boolean
711e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
721e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Indicate whether the media can be backward seeked
731e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
741e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int SEEK_BACKWARD_AVAILABLE = 2; // Boolean
751e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
761e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Indicate whether the media can be forward seeked
771e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
781e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int SEEK_FORWARD_AVAILABLE  = 3; // Boolean
791e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
801e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Indicate whether the media can be seeked
811e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
821e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int SEEK_AVAILABLE          = 4; // Boolean
831e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang
849193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // TODO: Should we use numbers compatible with the metadata retriever?
851e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
861e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
871e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
881e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int TITLE                   = 5; // String
891e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
901e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
911e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
921e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int COMMENT                 = 6; // String
931e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
941e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
951e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
961e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int COPYRIGHT               = 7; // String
971e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
981e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
991e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1001e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int ALBUM                   = 8; // String
1011e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1021e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1031e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1041e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int ARTIST                  = 9; // String
1051e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1061e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1071e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1081e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int AUTHOR                  = 10; // String
1091e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1101e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1111e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1121e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int COMPOSER                = 11; // String
1131e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1141e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1151e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1161e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int GENRE                   = 12; // String
1171e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1181e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1191e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1201e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int DATE                    = 13; // Date
1211e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1221e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1231e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1241e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int DURATION                = 14; // Integer(millisec)
1251e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1261e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1271e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1281e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int CD_TRACK_NUM            = 15; // Integer 1-based
1291e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1301e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1311e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1321e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int CD_TRACK_MAX            = 16; // Integer
1331e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1341e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1351e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1361e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int RATING                  = 17; // String
1371e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1381e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1391e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1401e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int ALBUM_ART               = 18; // byte[]
1411e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1421e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1431e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1441e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int VIDEO_FRAME             = 19; // Bitmap
1459193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
1461e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1471e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1481e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1491e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int BIT_RATE                = 20; // Integer, Aggregate rate of
1501e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang                                                          // all the streams in bps.
1519193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
1521e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1531e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1541e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1551e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int AUDIO_BIT_RATE          = 21; // Integer, bps
1561e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1571e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1581e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1591e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int VIDEO_BIT_RATE          = 22; // Integer, bps
1601e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1611e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1621e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1631e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int AUDIO_SAMPLE_RATE       = 23; // Integer, Hz
1641e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1651e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1661e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1671e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int VIDEO_FRAME_RATE        = 24; // Integer, Hz
168716383a686b086f68533a51785ba77186359ce6bNicolas Catania
1691e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    // See RFC2046 and RFC4281.
1701e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1711e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1721e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1731e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int MIME_TYPE               = 25; // String
1741e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1751e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1761e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1771e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int AUDIO_CODEC             = 26; // String
1781e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1791e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1801e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1811e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int VIDEO_CODEC             = 27; // String
1821e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang
1831e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1841e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1851e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1861e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int VIDEO_HEIGHT            = 28; // Integer
1871e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1881e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1891e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1901e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int VIDEO_WIDTH             = 29; // Integer
1911e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1921e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1931e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1941e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int NUM_TRACKS              = 30; // Integer
1951e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
1961e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
1971e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
1981e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int DRM_CRIPPLED            = 31; // Boolean
199716383a686b086f68533a51785ba77186359ce6bNicolas Catania
2001e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    private static final int LAST_SYSTEM = 31;
201bc7269278042e448299c2e80e4dbb16fed05791dniko    private static final int FIRST_CUSTOM = 8192;
2029193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
2039193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    // Shorthands to set the MediaPlayer's metadata filter.
2041e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2051e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2061e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
2079193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final Set<Integer> MATCH_NONE = Collections.EMPTY_SET;
2081e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2091e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2101e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
2119193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public static final Set<Integer> MATCH_ALL = Collections.singleton(ANY);
2129193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
2131e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2141e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2151e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
216cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int STRING_VAL     = 1;
2171e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2181e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2191e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
220cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int INTEGER_VAL    = 2;
2211e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2221e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2231e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
224cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int BOOLEAN_VAL    = 3;
2251e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2261e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2271e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
228cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int LONG_VAL       = 4;
2291e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2301e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2311e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
232cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public static final int DOUBLE_VAL     = 5;
2331e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2341e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2351e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
2361e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int DATE_VAL       = 6;
2371e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
2381e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2391e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
2401e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    public static final int BYTE_ARRAY_VAL = 7;
241cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // FIXME: misses a type for shared heap is missing (MemoryFile).
242cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // FIXME: misses a type for bitmaps.
2431e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    private static final int LAST_TYPE = 7;
244a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
245a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private static final String TAG = "media.Metadata";
2466fa41bbb56e0756d3eac15d6314007e4a450c9d3niko    private static final int kInt32Size = 4;
2476fa41bbb56e0756d3eac15d6314007e4a450c9d3niko    private static final int kMetaHeaderSize = 2 * kInt32Size; //  size + marker
2486fa41bbb56e0756d3eac15d6314007e4a450c9d3niko    private static final int kRecordHeaderSize = 3 * kInt32Size; // size + id + type
2496fa41bbb56e0756d3eac15d6314007e4a450c9d3niko
250a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private static final int kMetaMarker = 0x4d455441;  // 'M' 'E' 'T' 'A'
251a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
252a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // After a successful parsing, set the parcel with the serialized metadata.
253a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private Parcel mParcel;
254a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
255a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Map to associate a Metadata key (e.g TITLE) with the offset of
256a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // the record's payload in the parcel.
257a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Used to look up if a key was present too.
258a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Key: Metadata ID
259a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    // Value: Offset of the metadata type field in the record.
260cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    private final HashMap<Integer, Integer> mKeyToPosMap =
261cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            new HashMap<Integer, Integer>();
2625d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Catania
2639193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    /**
2641e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
2659193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     */
266a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public Metadata() { }
2679193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
268a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    /**
269a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * Go over all the records, collecting metadata keys and records'
270a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * type field offset in the Parcel. These are stored in
271a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * mKeyToPosMap for latter retrieval.
272a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * Format of a metadata record:
273a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     <pre>
274a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                         1                   2                   3
275a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas 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
276a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
277a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                     record size                               |
278a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
279a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                     metadata key                              |  // TITLE
280a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
281a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                     metadata type                             |  // STRING_VAL
282a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
283a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                                                               |
284a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                .... metadata payload ....                     |
285a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                                                               |
286a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
287a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     </pre>
288a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @param parcel With the serialized records.
289a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @param bytesLeft How many bytes in the parcel should be processed.
290a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @return false if an error occurred during parsing.
291a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     */
292a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private boolean scanAllRecords(Parcel parcel, int bytesLeft) {
293a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        int recCount = 0;
294a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        boolean error = false;
295a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
296a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        mKeyToPosMap.clear();
297a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        while (bytesLeft > kRecordHeaderSize) {
298a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            final int start = parcel.dataPosition();
299a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Check the size.
300a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            final int size = parcel.readInt();
301a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
302a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            if (size <= kRecordHeaderSize) {  // at least 1 byte should be present.
303a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                Log.e(TAG, "Record is too short");
304a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                error = true;
305a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                break;
306a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            }
307a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
308a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Check the metadata key.
309a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            final int metadataId = parcel.readInt();
310a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            if (!checkMetadataId(metadataId)) {
311a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                error = true;
312a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                break;
313a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            }
314a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
315a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Store the record offset which points to the type
316a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // field so we can later on read/unmarshall the record
317a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // payload.
318a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            if (mKeyToPosMap.containsKey(metadataId)) {
319a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                Log.e(TAG, "Duplicate metadata ID found");
320a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                error = true;
321a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                break;
322a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            }
323a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
324a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            mKeyToPosMap.put(metadataId, parcel.dataPosition());
325a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
326a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Check the metadata type.
327a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            final int metadataType = parcel.readInt();
328a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            if (metadataType <= 0 || metadataType > LAST_TYPE) {
329a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                Log.e(TAG, "Invalid metadata type " + metadataType);
330a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                error = true;
331a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                break;
332a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            }
333a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
334a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            // Skip to the next one.
335a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            parcel.setDataPosition(start + size);
336a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            bytesLeft -= size;
337a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            ++recCount;
338a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
339a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
340a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (0 != bytesLeft || error) {
341a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            Log.e(TAG, "Ran out of data or error on record " + recCount);
342a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            mKeyToPosMap.clear();
343a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
344a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        } else {
345a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return true;
346a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
3475d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Catania    }
3485d55c7119820ee9bb06fc072e416fe98ba77cd28Nicolas Catania
3499193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    /**
350a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * Check a parcel containing metadata is well formed. The header
351a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * is checked as well as the individual records format. However, the
352a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * data inside the record is not checked because we do lazy access
353a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * (we check/unmarshall only data the user asks for.)
354a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *
355a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * Format of a metadata parcel:
356a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     <pre>
357a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania                         1                   2                   3
358a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas 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
359a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
360a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                     metadata total size                       |
361a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
362a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |     'M'       |     'E'       |     'T'       |     'A'       |
363a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
364a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                                                               |
365a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                .... metadata records ....                     |
366a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      |                                                               |
367a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
368a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     </pre>
369a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *
370a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @param parcel With the serialized data. Metadata keeps a
371a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *               reference on it to access it later on. The caller
372a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *               should not modify the parcel after this call (and
373a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     *               not call recycle on it.)
374a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @return false if an error occurred.
3751e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
3769193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     */
377a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public boolean parse(Parcel parcel) {
378a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (parcel.dataAvail() < kMetaHeaderSize) {
379a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            Log.e(TAG, "Not enough data " + parcel.dataAvail());
380a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
381a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
382a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
383a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        final int pin = parcel.dataPosition();  // to roll back in case of errors.
384a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        final int size = parcel.readInt();
385a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
3866fa41bbb56e0756d3eac15d6314007e4a450c9d3niko        // The extra kInt32Size below is to account for the int32 'size' just read.
3876fa41bbb56e0756d3eac15d6314007e4a450c9d3niko        if (parcel.dataAvail() + kInt32Size < size || size < kMetaHeaderSize) {
388c39173be3237be9f39d2b57bb38249126e183c53niko            Log.e(TAG, "Bad size " + size + " avail " + parcel.dataAvail() + " position " + pin);
389a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            parcel.setDataPosition(pin);
390a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
391a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
392a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
393a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        // Checks if the 'M' 'E' 'T' 'A' marker is present.
394a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        final int kShouldBeMetaMarker = parcel.readInt();
395a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (kShouldBeMetaMarker != kMetaMarker ) {
396a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            Log.e(TAG, "Marker missing " + Integer.toHexString(kShouldBeMetaMarker));
397a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            parcel.setDataPosition(pin);
398a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
399a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
400a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
401a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        // Scan the records to collect metadata ids and offsets.
402a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (!scanAllRecords(parcel, size - kMetaHeaderSize)) {
403a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            parcel.setDataPosition(pin);
404a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
405a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
406a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        mParcel = parcel;
407a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        return true;
4089193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4099193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4109193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    /**
411a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania     * @return The set of metadata ID found.
4129193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     */
413a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public Set<Integer> keySet() {
414a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        return mKeyToPosMap.keySet();
4159193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4169193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4179193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    /**
4189193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     * @return true if a value is present for the given key.
4199193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania     */
420a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public boolean has(final int metadataId) {
421a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (!checkMetadataId(metadataId)) {
422a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            throw new IllegalArgumentException("Invalid key: " + metadataId);
4239193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania        }
424a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        return mKeyToPosMap.containsKey(metadataId);
4259193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4269193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
427cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // Accessors.
428cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // Caller must make sure the key is present using the {@code has}
429cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    // method otherwise a RuntimeException will occur.
430cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
4311e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4321e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4331e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
4349193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public String getString(final int key) {
435cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, STRING_VAL);
436cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readString();
4379193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4389193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4391e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4401e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4411e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
4429193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public int getInt(final int key) {
443cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, INTEGER_VAL);
444cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readInt();
445cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    }
446cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
4471e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4481e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Get the boolean value indicated by key
4491e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
450cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    public boolean getBoolean(final int key) {
451cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, BOOLEAN_VAL);
452cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readInt() == 1;
4539193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4549193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4551e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4561e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4571e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
4589193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public long getLong(final int key) {
4591e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang        checkType(key, LONG_VAL);    /**
4601e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4611e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
462cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readLong();
4639193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4649193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4651e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4661e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4671e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
4689193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public double getDouble(final int key) {
469cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, DOUBLE_VAL);
470cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.readDouble();
4719193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4729193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4731e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4741e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4751e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
4769193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public byte[] getByteArray(final int key) {
477cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, BYTE_ARRAY_VAL);
478cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        return mParcel.createByteArray();
4799193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4809193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
4811e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
4821e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
4831e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
4849193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    public Date getDate(final int key) {
485cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        checkType(key, DATE_VAL);
486cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final long timeSinceEpoch = mParcel.readLong();
487cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final String timeZone = mParcel.readString();
488cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
489cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        if (timeZone.length() == 0) {
490cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            return new Date(timeSinceEpoch);
491cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        } else {
492cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            TimeZone tz = TimeZone.getTimeZone(timeZone);
493cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            Calendar cal = Calendar.getInstance(tz);
494cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
495cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            cal.setTimeInMillis(timeSinceEpoch);
496cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            return cal.getTime();
497cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        }
4989193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania    }
4999193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania
5001e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
5011e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * @return the last available system metadata id. Ids are
5021e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     *         1-indexed.
5031e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
5041e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
505a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public static int lastSytemId() { return LAST_SYSTEM; }
506a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
5071e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
5081e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * @return the first available cutom metadata id.
5091e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
5101e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
511a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public static int firstCustomId() { return FIRST_CUSTOM; }
512a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
5131e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
5141e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * @return the last value of known type. Types are 1-indexed.
5151e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * {@hide}
5161e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
517a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    public static int lastType() { return LAST_TYPE; }
518a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania
5191e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
5201e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Check val is either a system id or a custom one.
5211e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * @param val Metadata key to test.
5221e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * @return true if it is in a valid range.
5231e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     **/
524a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    private boolean checkMetadataId(final int val) {
525a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        if (val <= ANY || (LAST_SYSTEM < val && val < FIRST_CUSTOM)) {
526a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            Log.e(TAG, "Invalid metadata ID " + val);
527a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania            return false;
528a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        }
529a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania        return true;
530a5ccb22a3ddb342fe3f7e5493095c6e6dceda60bNicolas Catania    }
531cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
5321e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang    /**
5331e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     * Check the type of the data match what is expected.
5341e1b13e62e38d6efc7cef4b496b3119bd45ee2c2Gloria Wang     */
535cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    private void checkType(final int key, final int expectedType) {
536cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final int pos = mKeyToPosMap.get(key);
537cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
538cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        mParcel.setDataPosition(pos);
539cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania
540cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        final int type = mParcel.readInt();
541cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        if (type != expectedType) {
542cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania            throw new IllegalStateException("Wrong type " + expectedType + " but got " + type);
543cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania        }
544cb2e00eedce99b30faf5f238136a00bc5448c5f2Nicolas Catania    }
5459193e08dc1d91401fdf1846eaad4689da3911dc1Nicolas Catania}
546