19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.text.format;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
209c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinekimport android.os.UserHandle;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.SpannableStringBuilder;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Spanned;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.SpannedString;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
264037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikasimport libcore.icu.ICU;
274037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikasimport libcore.icu.LocaleData;
284037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikas
294037d51b132a85dcfe37a95f9d2d91ad23d162fdAurimas Liutikasimport java.text.SimpleDateFormat;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Calendar;
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Date;
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.GregorianCalendar;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Locale;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.TimeZone;
354caba61ea0433099fc94e61221d02542c34e9e3aElliott Hughes
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
378326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * Utility class for producing strings with formatted date/time.
388326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes *
398326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * <p>Most callers should avoid supplying their own format strings to this
408326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * class' {@code format} methods and rely on the correctly localized ones
418326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * supplied by the system. This class' factory methods return
428326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * appropriately-localized {@link java.text.DateFormat} instances, suitable
438326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * for both formatting and parsing dates. For the canonical documentation
448326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * of format strings, see {@link java.text.SimpleDateFormat}.
458326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes *
46031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * <p>In cases where the system does not provide a suitable pattern,
47031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes * this class offers the {@link #getBestDateTimePattern} method.
48031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes *
49fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * <p>The {@code format} methods in this class implement a subset of Unicode
508326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes * <a href="http://www.unicode.org/reports/tr35/#Date_Format_Patterns">UTS #35</a> patterns.
51fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * The subset currently supported by this class includes the following format characters:
52fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * {@code acdEHhLKkLMmsyz}. Up to API level 17, only {@code adEhkMmszy} were supported.
53fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * Note that this class incorrectly implements {@code k} as if it were {@code H} for backwards
54fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * compatibility.
55fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes *
56fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * <p>See {@link java.text.SimpleDateFormat} for more documentation
57fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * about patterns, or if you need a more complete or correct implementation.
58fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * Note that the non-{@code format} methods in this class are implemented by
59fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes * {@code SimpleDateFormat}.
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class DateFormat {
629d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath    /**
639d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @deprecated Use a literal {@code '} instead.
649d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
659d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     */
668326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public  static final char    QUOTE                  =    '\'';
688326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes
699d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath    /**
709d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @deprecated Use a literal {@code 'a'} instead.
719d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
729d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     */
738326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public  static final char    AM_PM                  =    'a';
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
769d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath    /**
779d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @deprecated Use a literal {@code 'a'} instead; 'A' was always equivalent to 'a'.
789d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
799d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     */
808326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public  static final char    CAPITAL_AM_PM          =    'A';
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
839d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath    /**
849d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @deprecated Use a literal {@code 'd'} instead.
859d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
869d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     */
878326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public  static final char    DATE                   =    'd';
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
909d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath    /**
919d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @deprecated Use a literal {@code 'E'} instead.
929d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
939d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     */
948326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public  static final char    DAY                    =    'E';
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
979d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath    /**
989d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @deprecated Use a literal {@code 'h'} instead.
999d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
1009d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     */
1018326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public  static final char    HOUR                   =    'h';
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
104fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes    /**
105fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes     * @deprecated Use a literal {@code 'H'} (for compatibility with {@link SimpleDateFormat}
106fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes     * and Unicode) or {@code 'k'} (for compatibility with Android releases up to and including
107fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes     * Jelly Bean MR-1) instead. Note that the two are incompatible.
1089d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     *
1099d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
110fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes     */
1118326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public  static final char    HOUR_OF_DAY            =    'k';
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1149d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath    /**
1159d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @deprecated Use a literal {@code 'm'} instead.
1169d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
1179d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     */
1188326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public  static final char    MINUTE                 =    'm';
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1219d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath    /**
1229d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @deprecated Use a literal {@code 'M'} instead.
1239d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
1249d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     */
1258326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public  static final char    MONTH                  =    'M';
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1289d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath    /**
1299d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @deprecated Use a literal {@code 'L'} instead.
1309d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
1319d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     */
1328326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
13334de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes    public  static final char    STANDALONE_MONTH       =    'L';
13434de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes
1359d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath    /**
1369d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @deprecated Use a literal {@code 's'} instead.
1379d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
1389d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     */
1398326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public  static final char    SECONDS                =    's';
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1429d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath    /**
1439d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @deprecated Use a literal {@code 'z'} instead.
1449d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
1459d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     */
1468326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public  static final char    TIME_ZONE              =    'z';
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1499d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath    /**
1509d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @deprecated Use a literal {@code 'y'} instead.
1519d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * @removed
1529d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     */
1538326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    @Deprecated
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public  static final char    YEAR                   =    'y';
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final Object sLocaleLock = new Object();
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static Locale sIs24HourLocale;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean sIs24Hour;
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if user preference is set to 24-hour format.
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context the context to use for the content resolver
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if 24 hour time format is selected, false otherwise.
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static boolean is24HourFormat(Context context) {
1689c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek        return is24HourFormat(context, UserHandle.myUserId());
1699c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek    }
1709c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek
1719c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek    /**
1729c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * Returns true if user preference with the given user handle is set to 24-hour format.
1739c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * @param context the context to use for the content resolver
1749c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * @param userHandle the user handle of the user to query.
1759c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * @return true if 24 hour time format is selected, false otherwise.
1769c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     *
1779c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * @hide
1789c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     */
1799c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek    public static boolean is24HourFormat(Context context, int userHandle) {
1809c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek        String value = Settings.System.getStringForUser(context.getContentResolver(),
1819c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek                Settings.System.TIME_12_24, userHandle);
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (value == null) {
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Locale locale = context.getResources().getConfiguration().locale;
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (sLocaleLock) {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (sIs24HourLocale != null && sIs24HourLocale.equals(locale)) {
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return sIs24Hour;
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            java.text.DateFormat natural =
1939c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek                    java.text.DateFormat.getTimeInstance(java.text.DateFormat.LONG, locale);
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (natural instanceof SimpleDateFormat) {
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                SimpleDateFormat sdf = (SimpleDateFormat) natural;
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                String pattern = sdf.toPattern();
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (pattern.indexOf('H') >= 0) {
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    value = "24";
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    value = "12";
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                value = "12";
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (sLocaleLock) {
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                sIs24HourLocale = locale;
2103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                sIs24Hour = value.equals("24");
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
2133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            return sIs24Hour;
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return value.equals("24");
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
220031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * Returns the best possible localized form of the given skeleton for the given
221031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * locale. A skeleton is similar to, and uses the same format characters as, a Unicode
222031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * <a href="http://www.unicode.org/reports/tr35/#Date_Format_Patterns">UTS #35</a>
223031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * pattern.
224031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     *
225031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * <p>One difference is that order is irrelevant. For example, "MMMMd" will return
226031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * "MMMM d" in the {@code en_US} locale, but "d. MMMM" in the {@code de_CH} locale.
227031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     *
228031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * <p>Note also in that second example that the necessary punctuation for German was
229031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * added. For the same input in {@code es_ES}, we'd have even more extra text:
230031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * "d 'de' MMMM".
231031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     *
232031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * <p>This method will automatically correct for grammatical necessity. Given the
233031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * same "MMMMd" input, this method will return "d LLLL" in the {@code fa_IR} locale,
234031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * where stand-alone months are necessary. Lengths are preserved where meaningful,
235031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * so "Md" would give a different result to "MMMd", say, except in a locale such as
236031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * {@code ja_JP} where there is only one length of month.
237031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     *
238031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * <p>This method will only return patterns that are in CLDR, and is useful whenever
239031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * you know what elements you want in your format string but don't want to make your
240031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * code specific to any one locale.
241031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     *
242031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * @param locale the locale into which the skeleton should be localized
243031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * @param skeleton a skeleton as described above
244031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     * @return a string pattern suitable for use with {@link java.text.SimpleDateFormat}.
245031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes     */
246031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes    public static String getBestDateTimePattern(Locale locale, String skeleton) {
2472c9d2005ecd592fd5b038a6379b5f174d9e65121Narayan Kamath        return ICU.getBestDateTimePattern(skeleton, locale);
248031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes    }
249031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes
250031b581af2a14e9f957e511548b3da41152b2634Elliott Hughes    /**
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns a {@link java.text.DateFormat} object that can format the time according
252af0e7a7394bf1e2596c46f81c3b0302a56daab96Eric Fischer     * to the current locale and the user's 12-/24-hour clock preference.
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context the application context
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the {@link java.text.DateFormat} object that properly formats the time.
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2563d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static java.text.DateFormat getTimeFormat(Context context) {
257cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes        return new java.text.SimpleDateFormat(getTimeFormatString(context));
258cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes    }
259cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes
260cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes    /**
261cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * Returns a String pattern that can be used to format the time according
262cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * to the current locale and the user's 12-/24-hour clock preference.
263cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * @param context the application context
264cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     * @hide
265cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes     */
266cdafd37f3148dfc6f44f2e5de8b31adb6bf9e476Elliott Hughes    public static String getTimeFormatString(Context context) {
2679c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek        return getTimeFormatString(context, UserHandle.myUserId());
2689c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek    }
2699c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek
2709c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek    /**
2719c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * Returns a String pattern that can be used to format the time according
2729c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * to the current locale and the user's 12-/24-hour clock preference.
2739c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * @param context the application context
2749c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * @param userHandle the user handle of the user to query the format for
2759c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     * @hide
2769c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek     */
2779c4a707912da2c954b2d3d1311b8a691ded8aa16Selim Cinek    public static String getTimeFormatString(Context context, int userHandle) {
2784caba61ea0433099fc94e61221d02542c34e9e3aElliott Hughes        LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
2790da89b76402816dade084166a97b1d352ae1f78bJorim Jaggi        return is24HourFormat(context, userHandle) ? d.timeFormat_Hm : d.timeFormat_hm;
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2838326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes     * Returns a {@link java.text.DateFormat} object that can format the date
284f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath     * in short form according to the current locale.
285f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath     *
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context the application context
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the {@link java.text.DateFormat} object that properly formats the date.
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static java.text.DateFormat getDateFormat(Context context) {
290f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath        return java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT);
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2928326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns a {@link java.text.DateFormat} object that can format the date
2958326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes     * in long form (such as {@code Monday, January 3, 2000}) for the current locale.
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context the application context
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the {@link java.text.DateFormat} object that formats the date in long form.
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static java.text.DateFormat getLongDateFormat(Context context) {
3005bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer        return java.text.DateFormat.getDateInstance(java.text.DateFormat.LONG);
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns a {@link java.text.DateFormat} object that can format the date
3058326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes     * in medium form (such as {@code Jan 3, 2000}) for the current locale.
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context the application context
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the {@link java.text.DateFormat} object that formats the date in long form.
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static java.text.DateFormat getMediumDateFormat(Context context) {
3105bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer        return java.text.DateFormat.getDateInstance(java.text.DateFormat.MEDIUM);
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3149d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * Gets the current date format stored as a char array. Returns a 3 element
3159d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * array containing the day ({@code 'd'}), month ({@code 'M'}), and year ({@code 'y'}))
3169d68b3c839046d6a0ef505ab020fc4219ea36170Narayan Kamath     * in the order specified by the user's format preference.  Note that this order is
317edd6f9e688698da4f6ba9da5e56a5546f9162200Elliott Hughes     * <i>only</i> appropriate for all-numeric dates; spelled-out (MEDIUM and LONG)
31803a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer     * dates will generally contain other punctuation, spaces, or words,
31903a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer     * not just the day, month, and year, and not necessarily in the same
32003a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer     * order returned here.
3218326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes     */
3223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static char[] getDateFormatOrder(Context context) {
323f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath        return ICU.getDateFormatOrder(getDateFormatString());
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3258326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes
326f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath    private static String getDateFormatString() {
327f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath        java.text.DateFormat df = java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT);
328f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath        if (df instanceof SimpleDateFormat) {
329f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath            return ((SimpleDateFormat) df).toPattern();
330f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath        }
33103a8017d0fe3b55b69c4328aa0d27bd96a2f1360Eric Fischer
332f91f06a5991451e4af3cf99eba791cb3009810d2Narayan Kamath        throw new AssertionError("!(df instanceof SimpleDateFormat)");
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3368326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes     * Given a format string and a time in milliseconds since Jan 1, 1970 GMT, returns a
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * CharSequence containing the requested date.
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param inFormat the format string, as described in {@link android.text.format.DateFormat}
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param inTimeInMillis in milliseconds since Jan 1, 1970 GMT
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a {@link CharSequence} containing the requested text
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3423d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static CharSequence format(CharSequence inFormat, long inTimeInMillis) {
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return format(inFormat, new Date(inTimeInMillis));
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Given a format string and a {@link java.util.Date} object, returns a CharSequence containing
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the requested date.
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param inFormat the format string, as described in {@link android.text.format.DateFormat}
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param inDate the date to format
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a {@link CharSequence} containing the requested text
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3533d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static CharSequence format(CharSequence inFormat, Date inDate) {
3548326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        Calendar c = new GregorianCalendar();
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        c.setTime(inDate);
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return format(inFormat, c);
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3603d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Indicates whether the specified format string contains seconds.
3618326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes     *
3623d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * Always returns false if the input format is null.
3638326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes     *
3643d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @param inFormat the format string, as described in {@link android.text.format.DateFormat}
3658326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes     *
3663d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @return true if the format string contains {@link #SECONDS}, false otherwise
3678326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes     *
3683d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     * @hide
3693d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy     */
3703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static boolean hasSeconds(CharSequence inFormat) {
37106c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey        return hasDesignator(inFormat, SECONDS);
37206c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey    }
37306c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey
37406c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey    /**
37506c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey     * Test if a format string contains the given designator. Always returns
37606c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey     * {@code false} if the input format is {@code null}.
37706c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey     *
37806c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey     * @hide
37906c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey     */
38006c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey    public static boolean hasDesignator(CharSequence inFormat, char designator) {
3813d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        if (inFormat == null) return false;
3823d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3833d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        final int length = inFormat.length();
3843d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3853d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        int c;
3863d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        int count;
3873d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3883d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        for (int i = 0; i < length; i += count) {
3893d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            count = 1;
3903d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            c = inFormat.charAt(i);
3913d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3923d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            if (c == QUOTE) {
3933d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                count = skipQuotedText(inFormat, i, length);
39406c5f8a768bcd4f7b6441f7525bd5c639399fc76Jeff Sharkey            } else if (c == designator) {
3953d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                return true;
3963d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            }
3973d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
3983d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
3993d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return false;
4003d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4013d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4023d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private static int skipQuotedText(CharSequence s, int i, int len) {
4033d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        if (i + 1 < len && s.charAt(i + 1) == QUOTE) {
4043d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            return 2;
4053d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
4063d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4073d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        int count = 1;
4083d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        // skip leading quote
4093d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        i++;
4103d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4113d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        while (i < len) {
4123d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            char c = s.charAt(i);
4133d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4143d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            if (c == QUOTE) {
4153d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                count++;
4163d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                //  QUOTEQUOTE -> QUOTE
4173d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                if (i + 1 < len && s.charAt(i + 1) == QUOTE) {
4183d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                    i++;
4193d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                } else {
4203d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                    break;
4213d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                }
4223d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            } else {
4233d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                i++;
4243d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy                count++;
4253d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy            }
4263d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        }
4273d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4283d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy        return count;
4293d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    }
4303d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy
4313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    /**
4328326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes     * Given a format string and a {@link java.util.Calendar} object, returns a CharSequence
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * containing the requested date.
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param inFormat the format string, as described in {@link android.text.format.DateFormat}
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param inDate the date to format
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return a {@link CharSequence} containing the requested text
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4383d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    public static CharSequence format(CharSequence inFormat, Calendar inDate) {
4398326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        SpannableStringBuilder s = new SpannableStringBuilder(inFormat);
4408326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        int count;
4418326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes
4428326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        LocaleData localeData = LocaleData.get(Locale.getDefault());
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int len = inFormat.length();
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < len; i += count) {
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            count = 1;
4488326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes            int c = s.charAt(i);
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (c == QUOTE) {
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                count = appendQuotedText(s, i, len);
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                len = s.length();
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                continue;
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while ((i + count < len) && (s.charAt(i + count) == c)) {
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                count++;
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String replacement;
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (c) {
4628326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                case 'A':
4638326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                case 'a':
4648326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                    replacement = localeData.amPm[inDate.get(Calendar.AM_PM) - Calendar.AM];
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
4668326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                case 'd':
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    replacement = zeroPad(inDate.get(Calendar.DATE), count);
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
4698326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                case 'c':
4708326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                case 'E':
4718326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                    replacement = getDayOfWeekString(localeData,
4728326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                                                     inDate.get(Calendar.DAY_OF_WEEK), count, c);
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
4747a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                case 'K': // hour in am/pm (0-11)
4757a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                case 'h': // hour in am/pm (1-12)
4767a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                    {
4777a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                        int hour = inDate.get(Calendar.HOUR);
4787a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                        if (c == 'h' && hour == 0) {
4797a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                            hour = 12;
4807a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                        }
4817a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                        replacement = zeroPad(hour, count);
4827a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                    }
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
4847a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                case 'H': // hour in day (0-23)
485fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes                case 'k': // hour in day (1-24) [but see note below]
4867a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                    {
4877a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                        int hour = inDate.get(Calendar.HOUR_OF_DAY);
488fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes                        // Historically on Android 'k' was interpreted as 'H', which wasn't
489fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes                        // implemented, so pretty much all callers that want to format 24-hour
490fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes                        // times are abusing 'k'. http://b/8359981.
491fc55c2ba49957bb696b98d290964dc36f4827190Elliott Hughes                        if (false && c == 'k' && hour == 0) {
4927a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                            hour = 24;
4937a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                        }
4947a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                        replacement = zeroPad(hour, count);
4957a89f62877a03d249d9e7d0562058b973d747c49Elliott Hughes                    }
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
4978326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                case 'L':
4988326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                case 'M':
4998326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                    replacement = getMonthString(localeData,
5008326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                                                 inDate.get(Calendar.MONTH), count, c);
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
5028326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                case 'm':
5038326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                    replacement = zeroPad(inDate.get(Calendar.MINUTE), count);
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
5058326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                case 's':
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    replacement = zeroPad(inDate.get(Calendar.SECOND), count);
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
5088326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                case 'y':
5098326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                    replacement = getYearString(inDate.get(Calendar.YEAR), count);
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
5118326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                case 'z':
5128326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes                    replacement = getTimeZoneString(inDate, count);
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                default:
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    replacement = null;
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5188326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (replacement != null) {
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                s.replace(i, i + count, replacement);
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                count = replacement.length(); // CARE: count is used in the for loop above
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                len = s.length();
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5258326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes
5268326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        if (inFormat instanceof Spanned) {
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return new SpannedString(s);
5288326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        } else {
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return s.toString();
5308326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        }
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5328326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes
5338326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    private static String getDayOfWeekString(LocaleData ld, int day, int count, int kind) {
5348326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        boolean standalone = (kind == 'c');
5358326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        if (count == 5) {
5368326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes            return standalone ? ld.tinyStandAloneWeekdayNames[day] : ld.tinyWeekdayNames[day];
5378326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        } else if (count == 4) {
5388326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes            return standalone ? ld.longStandAloneWeekdayNames[day] : ld.longWeekdayNames[day];
5398326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        } else {
5408326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes            return standalone ? ld.shortStandAloneWeekdayNames[day] : ld.shortWeekdayNames[day];
5418326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        }
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5438326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes
5448326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    private static String getMonthString(LocaleData ld, int month, int count, int kind) {
5458326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        boolean standalone = (kind == 'L');
5468326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        if (count == 5) {
5478326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes            return standalone ? ld.tinyStandAloneMonthNames[month] : ld.tinyMonthNames[month];
5488326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes        } else if (count == 4) {
5498326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes            return standalone ? ld.longStandAloneMonthNames[month] : ld.longMonthNames[month];
55034de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes        } else if (count == 3) {
5518326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes            return standalone ? ld.shortStandAloneMonthNames[month] : ld.shortMonthNames[month];
55234de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes        } else {
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Calendar.JANUARY == 0, so add 1 to month.
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return zeroPad(month+1, count);
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5578326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes
5583d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private static String getTimeZoneString(Calendar inDate, int count) {
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        TimeZone tz = inDate.getTimeZone();
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count < 2) { // FIXME: shouldn't this be <= 2 ?
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return formatZoneOffset(inDate.get(Calendar.DST_OFFSET) +
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    inDate.get(Calendar.ZONE_OFFSET),
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    count);
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean dst = inDate.get(Calendar.DST_OFFSET) != 0;
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return tz.getDisplayName(dst, TimeZone.SHORT);
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5703d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private static String formatZoneOffset(int offset, int count) {
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        offset /= 1000; // milliseconds to seconds
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder tb = new StringBuilder();
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (offset < 0) {
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            tb.insert(0, "-");
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            offset = -offset;
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            tb.insert(0, "+");
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int hours = offset / 3600;
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int minutes = (offset % 3600) / 60;
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        tb.append(zeroPad(hours, 2));
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        tb.append(zeroPad(minutes, 2));
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return tb.toString();
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5888326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes
5898326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes    private static String getYearString(int year, int count) {
59034de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes        return (count <= 2) ? zeroPad(year % 100, 2)
59134de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes                            : String.format(Locale.getDefault(), "%d", year);
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5938326b9a429b63b680aa9af116c670ce674744d80Elliott Hughes
5943d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private static int appendQuotedText(SpannableStringBuilder s, int i, int len) {
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (i + 1 < len && s.charAt(i + 1) == QUOTE) {
5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            s.delete(i, i + 1);
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 1;
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = 0;
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // delete leading quote
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        s.delete(i, i + 1);
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        len--;
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (i < len) {
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            char c = s.charAt(i);
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (c == QUOTE) {
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                //  QUOTEQUOTE -> QUOTE
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (i + 1 < len && s.charAt(i + 1) == QUOTE) {
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    s.delete(i, i + 1);
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    len--;
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    count++;
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    i++;
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    //  Closing QUOTE ends quoted text copying
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    s.delete(i, i + 1);
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                i++;
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                count++;
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return count;
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6313d1728c03a0cd1aaed6bc81c97de27d62c771a6eRomain Guy    private static String zeroPad(int inValue, int inMinDigits) {
63234de3bc309fd9077cc1aa1e1af82652670fdb9dfElliott Hughes        return String.format(Locale.getDefault(), "%0" + inMinDigits + "d", inValue);
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
635