1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * you may not use this file except in compliance with the License.
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * You may obtain a copy of the License at
7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17757a7942eed2b0aa457f8517a0259d2ac82c5b18Elliott Hughes#define LOG_TAG "ICU"
18c08f9fb2a3be82bb1a3f477ca1524ddcf7a1d4b8Elliott Hughes
193aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes#include "IcuUtilities.h"
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include "JNIHelp.h"
21a9f5c16a864ff63ba63f810410f8a27c086d5d52Elliott Hughes#include "JniConstants.h"
22bef9ec33e1368f57c731fce63b6a8c61628c64b0Elliott Hughes#include "JniException.h"
23566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes#include "ScopedFd.h"
24a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes#include "ScopedIcuLocale.h"
254e3714f7fe8ac7f6b20896038e491d378f4e6464Elliott Hughes#include "ScopedJavaUnicodeString.h"
26f281667712baf8e0721ceb2cc60e7eef19c2d859Elliott Hughes#include "ScopedLocalRef.h"
279de899cc3ffd3aa3f8f827201cbe14120609018bElliott Hughes#include "ScopedUtfChars.h"
28f2d5062b67e57ef00ee81fec67480f0d58d66b50Elliott Hughes#include "cutils/log.h"
29ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes#include "toStringArray.h"
303879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes#include "unicode/brkiter.h"
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include "unicode/calendar.h"
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include "unicode/datefmt.h"
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include "unicode/dcfmtsym.h"
3494782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "unicode/decimfmt.h"
3594782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "unicode/dtfmtsym.h"
36cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes#include "unicode/dtptngen.h"
3794782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "unicode/gregocal.h"
3894782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "unicode/locid.h"
3994782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "unicode/numfmt.h"
40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include "unicode/strenum.h"
41cf14cc4ee0de8c3e4f9a1dab7a5a91d09264dee9Neil Fuller#include "unicode/timezone.h"
4294782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "unicode/ubrk.h"
4394782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "unicode/ucal.h"
4494782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "unicode/uclean.h"
4594782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "unicode/ucol.h"
4694782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "unicode/ucurr.h"
4794782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "unicode/udat.h"
480452e9adf6fb133b6d3e59ebae2135aa90ad0d5eFabrice Di Meglio#include "unicode/uloc.h"
4915d82808bab24f399a034d086f587d5fab32522eElliott Hughes#include "unicode/ulocdata.h"
5094782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "unicode/ustring.h"
51947eeb80f985827209c9500851e288504d58ec2eclaireho#include "ureslocs.h"
5294782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes#include "valueOf.h"
53ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes
54566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes#include <errno.h>
55566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes#include <fcntl.h>
56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <stdlib.h>
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <string.h>
58ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes#include <string>
59566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes#include <sys/mman.h>
60566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes#include <sys/stat.h>
61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project#include <sys/time.h>
62566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes#include <sys/types.h>
63566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes#include <time.h>
64566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes#include <unistd.h>
65b3aacde3d8af759ee4a7b395c636ea360547d92dIan Rogers#include <memory>
66c5b1eb191102a20bc0626aea955aba417e337fbcNarayan Kamath#include <vector>
67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6870fa193185427473999f1cda823c1ec408acd2baElliott Hughesclass ScopedResourceBundle {
69c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes public:
70c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  ScopedResourceBundle(UResourceBundle* bundle) : bundle_(bundle) {
71c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
73c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  ~ScopedResourceBundle() {
74c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    if (bundle_ != NULL) {
75c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes      ures_close(bundle_);
7670fa193185427473999f1cda823c1ec408acd2baElliott Hughes    }
77c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
79c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  UResourceBundle* get() {
80c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    return bundle_;
81c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
8270fa193185427473999f1cda823c1ec408acd2baElliott Hughes
83c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  bool hasKey(const char* key) {
84c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    UErrorCode status = U_ZERO_ERROR;
85c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    ures_getStringByKey(bundle_, key, NULL, &status);
86c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    return U_SUCCESS(status);
87c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
887ca6fd0dca02f7abdd8808db78357743bbdd23a5Elliott Hughes
89c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes private:
90c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  UResourceBundle* bundle_;
91c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  DISALLOW_COPY_AND_ASSIGN(ScopedResourceBundle);
9270fa193185427473999f1cda823c1ec408acd2baElliott Hughes};
9370fa193185427473999f1cda823c1ec408acd2baElliott Hughes
94a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic jstring ICU_addLikelySubtags(JNIEnv* env, jclass, jstring javaLocaleName) {
950452e9adf6fb133b6d3e59ebae2135aa90ad0d5eFabrice Di Meglio    UErrorCode status = U_ZERO_ERROR;
96a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    ScopedUtfChars localeID(env, javaLocaleName);
970452e9adf6fb133b6d3e59ebae2135aa90ad0d5eFabrice Di Meglio    char maximizedLocaleID[ULOC_FULLNAME_CAPACITY];
980452e9adf6fb133b6d3e59ebae2135aa90ad0d5eFabrice Di Meglio    uloc_addLikelySubtags(localeID.c_str(), maximizedLocaleID, sizeof(maximizedLocaleID), &status);
990452e9adf6fb133b6d3e59ebae2135aa90ad0d5eFabrice Di Meglio    if (U_FAILURE(status)) {
100a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes        return javaLocaleName;
1010452e9adf6fb133b6d3e59ebae2135aa90ad0d5eFabrice Di Meglio    }
1020452e9adf6fb133b6d3e59ebae2135aa90ad0d5eFabrice Di Meglio    return env->NewStringUTF(maximizedLocaleID);
1030452e9adf6fb133b6d3e59ebae2135aa90ad0d5eFabrice Di Meglio}
1040452e9adf6fb133b6d3e59ebae2135aa90ad0d5eFabrice Di Meglio
105a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic jstring ICU_getScript(JNIEnv* env, jclass, jstring javaLocaleName) {
106a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuLocale(env, javaLocaleName);
107a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuLocale.valid()) {
108a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
109a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
110a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  return env->NewStringUTF(icuLocale.locale().getScript());
1114c94a6128d1fcfaa75539b36c9f50d0c75df6144Fabrice Di Meglio}
1124c94a6128d1fcfaa75539b36c9f50d0c75df6144Fabrice Di Meglio
11352b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughesstatic jint ICU_getCurrencyFractionDigits(JNIEnv* env, jclass, jstring javaCurrencyCode) {
1143aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode);
1153aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  if (!currencyCode.valid()) {
1163aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes    return 0;
1173aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  }
118a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString icuCurrencyCode(currencyCode.unicodeString());
1193aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  UErrorCode status = U_ZERO_ERROR;
1203aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  return ucurr_getDefaultFractionDigits(icuCurrencyCode.getTerminatedBuffer(), &status);
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
123d627bd4525e41b0503f94c2887c3e01618c73105Neil Fullerstatic jint ICU_getCurrencyNumericCode(JNIEnv* env, jclass, jstring javaCurrencyCode) {
124d627bd4525e41b0503f94c2887c3e01618c73105Neil Fuller  ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode);
125d627bd4525e41b0503f94c2887c3e01618c73105Neil Fuller  if (!currencyCode.valid()) {
126d627bd4525e41b0503f94c2887c3e01618c73105Neil Fuller    return 0;
127d627bd4525e41b0503f94c2887c3e01618c73105Neil Fuller  }
128a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString icuCurrencyCode(currencyCode.unicodeString());
129d627bd4525e41b0503f94c2887c3e01618c73105Neil Fuller  return ucurr_getNumericCode(icuCurrencyCode.getTerminatedBuffer());
130d627bd4525e41b0503f94c2887c3e01618c73105Neil Fuller}
131d627bd4525e41b0503f94c2887c3e01618c73105Neil Fuller
132a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes// TODO: rewrite this with int32_t ucurr_forLocale(const char* locale, UChar* buff, int32_t buffCapacity, UErrorCode* ec)...
13352b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughesstatic jstring ICU_getCurrencyCode(JNIEnv* env, jclass, jstring javaCountryCode) {
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    UErrorCode status = U_ZERO_ERROR;
135947eeb80f985827209c9500851e288504d58ec2eclaireho    ScopedResourceBundle supplData(ures_openDirect(U_ICUDATA_CURR, "supplementalData", &status));
13670fa193185427473999f1cda823c1ec408acd2baElliott Hughes    if (U_FAILURE(status)) {
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return NULL;
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
14070fa193185427473999f1cda823c1ec408acd2baElliott Hughes    ScopedResourceBundle currencyMap(ures_getByKey(supplData.get(), "CurrencyMap", NULL, &status));
14170fa193185427473999f1cda823c1ec408acd2baElliott Hughes    if (U_FAILURE(status)) {
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return NULL;
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
14552b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes    ScopedUtfChars countryCode(env, javaCountryCode);
14652b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes    ScopedResourceBundle currency(ures_getByKey(currencyMap.get(), countryCode.c_str(), NULL, &status));
14770fa193185427473999f1cda823c1ec408acd2baElliott Hughes    if (U_FAILURE(status)) {
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return NULL;
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
15170fa193185427473999f1cda823c1ec408acd2baElliott Hughes    ScopedResourceBundle currencyElem(ures_getByIndex(currency.get(), 0, NULL, &status));
15270fa193185427473999f1cda823c1ec408acd2baElliott Hughes    if (U_FAILURE(status)) {
1535b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho        return env->NewStringUTF("XXX");
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
15652b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes    // Check if there's a 'to' date. If there is, the currency isn't used anymore.
15767081ff5bcb8a2b3f7db2940f6e0cb3e459ab4b4Elliott Hughes    ScopedResourceBundle currencyTo(ures_getByKey(currencyElem.get(), "to", NULL, &status));
15867081ff5bcb8a2b3f7db2940f6e0cb3e459ab4b4Elliott Hughes    if (!U_FAILURE(status)) {
15967081ff5bcb8a2b3f7db2940f6e0cb3e459ab4b4Elliott Hughes        return NULL;
160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
16152b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes    // Ignore the failure to find a 'to' date.
16267081ff5bcb8a2b3f7db2940f6e0cb3e459ab4b4Elliott Hughes    status = U_ZERO_ERROR;
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
16470fa193185427473999f1cda823c1ec408acd2baElliott Hughes    ScopedResourceBundle currencyId(ures_getByKey(currencyElem.get(), "id", NULL, &status));
16570fa193185427473999f1cda823c1ec408acd2baElliott Hughes    if (U_FAILURE(status)) {
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        // No id defined for this country
1675b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho        return env->NewStringUTF("XXX");
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
17052b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes    int32_t charCount;
17152b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes    const jchar* chars = ures_getString(currencyId.get(), &charCount, &status);
1725b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    return (charCount == 0) ? env->NewStringUTF("XXX") : env->NewString(chars, charCount);
17352b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes}
17452b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes
175a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic jstring getCurrencyName(JNIEnv* env, jstring javaLanguageTag, jstring javaCurrencyCode, UCurrNameStyle nameStyle) {
176a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedUtfChars languageTag(env, javaLanguageTag);
177a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (languageTag.c_str() == NULL) {
1783aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes    return NULL;
1793aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  }
180a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes  ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode);
1813aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  if (!currencyCode.valid()) {
1823aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes    return NULL;
1833aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  }
184a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString icuCurrencyCode(currencyCode.unicodeString());
185a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes  UErrorCode status = U_ZERO_ERROR;
186a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes  UBool isChoiceFormat = false;
187a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes  int32_t charCount;
188a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  const UChar* chars = ucurr_getName(icuCurrencyCode.getTerminatedBuffer(), languageTag.c_str(),
189a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes                                     nameStyle, &isChoiceFormat, &charCount, &status);
190a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes  if (status == U_USING_DEFAULT_WARNING) {
191a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes    if (nameStyle == UCURR_SYMBOL_NAME) {
192a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes      // ICU doesn't distinguish between falling back to the root locale and meeting a genuinely
193a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes      // unknown currency. The Currency class does.
194a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes      if (!ucurr_isAvailable(icuCurrencyCode.getTerminatedBuffer(), U_DATE_MIN, U_DATE_MAX, &status)) {
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return NULL;
196a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes      }
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
198a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes    if (nameStyle == UCURR_LONG_NAME) {
199a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes      // ICU's default is English. We want the ISO 4217 currency code instead.
200a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes      chars = icuCurrencyCode.getBuffer();
201a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes      charCount = icuCurrencyCode.length();
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
203a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes  }
204a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes  return (charCount == 0) ? NULL : env->NewString(chars, charCount);
205a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes}
206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
207a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic jstring ICU_getCurrencyDisplayName(JNIEnv* env, jclass, jstring javaLanguageTag, jstring javaCurrencyCode) {
208a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  return getCurrencyName(env, javaLanguageTag, javaCurrencyCode, UCURR_LONG_NAME);
209a49a1e8c20b3cf9435ed422379f63e33e5c2eaf2Elliott Hughes}
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
211a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic jstring ICU_getCurrencySymbol(JNIEnv* env, jclass, jstring javaLanguageTag, jstring javaCurrencyCode) {
212a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  return getCurrencyName(env, javaLanguageTag, javaCurrencyCode, UCURR_SYMBOL_NAME);
213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
214adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
215a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic jstring ICU_getDisplayCountryNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
216a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuLocale(env, javaLanguageTag);
217a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuLocale.valid()) {
218a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
219a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
220a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
221a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuTargetLocale.valid()) {
222a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
223a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
224a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes
225a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString str;
226a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  icuTargetLocale.locale().getDisplayCountry(icuLocale.locale(), str);
227a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  return env->NewString(str.getBuffer(), str.length());
228adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
229adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
230a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic jstring ICU_getDisplayLanguageNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
231a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuLocale(env, javaLanguageTag);
232a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuLocale.valid()) {
233a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
234a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
235a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
236a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuTargetLocale.valid()) {
237a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
238a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
239a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes
240a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString str;
241a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  icuTargetLocale.locale().getDisplayLanguage(icuLocale.locale(), str);
242a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  return env->NewString(str.getBuffer(), str.length());
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
245a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic jstring ICU_getDisplayScriptNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
246a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuLocale(env, javaLanguageTag);
247a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuLocale.valid()) {
248a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
249a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
250a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
251a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuTargetLocale.valid()) {
252a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
253a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
254a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes
255a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString str;
256a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  icuTargetLocale.locale().getDisplayScript(icuLocale.locale(), str);
257a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  return env->NewString(str.getBuffer(), str.length());
258c5b1eb191102a20bc0626aea955aba417e337fbcNarayan Kamath}
259c5b1eb191102a20bc0626aea955aba417e337fbcNarayan Kamath
260a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic jstring ICU_getDisplayVariantNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
261a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuLocale(env, javaLanguageTag);
262a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuLocale.valid()) {
263a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
264a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
265a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
266a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuTargetLocale.valid()) {
267a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
268a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
269a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes
270a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString str;
271a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  icuTargetLocale.locale().getDisplayVariant(icuLocale.locale(), str);
272a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  return env->NewString(str.getBuffer(), str.length());
273adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
275ca6c2dfd21fef61f179223fb710db791802068d5Narayan Kamathstatic jstring ICU_getISO3Country(JNIEnv* env, jclass, jstring javaLanguageTag) {
276a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuLocale(env, javaLanguageTag);
277a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuLocale.valid()) {
278a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
279a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
280a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  return env->NewStringUTF(icuLocale.locale().getISO3Country());
281adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
283ca6c2dfd21fef61f179223fb710db791802068d5Narayan Kamathstatic jstring ICU_getISO3Language(JNIEnv* env, jclass, jstring javaLanguageTag) {
284a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuLocale(env, javaLanguageTag);
285a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuLocale.valid()) {
286a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
287a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
288a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  return env->NewStringUTF(icuLocale.locale().getISO3Language());
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
291e22935d3c7040c22b48d53bd18878844f381287cElliott Hughesstatic jobjectArray ICU_getISOCountriesNative(JNIEnv* env, jclass) {
292a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    return toStringArray(env, icu::Locale::getISOCountries());
2932e3a41defb42a97b463194d859d2d4088a600fd8Elliott Hughes}
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
295e22935d3c7040c22b48d53bd18878844f381287cElliott Hughesstatic jobjectArray ICU_getISOLanguagesNative(JNIEnv* env, jclass) {
296a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    return toStringArray(env, icu::Locale::getISOLanguages());
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
299e22935d3c7040c22b48d53bd18878844f381287cElliott Hughesstatic jobjectArray ICU_getAvailableLocalesNative(JNIEnv* env, jclass) {
300ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes    return toStringArray(env, uloc_countAvailable, uloc_getAvailable);
301f9157eaea53923d3dbe6a521b29427819052f176Elliott Hughes}
302f9157eaea53923d3dbe6a521b29427819052f176Elliott Hughes
303e22935d3c7040c22b48d53bd18878844f381287cElliott Hughesstatic jobjectArray ICU_getAvailableBreakIteratorLocalesNative(JNIEnv* env, jclass) {
304ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes    return toStringArray(env, ubrk_countAvailable, ubrk_getAvailable);
305f9157eaea53923d3dbe6a521b29427819052f176Elliott Hughes}
306f9157eaea53923d3dbe6a521b29427819052f176Elliott Hughes
307e22935d3c7040c22b48d53bd18878844f381287cElliott Hughesstatic jobjectArray ICU_getAvailableCalendarLocalesNative(JNIEnv* env, jclass) {
308ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes    return toStringArray(env, ucal_countAvailable, ucal_getAvailable);
309f9157eaea53923d3dbe6a521b29427819052f176Elliott Hughes}
310f9157eaea53923d3dbe6a521b29427819052f176Elliott Hughes
311e22935d3c7040c22b48d53bd18878844f381287cElliott Hughesstatic jobjectArray ICU_getAvailableCollatorLocalesNative(JNIEnv* env, jclass) {
312ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes    return toStringArray(env, ucol_countAvailable, ucol_getAvailable);
313f9157eaea53923d3dbe6a521b29427819052f176Elliott Hughes}
314f9157eaea53923d3dbe6a521b29427819052f176Elliott Hughes
315e22935d3c7040c22b48d53bd18878844f381287cElliott Hughesstatic jobjectArray ICU_getAvailableDateFormatLocalesNative(JNIEnv* env, jclass) {
316ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes    return toStringArray(env, udat_countAvailable, udat_getAvailable);
317f9157eaea53923d3dbe6a521b29427819052f176Elliott Hughes}
318f9157eaea53923d3dbe6a521b29427819052f176Elliott Hughes
319e22935d3c7040c22b48d53bd18878844f381287cElliott Hughesstatic jobjectArray ICU_getAvailableNumberFormatLocalesNative(JNIEnv* env, jclass) {
320ddafeb1d73cfe504720d10a2634b5858fc4cc413Elliott Hughes    return toStringArray(env, unum_countAvailable, unum_getAvailable);
321f9157eaea53923d3dbe6a521b29427819052f176Elliott Hughes}
322f9157eaea53923d3dbe6a521b29427819052f176Elliott Hughes
32333aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughesstatic void setIntegerField(JNIEnv* env, jobject obj, const char* fieldName, int value) {
32494782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes    ScopedLocalRef<jobject> integerValue(env, integerValueOf(env, value));
325a9f5c16a864ff63ba63f810410f8a27c086d5d52Elliott Hughes    jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, fieldName, "Ljava/lang/Integer;");
32694782d07dd2d65b1a37fddca68eb9a9ac81ada4aElliott Hughes    env->SetObjectField(obj, fid, integerValue.get());
32733aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes}
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
32933aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughesstatic void setStringField(JNIEnv* env, jobject obj, const char* fieldName, jstring value) {
330a9f5c16a864ff63ba63f810410f8a27c086d5d52Elliott Hughes    jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, fieldName, "Ljava/lang/String;");
33133aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes    env->SetObjectField(obj, fid, value);
332e2377cdd707b830d07a5708216834f7ac76ee3e1Elliott Hughes    env->DeleteLocalRef(value);
33333aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes}
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
33533aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughesstatic void setStringArrayField(JNIEnv* env, jobject obj, const char* fieldName, jobjectArray value) {
336a9f5c16a864ff63ba63f810410f8a27c086d5d52Elliott Hughes    jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, fieldName, "[Ljava/lang/String;");
33733aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes    env->SetObjectField(obj, fid, value);
33833aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes}
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
340a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughesstatic void setStringArrayField(JNIEnv* env, jobject obj, const char* fieldName, const icu::UnicodeString* valueArray, int32_t size) {
3415b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    ScopedLocalRef<jobjectArray> result(env, env->NewObjectArray(size, JniConstants::stringClass, NULL));
3425b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    for (int32_t i = 0; i < size ; i++) {
3435b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho        ScopedLocalRef<jstring> s(env, env->NewString(valueArray[i].getBuffer(),valueArray[i].length()));
3445b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho        if (env->ExceptionCheck()) {
3455b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho            return;
3465b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho        }
3475b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho        env->SetObjectArrayElement(result.get(), i, s.get());
3485b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho        if (env->ExceptionCheck()) {
3495b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho            return;
3505b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho        }
3515b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    }
3525b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringArrayField(env, obj, fieldName, result.get());
3535b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho}
3545b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho
35533aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughesstatic void setStringField(JNIEnv* env, jobject obj, const char* fieldName, UResourceBundle* bundle, int index) {
356c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  UErrorCode status = U_ZERO_ERROR;
357c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  int charCount;
358c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  const UChar* chars = ures_getStringByIndex(bundle, index, &charCount, &status);
359c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  if (U_SUCCESS(status)) {
360c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    setStringField(env, obj, fieldName, env->NewString(chars, charCount));
361c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  } else {
362c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    ALOGE("Error setting String field %s from ICU resource (index %d): %s", fieldName, index, u_errorName(status));
363c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
364c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes}
365c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
366a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughesstatic void setCharField(JNIEnv* env, jobject obj, const char* fieldName, const icu::UnicodeString& value) {
3675b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    if (value.length() == 0) {
3685b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho        return;
3693be1277a4644a149c158f99febbab890fc7b708fclaireho    }
3705b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    jfieldID fid = env->GetFieldID(JniConstants::localeDataClass, fieldName, "C");
3715b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    env->SetCharField(obj, fid, value.charAt(0));
3723be1277a4644a149c158f99febbab890fc7b708fclaireho}
3733be1277a4644a149c158f99febbab890fc7b708fclaireho
374a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughesstatic void setStringField(JNIEnv* env, jobject obj, const char* fieldName, const icu::UnicodeString& value) {
3755b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    const UChar* chars = value.getBuffer();
3765b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringField(env, obj, fieldName, env->NewString(chars, value.length()));
3773be1277a4644a149c158f99febbab890fc7b708fclaireho}
3783be1277a4644a149c158f99febbab890fc7b708fclaireho
379a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughesstatic void setNumberPatterns(JNIEnv* env, jobject obj, icu::Locale& locale) {
3803be1277a4644a149c158f99febbab890fc7b708fclaireho    UErrorCode status = U_ZERO_ERROR;
3813be1277a4644a149c158f99febbab890fc7b708fclaireho
382a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    icu::UnicodeString pattern;
383a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    std::unique_ptr<icu::DecimalFormat> fmt(static_cast<icu::DecimalFormat*>(icu::NumberFormat::createInstance(locale, UNUM_CURRENCY, status)));
3845b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    pattern = fmt->toPattern(pattern.remove());
3855b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringField(env, obj, "currencyPattern", pattern);
3863be1277a4644a149c158f99febbab890fc7b708fclaireho
387a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    fmt.reset(static_cast<icu::DecimalFormat*>(icu::NumberFormat::createInstance(locale, UNUM_DECIMAL, status)));
3885b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    pattern = fmt->toPattern(pattern.remove());
3895b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringField(env, obj, "numberPattern", pattern);
3903be1277a4644a149c158f99febbab890fc7b708fclaireho
391a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    fmt.reset(static_cast<icu::DecimalFormat*>(icu::NumberFormat::createInstance(locale, UNUM_PERCENT, status)));
3925b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    pattern = fmt->toPattern(pattern.remove());
3935b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringField(env, obj, "percentPattern", pattern);
3943be1277a4644a149c158f99febbab890fc7b708fclaireho}
3953be1277a4644a149c158f99febbab890fc7b708fclaireho
396a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughesstatic void setDecimalFormatSymbolsData(JNIEnv* env, jobject obj, icu::Locale& locale) {
3973be1277a4644a149c158f99febbab890fc7b708fclaireho    UErrorCode status = U_ZERO_ERROR;
398a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    icu::DecimalFormatSymbols dfs(locale, status);
3995b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho
400a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    setCharField(env, obj, "decimalSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kDecimalSeparatorSymbol));
401a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    setCharField(env, obj, "groupingSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kGroupingSeparatorSymbol));
402a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    setCharField(env, obj, "patternSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kPatternSeparatorSymbol));
403a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    setStringField(env, obj, "percent", dfs.getSymbol(icu::DecimalFormatSymbols::kPercentSymbol));
404a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    setCharField(env, obj, "perMill", dfs.getSymbol(icu::DecimalFormatSymbols::kPerMillSymbol));
405a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    setCharField(env, obj, "monetarySeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kMonetarySeparatorSymbol));
406a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    setStringField(env, obj, "minusSign", dfs.getSymbol(icu::DecimalFormatSymbols:: kMinusSignSymbol));
407a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    setStringField(env, obj, "exponentSeparator", dfs.getSymbol(icu::DecimalFormatSymbols::kExponentialSymbol));
408a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    setStringField(env, obj, "infinity", dfs.getSymbol(icu::DecimalFormatSymbols::kInfinitySymbol));
409a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    setStringField(env, obj, "NaN", dfs.getSymbol(icu::DecimalFormatSymbols::kNaNSymbol));
410a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    setCharField(env, obj, "zeroDigit", dfs.getSymbol(icu::DecimalFormatSymbols::kZeroDigitSymbol));
4113be1277a4644a149c158f99febbab890fc7b708fclaireho}
4123be1277a4644a149c158f99febbab890fc7b708fclaireho
413c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
414c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes// Iterates up through the locale hierarchy. So "en_US" would return "en_US", "en", "".
415c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughesclass LocaleNameIterator {
416c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes public:
417c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  LocaleNameIterator(const char* locale_name, UErrorCode& status) : status_(status), has_next_(true) {
418c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    strcpy(locale_name_, locale_name);
419c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    locale_name_length_ = strlen(locale_name_);
420c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
421c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
422c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  const char* Get() {
423c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes      return locale_name_;
424c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
425c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
426c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  bool HasNext() {
427c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    return has_next_;
428c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
429c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
430c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  void Up() {
431c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    if (locale_name_length_ == 0) {
432c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes      has_next_ = false;
433f001abe6478c2ece3d86138f649a5459de85a50aElliott Hughes    } else {
434f001abe6478c2ece3d86138f649a5459de85a50aElliott Hughes      locale_name_length_ = uloc_getParent(locale_name_, locale_name_, sizeof(locale_name_), &status_);
435c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    }
436c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
437c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
438c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes private:
439c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  UErrorCode& status_;
440c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  bool has_next_;
441c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  char locale_name_[ULOC_FULLNAME_CAPACITY];
442c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  int32_t locale_name_length_;
443c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
444c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  DISALLOW_COPY_AND_ASSIGN(LocaleNameIterator);
445c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes};
446c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
447b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughesstatic bool getAmPmMarkersNarrow(JNIEnv* env, jobject localeData, const char* locale_name) {
448b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  UErrorCode status = U_ZERO_ERROR;
449b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  ScopedResourceBundle root(ures_open(NULL, locale_name, &status));
450b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  if (U_FAILURE(status)) {
451b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes    return false;
452b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  }
453b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
454b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  if (U_FAILURE(status)) {
455b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes    return false;
456b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  }
457b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
458b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  if (U_FAILURE(status)) {
459b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes    return false;
460b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  }
461b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  ScopedResourceBundle amPmMarkersNarrow(ures_getByKey(gregorian.get(), "AmPmMarkersNarrow", NULL, &status));
462b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  if (U_FAILURE(status)) {
463b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes    return false;
464b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  }
465b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  setStringField(env, localeData, "narrowAm", amPmMarkersNarrow.get(), 0);
466b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  setStringField(env, localeData, "narrowPm", amPmMarkersNarrow.get(), 1);
467b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes  return true;
468b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes}
469b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes
470c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughesstatic bool getDateTimePatterns(JNIEnv* env, jobject localeData, const char* locale_name) {
471c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  UErrorCode status = U_ZERO_ERROR;
472c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  ScopedResourceBundle root(ures_open(NULL, locale_name, &status));
473c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  if (U_FAILURE(status)) {
474c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    return false;
475c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
476c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
477c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  if (U_FAILURE(status)) {
478c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    return false;
479c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
480c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
481c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  if (U_FAILURE(status)) {
482c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    return false;
483c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
484c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  ScopedResourceBundle dateTimePatterns(ures_getByKey(gregorian.get(), "DateTimePatterns", NULL, &status));
485c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  if (U_FAILURE(status)) {
486c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    return false;
487c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
488c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  setStringField(env, localeData, "fullTimeFormat", dateTimePatterns.get(), 0);
489c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  setStringField(env, localeData, "longTimeFormat", dateTimePatterns.get(), 1);
490c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  setStringField(env, localeData, "mediumTimeFormat", dateTimePatterns.get(), 2);
491c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  setStringField(env, localeData, "shortTimeFormat", dateTimePatterns.get(), 3);
492c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  setStringField(env, localeData, "fullDateFormat", dateTimePatterns.get(), 4);
493c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  setStringField(env, localeData, "longDateFormat", dateTimePatterns.get(), 5);
494c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  setStringField(env, localeData, "mediumDateFormat", dateTimePatterns.get(), 6);
495c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  setStringField(env, localeData, "shortDateFormat", dateTimePatterns.get(), 7);
496c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  return true;
497c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes}
498c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
499a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughesstatic bool getYesterdayTodayAndTomorrow(JNIEnv* env, jobject localeData, const icu::Locale& locale, const char* locale_name) {
500c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  UErrorCode status = U_ZERO_ERROR;
501c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  ScopedResourceBundle root(ures_open(NULL, locale_name, &status));
5020ef9944d1968207ae8501aca5f904809320c520eElliott Hughes  ScopedResourceBundle fields(ures_getByKey(root.get(), "fields", NULL, &status));
5033879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes  ScopedResourceBundle day(ures_getByKey(fields.get(), "day", NULL, &status));
5043879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes  ScopedResourceBundle relative(ures_getByKey(day.get(), "relative", NULL, &status));
505c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  if (U_FAILURE(status)) {
506c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    return false;
507c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
5083879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes
509a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString yesterday(icu::ures_getUnicodeStringByKey(relative.get(), "-1", &status));
510a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString today(icu::ures_getUnicodeStringByKey(relative.get(), "0", &status));
511a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString tomorrow(icu::ures_getUnicodeStringByKey(relative.get(), "1", &status));
512c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  if (U_FAILURE(status)) {
513b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes    ALOGE("Error getting yesterday/today/tomorrow for %s: %s", locale_name, u_errorName(status));
514c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    return false;
515c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
5163879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes
5173879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes  // We title-case the strings so they have consistent capitalization (http://b/14493853).
518a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  std::unique_ptr<icu::BreakIterator> brk(icu::BreakIterator::createSentenceInstance(locale, status));
519c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  if (U_FAILURE(status)) {
520b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes    ALOGE("Error getting yesterday/today/tomorrow break iterator for %s: %s", locale_name, u_errorName(status));
521c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    return false;
522c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes  }
5233879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes  yesterday.toTitle(brk.get(), locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
5243879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes  today.toTitle(brk.get(), locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
5253879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes  tomorrow.toTitle(brk.get(), locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
5263879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes
5273879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes  setStringField(env, localeData, "yesterday", yesterday);
5283879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes  setStringField(env, localeData, "today", today);
5293879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes  setStringField(env, localeData, "tomorrow", tomorrow);
5303879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes  return true;
531c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes}
532c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
5335c0472fd7c53464e526bb833707551d85dbafec1Narayan Kamathstatic jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLanguageTag, jobject localeData) {
5345c0472fd7c53464e526bb833707551d85dbafec1Narayan Kamath    ScopedUtfChars languageTag(env, javaLanguageTag);
5355c0472fd7c53464e526bb833707551d85dbafec1Narayan Kamath    if (languageTag.c_str() == NULL) {
5365b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho        return JNI_FALSE;
5373be1277a4644a149c158f99febbab890fc7b708fclaireho    }
5385c0472fd7c53464e526bb833707551d85dbafec1Narayan Kamath    if (languageTag.size() >= ULOC_FULLNAME_CAPACITY) {
539c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes        return JNI_FALSE; // ICU has a fixed-length limit.
5405b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    }
5415b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho
5425c0472fd7c53464e526bb833707551d85dbafec1Narayan Kamath    ScopedIcuLocale icuLocale(env, javaLanguageTag);
543a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    if (!icuLocale.valid()) {
544a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes      return JNI_FALSE;
545a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    }
5463879b91e1baee17ecd51c653200ebdafc011020cElliott Hughes
547c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    // Get the DateTimePatterns.
548c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    UErrorCode status = U_ZERO_ERROR;
549c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    bool foundDateTimePatterns = false;
5505c0472fd7c53464e526bb833707551d85dbafec1Narayan Kamath    for (LocaleNameIterator it(icuLocale.locale().getBaseName(), status); it.HasNext(); it.Up()) {
551c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes      if (getDateTimePatterns(env, localeData, it.Get())) {
552c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes          foundDateTimePatterns = true;
553c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes          break;
554c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes      }
555c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    }
556c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    if (!foundDateTimePatterns) {
5575c0472fd7c53464e526bb833707551d85dbafec1Narayan Kamath        ALOGE("Couldn't find ICU DateTimePatterns for %s", languageTag.c_str());
55833aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes        return JNI_FALSE;
559adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
560adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
561c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    // Get the "Yesterday", "Today", and "Tomorrow" strings.
562c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    bool foundYesterdayTodayAndTomorrow = false;
5635c0472fd7c53464e526bb833707551d85dbafec1Narayan Kamath    for (LocaleNameIterator it(icuLocale.locale().getBaseName(), status); it.HasNext(); it.Up()) {
564a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes      if (getYesterdayTodayAndTomorrow(env, localeData, icuLocale.locale(), it.Get())) {
565c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes        foundYesterdayTodayAndTomorrow = true;
566c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes        break;
567c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes      }
568c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    }
569c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    if (!foundYesterdayTodayAndTomorrow) {
5705c0472fd7c53464e526bb833707551d85dbafec1Narayan Kamath      ALOGE("Couldn't find ICU yesterday/today/tomorrow for %s", languageTag.c_str());
571680b1e27caf10e3c41ec9f022054ab53d3a6bf7aElliott Hughes      return JNI_FALSE;
572c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    }
573c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
574b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes    // Get the narrow "AM" and "PM" strings.
575b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes    bool foundAmPmMarkersNarrow = false;
576b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes    for (LocaleNameIterator it(icuLocale.locale().getBaseName(), status); it.HasNext(); it.Up()) {
577b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes      if (getAmPmMarkersNarrow(env, localeData, it.Get())) {
578b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes        foundAmPmMarkersNarrow = true;
579b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes        break;
580b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes      }
581b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes    }
582b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes    if (!foundAmPmMarkersNarrow) {
583b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes      ALOGE("Couldn't find ICU AmPmMarkersNarrow for %s", languageTag.c_str());
584b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes      return JNI_FALSE;
585b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes    }
586b799123bc221b926a9f189107f2a3619a4da8874Elliott Hughes
5875b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    status = U_ZERO_ERROR;
588a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    std::unique_ptr<icu::Calendar> cal(icu::Calendar::createInstance(icuLocale.locale(), status));
58933aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes    if (U_FAILURE(status)) {
59033aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes        return JNI_FALSE;
591adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
592c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
5935b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setIntegerField(env, localeData, "firstDayOfWeek", cal->getFirstDayOfWeek());
5945b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setIntegerField(env, localeData, "minimalDaysInFirstWeek", cal->getMinimalDaysInFirstWeek());
595adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
596c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    // Get DateFormatSymbols.
5975b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    status = U_ZERO_ERROR;
598a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    icu::DateFormatSymbols dateFormatSym(icuLocale.locale(), status);
59933aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes    if (U_FAILURE(status)) {
60033aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes        return JNI_FALSE;
601adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
602c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes
603c4e0797a4dd028d23e788da15c3055f83f6f37d5Elliott Hughes    // Get AM/PM and BC/AD.
6045b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    int32_t count = 0;
605a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* amPmStrs = dateFormatSym.getAmPmStrings(count);
6065b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringArrayField(env, localeData, "amPm", amPmStrs, count);
607a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* erasStrs = dateFormatSym.getEras(count);
6085b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringArrayField(env, localeData, "eras", erasStrs, count);
6095b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho
610a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* longMonthNames =
611a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes       dateFormatSym.getMonths(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::WIDE);
6125b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringArrayField(env, localeData, "longMonthNames", longMonthNames, count);
613a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* shortMonthNames =
614a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes        dateFormatSym.getMonths(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::ABBREVIATED);
6155b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringArrayField(env, localeData, "shortMonthNames", shortMonthNames, count);
616a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* tinyMonthNames =
617a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes        dateFormatSym.getMonths(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::NARROW);
618ad66a888b2e48b1a185de1b3c73fd01383a1fd04Elliott Hughes    setStringArrayField(env, localeData, "tinyMonthNames", tinyMonthNames, count);
619a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* longWeekdayNames =
620a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes        dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::WIDE);
6215b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringArrayField(env, localeData, "longWeekdayNames", longWeekdayNames, count);
622a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* shortWeekdayNames =
623a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes        dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::ABBREVIATED);
6245b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringArrayField(env, localeData, "shortWeekdayNames", shortWeekdayNames, count);
625a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* tinyWeekdayNames =
626a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes        dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::FORMAT, icu::DateFormatSymbols::NARROW);
627ad66a888b2e48b1a185de1b3c73fd01383a1fd04Elliott Hughes    setStringArrayField(env, localeData, "tinyWeekdayNames", tinyWeekdayNames, count);
6285b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho
629a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* longStandAloneMonthNames =
630a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes        dateFormatSym.getMonths(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::WIDE);
6315b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringArrayField(env, localeData, "longStandAloneMonthNames", longStandAloneMonthNames, count);
632a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* shortStandAloneMonthNames =
633a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes        dateFormatSym.getMonths(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::ABBREVIATED);
6345b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringArrayField(env, localeData, "shortStandAloneMonthNames", shortStandAloneMonthNames, count);
635a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* tinyStandAloneMonthNames =
636a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes        dateFormatSym.getMonths(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::NARROW);
637ad66a888b2e48b1a185de1b3c73fd01383a1fd04Elliott Hughes    setStringArrayField(env, localeData, "tinyStandAloneMonthNames", tinyStandAloneMonthNames, count);
638a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* longStandAloneWeekdayNames =
639a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes        dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::WIDE);
6405b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringArrayField(env, localeData, "longStandAloneWeekdayNames", longStandAloneWeekdayNames, count);
641a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* shortStandAloneWeekdayNames =
642a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes        dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::ABBREVIATED);
6435b7b7fe6a817fdf058eefd9a716cc58a3283eb05claireho    setStringArrayField(env, localeData, "shortStandAloneWeekdayNames", shortStandAloneWeekdayNames, count);
644a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes    const icu::UnicodeString* tinyStandAloneWeekdayNames =
645a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes        dateFormatSym.getWeekdays(count, icu::DateFormatSymbols::STANDALONE, icu::DateFormatSymbols::NARROW);
646ad66a888b2e48b1a185de1b3c73fd01383a1fd04Elliott Hughes    setStringArrayField(env, localeData, "tinyStandAloneWeekdayNames", tinyStandAloneWeekdayNames, count);
647adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
64833aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes    status = U_ZERO_ERROR;
649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6503be1277a4644a149c158f99febbab890fc7b708fclaireho    // For numberPatterns and symbols.
651a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    setNumberPatterns(env, localeData, icuLocale.locale());
652a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    setDecimalFormatSymbolsData(env, localeData, icuLocale.locale());
653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
6545c0472fd7c53464e526bb833707551d85dbafec1Narayan Kamath    jstring countryCode = env->NewStringUTF(icuLocale.locale().getCountry());
65552b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes    jstring internationalCurrencySymbol = ICU_getCurrencyCode(env, NULL, countryCode);
656e2377cdd707b830d07a5708216834f7ac76ee3e1Elliott Hughes    env->DeleteLocalRef(countryCode);
657e2377cdd707b830d07a5708216834f7ac76ee3e1Elliott Hughes    countryCode = NULL;
658e2377cdd707b830d07a5708216834f7ac76ee3e1Elliott Hughes
65933aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes    jstring currencySymbol = NULL;
66033aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes    if (internationalCurrencySymbol != NULL) {
6615c0472fd7c53464e526bb833707551d85dbafec1Narayan Kamath        currencySymbol = ICU_getCurrencySymbol(env, NULL, javaLanguageTag, internationalCurrencySymbol);
662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    } else {
66333aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes        internationalCurrencySymbol = env->NewStringUTF("XXX");
664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
66533aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes    if (currencySymbol == NULL) {
66633aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes        // This is the UTF-8 encoding of U+00A4 (CURRENCY SIGN).
667ad884a7b8cae7a1c3d973c8032d4f78ef7c96b80Hao Feng        currencySymbol = env->NewStringUTF("\xc2\xa4");
668adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
66933aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes    setStringField(env, localeData, "currencySymbol", currencySymbol);
67033aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes    setStringField(env, localeData, "internationalCurrencySymbol", internationalCurrencySymbol);
671adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
67233aa6eb602478e7f51ac16f30c88db3566022886Elliott Hughes    return JNI_TRUE;
673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
675a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic jstring ICU_toLowerCase(JNIEnv* env, jclass, jstring javaString, jstring javaLanguageTag) {
6763aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  ScopedJavaUnicodeString scopedString(env, javaString);
6773aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  if (!scopedString.valid()) {
6783aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes    return NULL;
6793aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  }
680a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuLocale(env, javaLanguageTag);
681a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuLocale.valid()) {
682a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
683a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
684a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString& s(scopedString.unicodeString());
685a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString original(s);
686a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  s.toLower(icuLocale.locale());
6873aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  return s == original ? javaString : env->NewString(s.getBuffer(), s.length());
688dbbdffce5ac97a0e93ef495adaacca3660b9ab21Elliott Hughes}
689dbbdffce5ac97a0e93ef495adaacca3660b9ab21Elliott Hughes
690a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic jstring ICU_toUpperCase(JNIEnv* env, jclass, jstring javaString, jstring javaLanguageTag) {
6913aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  ScopedJavaUnicodeString scopedString(env, javaString);
6923aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  if (!scopedString.valid()) {
6933aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes    return NULL;
6943aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  }
695a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuLocale(env, javaLanguageTag);
696a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuLocale.valid()) {
697a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
698a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
699a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString& s(scopedString.unicodeString());
700a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString original(s);
701a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  s.toUpper(icuLocale.locale());
7023aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  return s == original ? javaString : env->NewString(s.getBuffer(), s.length());
703dbbdffce5ac97a0e93ef495adaacca3660b9ab21Elliott Hughes}
704dbbdffce5ac97a0e93ef495adaacca3660b9ab21Elliott Hughes
705e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughesstatic jstring versionString(JNIEnv* env, const UVersionInfo& version) {
706e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes    char versionString[U_MAX_VERSION_STRING_LENGTH];
707e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes    u_versionToString(const_cast<UVersionInfo&>(version), &versionString[0]);
708e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes    return env->NewStringUTF(versionString);
709e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes}
710e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes
71115d82808bab24f399a034d086f587d5fab32522eElliott Hughesstatic jstring ICU_getCldrVersion(JNIEnv* env, jclass) {
71215d82808bab24f399a034d086f587d5fab32522eElliott Hughes  UErrorCode status = U_ZERO_ERROR;
71315d82808bab24f399a034d086f587d5fab32522eElliott Hughes  UVersionInfo cldrVersion;
71415d82808bab24f399a034d086f587d5fab32522eElliott Hughes  ulocdata_getCLDRVersion(cldrVersion, &status);
71515d82808bab24f399a034d086f587d5fab32522eElliott Hughes  return versionString(env, cldrVersion);
71615d82808bab24f399a034d086f587d5fab32522eElliott Hughes}
71715d82808bab24f399a034d086f587d5fab32522eElliott Hughes
718e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughesstatic jstring ICU_getIcuVersion(JNIEnv* env, jclass) {
719e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes    UVersionInfo icuVersion;
720e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes    u_getVersion(icuVersion);
721e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes    return versionString(env, icuVersion);
722e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes}
723e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes
724e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughesstatic jstring ICU_getUnicodeVersion(JNIEnv* env, jclass) {
725e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes    UVersionInfo unicodeVersion;
726e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes    u_getUnicodeVersion(unicodeVersion);
727e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes    return versionString(env, unicodeVersion);
728e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes}
729e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes
730cf14cc4ee0de8c3e4f9a1dab7a5a91d09264dee9Neil Fullerstatic jstring ICU_getTZDataVersion(JNIEnv* env, jclass) {
731cf14cc4ee0de8c3e4f9a1dab7a5a91d09264dee9Neil Fuller  UErrorCode status = U_ZERO_ERROR;
732cf14cc4ee0de8c3e4f9a1dab7a5a91d09264dee9Neil Fuller  const char* version = icu::TimeZone::getTZDataVersion(status);
733cf14cc4ee0de8c3e4f9a1dab7a5a91d09264dee9Neil Fuller  if (maybeThrowIcuException(env, "icu::TimeZone::getTZDataVersion", status)) {
734cf14cc4ee0de8c3e4f9a1dab7a5a91d09264dee9Neil Fuller    return NULL;
735cf14cc4ee0de8c3e4f9a1dab7a5a91d09264dee9Neil Fuller  }
736cf14cc4ee0de8c3e4f9a1dab7a5a91d09264dee9Neil Fuller  return env->NewStringUTF(version);
737cf14cc4ee0de8c3e4f9a1dab7a5a91d09264dee9Neil Fuller}
738cf14cc4ee0de8c3e4f9a1dab7a5a91d09264dee9Neil Fuller
73952b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughesstatic jobject ICU_getAvailableCurrencyCodes(JNIEnv* env, jclass) {
740783a57a7ece339bc246925e328bc82b50cae427aElliott Hughes  UErrorCode status = U_ZERO_ERROR;
741a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UStringEnumeration e(ucurr_openISOCurrencies(UCURR_COMMON|UCURR_NON_DEPRECATED, &status));
742783a57a7ece339bc246925e328bc82b50cae427aElliott Hughes  return fromStringEnumeration(env, status, "ucurr_openISOCurrencies", &e);
74352b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes}
74452b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes
745a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic jstring ICU_getBestDateTimePatternNative(JNIEnv* env, jclass, jstring javaSkeleton, jstring javaLanguageTag) {
746a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuLocale(env, javaLanguageTag);
747a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuLocale.valid()) {
748a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return NULL;
749a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
750a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes
751cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes  UErrorCode status = U_ZERO_ERROR;
752a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  std::unique_ptr<icu::DateTimePatternGenerator> generator(icu::DateTimePatternGenerator::createInstance(icuLocale.locale(), status));
753cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes  if (maybeThrowIcuException(env, "DateTimePatternGenerator::createInstance", status)) {
754cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes    return NULL;
755cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes  }
756cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes
757480537d9d51add98bffe6d9a9ef3b1022b959336Elliott Hughes  ScopedJavaUnicodeString skeletonHolder(env, javaSkeleton);
758480537d9d51add98bffe6d9a9ef3b1022b959336Elliott Hughes  if (!skeletonHolder.valid()) {
7593aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes    return NULL;
7603aac4ddc4d17c07fa8b4908069d23d5401a77993Elliott Hughes  }
761a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::UnicodeString result(generator->getBestPattern(skeletonHolder.unicodeString(), status));
762cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes  if (maybeThrowIcuException(env, "DateTimePatternGenerator::getBestPattern", status)) {
763cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes    return NULL;
764cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes  }
765cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes
766cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes  return env->NewString(result.getBuffer(), result.length());
767cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes}
768cb1b9026b8aa993785c4d54f686905522b7959b9Elliott Hughes
769a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughesstatic void ICU_setDefaultLocale(JNIEnv* env, jclass, jstring javaLanguageTag) {
770a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  ScopedIcuLocale icuLocale(env, javaLanguageTag);
771a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  if (!icuLocale.valid()) {
772a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes    return;
773a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  }
774de0eb683370d789e7bb25673b350b8dbf2ba5d69Narayan Kamath
775a94266074c7b82720fd2cecfb37ab8da85f1b296Elliott Hughes  UErrorCode status = U_ZERO_ERROR;
776a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  icu::Locale::setDefault(icuLocale.locale(), status);
777de0eb683370d789e7bb25673b350b8dbf2ba5d69Narayan Kamath  maybeThrowIcuException(env, "Locale::setDefault", status);
778de0eb683370d789e7bb25673b350b8dbf2ba5d69Narayan Kamath}
779de0eb683370d789e7bb25673b350b8dbf2ba5d69Narayan Kamath
780de0eb683370d789e7bb25673b350b8dbf2ba5d69Narayan Kamathstatic jstring ICU_getDefaultLocale(JNIEnv* env, jclass) {
781a04b5c3d39232c7616591883ee2124520e3ab622Elliott Hughes  return env->NewStringUTF(icu::Locale::getDefault().getName());
782de0eb683370d789e7bb25673b350b8dbf2ba5d69Narayan Kamath}
783de0eb683370d789e7bb25673b350b8dbf2ba5d69Narayan Kamath
784adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectstatic JNINativeMethod gMethods[] = {
7850452e9adf6fb133b6d3e59ebae2135aa90ad0d5eFabrice Di Meglio    NATIVE_METHOD(ICU, addLikelySubtags, "(Ljava/lang/String;)Ljava/lang/String;"),
786e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, getAvailableBreakIteratorLocalesNative, "()[Ljava/lang/String;"),
787e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, getAvailableCalendarLocalesNative, "()[Ljava/lang/String;"),
788e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, getAvailableCollatorLocalesNative, "()[Ljava/lang/String;"),
78952b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes    NATIVE_METHOD(ICU, getAvailableCurrencyCodes, "()[Ljava/lang/String;"),
790e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, getAvailableDateFormatLocalesNative, "()[Ljava/lang/String;"),
791e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, getAvailableLocalesNative, "()[Ljava/lang/String;"),
792e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, getAvailableNumberFormatLocalesNative, "()[Ljava/lang/String;"),
7930fd776f4dbf7c1940c080003f0c7a02d35374ab9Elliott Hughes    NATIVE_METHOD(ICU, getBestDateTimePatternNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
79415d82808bab24f399a034d086f587d5fab32522eElliott Hughes    NATIVE_METHOD(ICU, getCldrVersion, "()Ljava/lang/String;"),
79552b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes    NATIVE_METHOD(ICU, getCurrencyCode, "(Ljava/lang/String;)Ljava/lang/String;"),
79652b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes    NATIVE_METHOD(ICU, getCurrencyDisplayName, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
79752b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes    NATIVE_METHOD(ICU, getCurrencyFractionDigits, "(Ljava/lang/String;)I"),
798d627bd4525e41b0503f94c2887c3e01618c73105Neil Fuller    NATIVE_METHOD(ICU, getCurrencyNumericCode, "(Ljava/lang/String;)I"),
79952b310afcffe8b6aed6fa0c1e9e8b0ade6f0a672Elliott Hughes    NATIVE_METHOD(ICU, getCurrencySymbol, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
800de0eb683370d789e7bb25673b350b8dbf2ba5d69Narayan Kamath    NATIVE_METHOD(ICU, getDefaultLocale, "()Ljava/lang/String;"),
801e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, getDisplayCountryNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
802e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, getDisplayLanguageNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
803c5b1eb191102a20bc0626aea955aba417e337fbcNarayan Kamath    NATIVE_METHOD(ICU, getDisplayScriptNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
804e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, getDisplayVariantNative, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
805ca6c2dfd21fef61f179223fb710db791802068d5Narayan Kamath    NATIVE_METHOD(ICU, getISO3Country, "(Ljava/lang/String;)Ljava/lang/String;"),
806ca6c2dfd21fef61f179223fb710db791802068d5Narayan Kamath    NATIVE_METHOD(ICU, getISO3Language, "(Ljava/lang/String;)Ljava/lang/String;"),
807e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, getISOCountriesNative, "()[Ljava/lang/String;"),
808e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, getISOLanguagesNative, "()[Ljava/lang/String;"),
809e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes    NATIVE_METHOD(ICU, getIcuVersion, "()Ljava/lang/String;"),
8104c94a6128d1fcfaa75539b36c9f50d0c75df6144Fabrice Di Meglio    NATIVE_METHOD(ICU, getScript, "(Ljava/lang/String;)Ljava/lang/String;"),
811cf14cc4ee0de8c3e4f9a1dab7a5a91d09264dee9Neil Fuller    NATIVE_METHOD(ICU, getTZDataVersion, "()Ljava/lang/String;"),
812e0e567287e4392bebc5f5826b8ef3b1bd8ca166eElliott Hughes    NATIVE_METHOD(ICU, getUnicodeVersion, "()Ljava/lang/String;"),
8130fd776f4dbf7c1940c080003f0c7a02d35374ab9Elliott Hughes    NATIVE_METHOD(ICU, initLocaleDataNative, "(Ljava/lang/String;Llibcore/icu/LocaleData;)Z"),
814de0eb683370d789e7bb25673b350b8dbf2ba5d69Narayan Kamath    NATIVE_METHOD(ICU, setDefaultLocale, "(Ljava/lang/String;)V"),
815e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, toLowerCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
816e22935d3c7040c22b48d53bd18878844f381287cElliott Hughes    NATIVE_METHOD(ICU, toUpperCase, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"),
817adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project};
818566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes
819317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller#define FAIL_WITH_STRERROR(s) \
820317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    ALOGE("Couldn't " s " '%s': %s", path.c_str(), strerror(errno)); \
821317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    return FALSE;
822317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller
823317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller#define MAYBE_FAIL_WITH_ICU_ERROR(s) \
824317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    if (status != U_ZERO_ERROR) {\
825317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        ALOGE("Couldn't initialize ICU (" s "): %s (%s)", u_errorName(status), path.c_str()); \
826317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        return FALSE; \
827317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    }
828317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller
829317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fullerstatic bool mapIcuData(const std::string& path) {
830566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    // Open the file and get its length.
831566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    ScopedFd fd(open(path.c_str(), O_RDONLY));
832566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    if (fd.get() == -1) {
8339f557fae5a751ba8de8c0bc9ba689ab23ad405f6Elliott Hughes        FAIL_WITH_STRERROR("open");
834566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    }
835566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    struct stat sb;
836566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    if (fstat(fd.get(), &sb) == -1) {
8379f557fae5a751ba8de8c0bc9ba689ab23ad405f6Elliott Hughes        FAIL_WITH_STRERROR("stat");
838566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    }
839566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes
840566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    // Map it.
841566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    void* data = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd.get(), 0);
842566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    if (data == MAP_FAILED) {
8439f557fae5a751ba8de8c0bc9ba689ab23ad405f6Elliott Hughes        FAIL_WITH_STRERROR("mmap");
844566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    }
845566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes
846566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    // Tell the kernel that accesses are likely to be random rather than sequential.
847566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    if (madvise(data, sb.st_size, MADV_RANDOM) == -1) {
8489f557fae5a751ba8de8c0bc9ba689ab23ad405f6Elliott Hughes        FAIL_WITH_STRERROR("madvise(MADV_RANDOM)");
849566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    }
850566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes
851566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    UErrorCode status = U_ZERO_ERROR;
852317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller
853317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    // Tell ICU to use our memory-mapped data.
854566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    udata_setCommonData(data, &status);
8559f557fae5a751ba8de8c0bc9ba689ab23ad405f6Elliott Hughes    MAYBE_FAIL_WITH_ICU_ERROR("udata_setCommonData");
856317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller
857317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    return TRUE;
858317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller}
859317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller
860317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fullervoid register_libcore_icu_ICU(JNIEnv* env) {
861317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    // Check the timezone override file exists. If it does, map it first so we use it in preference
862317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    // to the one that shipped with the device.
863317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    const char* dataPathPrefix = getenv("ANDROID_DATA");
864317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    if (dataPathPrefix == NULL) {
865317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        ALOGE("ANDROID_DATA environment variable not set"); \
866317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        abort();
867317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    }
868317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller
869317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    UErrorCode status = U_ZERO_ERROR;
870566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    // Tell ICU it can *only* use our memory-mapped data.
871566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes    udata_setFileAccess(UDATA_NO_FILES, &status);
872317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    if (status != U_ZERO_ERROR) {
873317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        ALOGE("Couldn't initialize ICU (s_setFileAccess): %s", u_errorName(status));
874317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        abort();
875317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    }
876317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller
877317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    // Map in optional TZ data files.
878317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    std::string dataPath;
879317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    dataPath = dataPathPrefix;
880317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    dataPath += "/misc/zoneinfo/current/icu/icu_tzdata.dat";
881317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller
882317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    struct stat sb;
883317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    if (stat(dataPath.c_str(), &sb) == 0) {
884317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        ALOGD("Timezone override file found: %s", dataPath.c_str());
885317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        if (!mapIcuData(dataPath)) {
886317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller            ALOGW("TZ override file %s exists but could not be loaded. Skipping.", dataPath.c_str());
887317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        }
888317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    } else {
889317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        ALOGD("No timezone override file found: %s", dataPath.c_str());
890317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    }
891317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller
892317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    // Use the ICU data files that shipped with the device for everything else.
893d2a3075106f700f229750c228de989b789b7dacdNeil Fuller    const char* systemPathPrefix = getenv("ANDROID_ROOT");
894d2a3075106f700f229750c228de989b789b7dacdNeil Fuller    if (systemPathPrefix == NULL) {
895d2a3075106f700f229750c228de989b789b7dacdNeil Fuller        ALOGE("ANDROID_ROOT environment variable not set"); \
896d2a3075106f700f229750c228de989b789b7dacdNeil Fuller        abort();
897d2a3075106f700f229750c228de989b789b7dacdNeil Fuller    }
898317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    std::string systemPath;
899d2a3075106f700f229750c228de989b789b7dacdNeil Fuller    systemPath = systemPathPrefix;
900d2a3075106f700f229750c228de989b789b7dacdNeil Fuller    systemPath += "/usr/icu/";
901317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    systemPath += U_ICUDATA_NAME;
902317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    systemPath += ".dat";
903317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller
904317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    if (!mapIcuData(systemPath)) {
905317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        abort();
906317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    }
907566bbb1d5a0ffadfc07fa58176587d4bd0d0be13Elliott Hughes
908972d9be2dbbf6d467728b8ad44625f6574068bf8Elliott Hughes    // Failures to find the ICU data tend to be somewhat obscure because ICU loads its data on first
909972d9be2dbbf6d467728b8ad44625f6574068bf8Elliott Hughes    // use, which can be anywhere. Force initialization up front so we can report a nice clear error
910972d9be2dbbf6d467728b8ad44625f6574068bf8Elliott Hughes    // and bail.
911972d9be2dbbf6d467728b8ad44625f6574068bf8Elliott Hughes    u_init(&status);
912317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    if (status != U_ZERO_ERROR) {\
913317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        ALOGE("Couldn't initialize ICU (u_init): %s", u_errorName(status));
914317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller        abort();
915317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller    }
916317d6e12782e069e4fde06ed0f9a976a7c49f580Neil Fuller
9177cd6760f7045d771faae8080a8c6150bf678f679Elliott Hughes    jniRegisterNativeMethods(env, "libcore/icu/ICU", gMethods, NELEM(gMethods));
918adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
919