Speed up the way we access ICU's locale data.
This patch makes creating a new NumberFormat or new SimpleDateFormat 2x faster.
Basically, the ResourceBundle mechanism is really expensive in several ways:
1. The two-level caching is unnecessary for locale data, and expensive because
it burns through a lot of temporary objects.
2. The PrivilegedAction stuff is unnecessary and expensive because it too burns
quite a few temporary objects (including an ArrayList for each call; should
we consider removing support for SecurityManager so we can remove this cruft
from our code?).
3. The caching in most cases doesn't cache anything useful; the ResourceBundles
simply forward all questions straight to native code anyway, all we're
caching is an unnecessary forwarding object (in a cache where lookups cost
more than just creating a new unnecessary forwarding object would cost).
I've left CurrencyResourceBundle on the slow (ResourceBundle.getBundle) path
because I'm not yet sure how much of that path's semantics it relies on.
I still return LocaleResourceBundle instances (albeit via a much faster path)
but we should fix that. The native code returns an array which ResourceBundle
stuffs into a Hashtable and the calling code accesses via hash table lookups.
This despite the fact that the keys are a small fixed set known in advance.
We could make the native layer and the calling layer simpler and faster by
using a "struct", and doing so would make the middle layer go away completely.
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java
index 533c674..0ceb287 100644
--- a/libcore/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java
@@ -37,13 +37,7 @@
public DecimalFormatSymbols(Locale locale) {
this.loc = locale;
- ResourceBundle bundle = AccessController.
- doPrivileged(new PrivilegedAction<ResourceBundle>() {
- public ResourceBundle run() {
- return ResourceBundle.getBundle(
- "org.apache.harmony.luni.internal.locale.Locale", loc); //$NON-NLS-1$
- }
- });
+ ResourceBundle bundle = com.ibm.icu4jni.util.Resources.getLocaleInstance(locale);
String pattern = bundle.getString("Number");
this.addr = NativeDecimalFormat.openDecimalFormatImpl(
locale.toString(), pattern);
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java b/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
index 7eeae7d..41bf3e3 100644
--- a/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/util/Resources.java
@@ -16,34 +16,25 @@
package com.ibm.icu4jni.util;
+import java.util.Arrays;
import java.util.Enumeration;
import java.util.ListResourceBundle;
+import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.TimeZone;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;
/**
- * Helper class that delivers ResourceBundle instances expected by Harmony, but
- * with the data taken from ICU's database. This approach has a couple of
- * advantages:
- * <ol>
- * <li> We have less classes in the overall system, since we use different
- * instances for different ResourceBundles.
- * <li> We don't have these classes that consists of monstrous static arrays
- * with anymore.
- * <li> We have control over which values we load at which time or even cache
- * for later use.
- * <li> There is only one central place left in the system where I18N data needs
- * to be configured, namely ICU.
- * </ol>
- * Since we're mimicking the original Harmony ResourceBundle structures, most of
- * the Harmony code can stay the same. We basically just need to change the
- * ResourceBundle instantiation. Only the special case of the Locale bundles
- * needs some more tweaking, since we don't want to keep several hundred
- * timezone names in memory.
+ * Makes ICU data accessible to Java.
+ *
+ * TODO: finish removing the expensive ResourceBundle nonsense and rename this class.
*/
public class Resources {
+ // A cache for the locale-specific data.
+ private static final ConcurrentHashMap<String, LocaleResourceBundle> localeInstanceCache =
+ new ConcurrentHashMap<String, LocaleResourceBundle>();
/**
* Cache for ISO language names.
@@ -66,41 +57,52 @@
private static String[] availableTimezones = null;
/**
- * Creates ResourceBundle instance and fills it with ICU data.
- *
- * @param bundleName The name of the requested Harmony resource bundle,
- * excluding the package name.
- * @param locale The locale to use for the resources. A null value denotes
- * the default locale as configured in Java.
- * @return The new ResourceBundle, or null, if no ResourceBundle was
- * created.
+ * Returns a LocaleResourceBundle corresponding to the given locale.
+ * TODO: return something that allows cheap static field lookup rather than
+ * expensive chained hash table lookup.
*/
+ public static ResourceBundle getLocaleInstance(Locale locale) {
+ if (locale == null) {
+ locale = Locale.getDefault();
+ }
+ String localeName = locale.toString();
+ LocaleResourceBundle bundle = localeInstanceCache.get(localeName);
+ if (bundle != null) {
+ return bundle;
+ }
+ bundle = makeLocaleResourceBundle(locale);
+ localeInstanceCache.put(localeName, bundle);
+ boolean absent = (localeInstanceCache.putIfAbsent(localeName, bundle) == null);
+ return absent ? bundle : localeInstanceCache.get(localeName);
+ }
+
+ private static LocaleResourceBundle makeLocaleResourceBundle(Locale locale) {
+ LocaleResourceBundle result = new LocaleResourceBundle(locale);
+
+ // Anything not found in this ResourceBundle should be passed on to
+ // a parent ResourceBundle corresponding to the next-most-specific locale.
+ String country = locale.getCountry();
+ String language = locale.getLanguage();
+ if (locale.getVariant().length() > 0) {
+ result.setParent(getLocaleInstance(new Locale(language, country, "")));
+ } else if (country.length() > 0) {
+ result.setParent(getLocaleInstance(new Locale(language, "", "")));
+ } else if (language.length() > 0) {
+ result.setParent(getLocaleInstance(new Locale("", "", "")));
+ }
+
+ return result;
+ }
+
+ // TODO: fix remaining caller and remove this.
public static ResourceBundle getInstance(String bundleName, String locale) {
if (locale == null) {
- locale = java.util.Locale.getDefault().toString();
+ locale = Locale.getDefault().toString();
}
-
- if (bundleName.startsWith("Locale")) {
- return new Locale(locale);
- } else if (bundleName.startsWith("Country")) {
- return new Country(locale);
- } else if (bundleName.startsWith("Currency")) {
- return new Currency(locale);
- } else if (bundleName.startsWith("Language")) {
- return new Language(locale);
- } else if (bundleName.startsWith("Variant")) {
- return new Variant(locale);
- } else if (bundleName.equals("ISO3Countries")) {
- return new ISO3Countries();
- } else if (bundleName.equals("ISO3Languages")) {
- return new ISO3Languages();
- } else if (bundleName.equals("ISO4CurrenciesToDigits")) {
- return new ISO4CurrenciesToDigits();
- } else if (bundleName.equals("ISO4Currencies")) {
- return new ISO4Currencies();
+ if (bundleName.startsWith("Currency")) {
+ return new CurrencyResourceBundle(locale);
}
-
- return null;
+ throw new AssertionError("bundle="+bundleName+" locale="+locale);
}
/**
@@ -174,13 +176,6 @@
}
/**
- * Gets the name of the default locale.
- */
- private static String getDefaultLocaleName() {
- return java.util.Locale.getDefault().toString();
- }
-
- /**
* Initialization holder for default time zone names. This class will
* be preloaded by the zygote to share the time and space costs of setting
* up the list of time zone names, so although it looks like the lazy
@@ -190,7 +185,7 @@
/**
* Name of default locale at the time this class was initialized.
*/
- private static final String locale = getDefaultLocaleName();
+ private static final String locale = Locale.getDefault().toString();
/**
* Names of time zones for the default locale.
@@ -260,7 +255,7 @@
* the TomeZone class.
*/
public static String[][] getDisplayTimeZones(String locale) {
- String defaultLocale = getDefaultLocaleName();
+ String defaultLocale = Locale.getDefault().toString();
if (locale == null) {
locale = defaultLocale;
}
@@ -286,135 +281,16 @@
// --- Specialized ResourceBundle subclasses ------------------------------
/**
- * Internal ResourceBundle mimicking the Harmony "ISO3Countries" bundle.
- * Keys are the two-letter ISO country codes. Values are the three-letter
- * ISO country abbreviations. An example entry is "US"->"USA".
- */
- private static final class ISO3Countries extends ResourceBundle {
-
- @Override
- public Enumeration<String> getKeys() {
- // Won't get used
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected Object handleGetObject(String key) {
- return getISO3CountryNative(key);
- }
-
- }
-
- /**
- * Internal ResourceBundle mimicking the Harmony "ISO3Languages" bundle.
- * Keys are the two-letter ISO language codes. Values are the three-letter
- * ISO language abbreviations. An example entry is "EN"->"ENG".
- */
- private static final class ISO3Languages extends ResourceBundle {
-
- @Override
- public Enumeration<String> getKeys() {
- // Won't get used
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected Object handleGetObject(String key) {
- return getISO3LanguageNative(key);
- }
-
- }
-
- /**
- * Internal ResourceBundle mimicking the Harmony "ISO4Currencies" bundle.
- * Keys are the two-letter ISO language codes. Values are the three-letter
- * ISO currency abbreviations. An example entry is "US"->"USD".
- */
- private static final class ISO4Currencies extends ResourceBundle {
-
- @Override
- public Enumeration<String> getKeys() {
- // Won't get used
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected Object handleGetObject(String key) {
- return getCurrencyCodeNative(key);
- }
-
- }
-
- /**
- * Internal ResourceBundle mimicking the Harmony "ISO4CurrenciesToDigits"
- * bundle. Keys are the three-letter ISO currency codes. Values are strings
- * containing the number of fraction digits to use for the currency. An
- * example entry is "USD"->"2".
- */
- private static final class ISO4CurrenciesToDigits extends ResourceBundle {
-
- @Override
- public Enumeration<String> getKeys() {
- // Won't get used
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected Object handleGetObject(String key) {
- // In some places the triple-x code is used as the fall back
- // currency. The harmony package returned -1 for this requested
- // currency.
- if ("XXX".equals(key)) {
- return "-1";
- }
- int res = getFractionDigitsNative(key);
- if (res < 0) {
- throw new MissingResourceException("couldn't find resource.",
- ISO4CurrenciesToDigits.class.getName(), key);
- }
- return Integer.toString(res);
- }
-
- }
-
- /**
- * Internal ResourceBundle mimicking the Harmony "Country_*" bundles. Keys
- * are the two-letter ISO country codes. Values are the printable country
- * names in terms of the specified locale. An example entry is "US"->"United
- * States".
- */
- private static final class Country extends ResourceBundle {
- private String locale;
-
- public Country(String locale) {
- super();
- this.locale = locale;
- }
-
- @Override
- public Enumeration<String> getKeys() {
- // Won't get used
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected Object handleGetObject(String key) {
- return getDisplayCountryNative(key, locale);
- }
-
- }
-
- /**
* Internal ResourceBundle mimicking the Harmony "Currency_*" bundles. Keys
* are the three-letter ISO currency codes. Values are the printable
* currency names in terms of the specified locale. An example entry is
* "USD"->"$" (for inside the US) and "USD->"US$" (for outside the US).
*/
- private static final class Currency extends ResourceBundle {
+ private static final class CurrencyResourceBundle extends ResourceBundle {
private String locale;
- public Currency(String locale) {
+ public CurrencyResourceBundle(String locale) {
super();
this.locale = locale;
}
@@ -433,105 +309,64 @@
}
/**
- * Internal ResourceBundle mimicking the Harmony "Language_*" bundles. Keys
- * are the two-letter ISO language codes. Values are the printable language
- * names in terms of the specified locale. An example entry is
- * "en"->"English".
- */
- private static final class Language extends ResourceBundle {
- private String locale;
-
- public Language(String locale) {
- super();
- this.locale = locale;
- }
-
- @Override
- public Enumeration<String> getKeys() {
- // Won't get used
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected Object handleGetObject(String key) {
- return getDisplayLanguageNative(key, locale);
- }
-
- }
-
- /**
- * Internal ResourceBundle mimicking the Harmony "Variant_*" bundles. Keys
- * are a fixed set of variants codes known to Harmony. Values are the
- * printable variant names in terms of the specified locale. An example
- * entry is "EURO"->"Euro".
- */
- private static final class Variant extends ResourceBundle {
-
- private String locale;
-
- public Variant(String locale) {
- super();
- this.locale = locale;
- }
-
- @Override
- public Enumeration<String> getKeys() {
- // Won't get used
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected Object handleGetObject(String key) {
- return getDisplayVariantNative(key, locale);
- }
-
- }
-
- /**
- * Internal ResourceBundle mimicking the Harmony "Locale_*" bundles. This is
- * clearly the most complex case, because the content covers a wide range of
+ * Internal ResourceBundle mimicking the Harmony "Locale_*" bundles.
+ * The content covers a wide range of
* data items, with values even being arrays in some cases. Note we are
* cheating with the "timezones" entry, since we normally don't want to
* waste our precious RAM on several thousand of these Strings.
*/
- private static final class Locale extends ListResourceBundle {
-
- private String locale;
-
- public Locale(String locale) {
- super();
+ private static final class LocaleResourceBundle extends ListResourceBundle {
+ private final Locale locale;
+
+ public LocaleResourceBundle(Locale locale) {
this.locale = locale;
}
+
+ // We can't set the superclass' locale field, so we need our own, and our own accessor.
+ @Override
+ public Locale getLocale() {
+ return locale;
+ }
@Override
protected Object[][] getContents() {
- return getContentImpl(locale, false);
+ return getContentImpl(locale.toString());
}
+ // Increase accessibility of this method so we can call it.
+ @Override
+ public void setParent(ResourceBundle bundle) {
+ this.parent = bundle;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder result = new StringBuilder();
+ result.append("LocaleResourceBundle[locale=");
+ result.append(getLocale());
+ result.append(",contents=");
+ result.append(Arrays.deepToString(getContents()));
+ return result.toString();
+ }
}
// --- Native methods accessing ICU's database ----------------------------
- private static native int getFractionDigitsNative(String currencyCode);
+ public static native String getDisplayCountryNative(String countryCode, String locale);
+ public static native String getDisplayLanguageNative(String languageCode, String locale);
+ public static native String getDisplayVariantNative(String variantCode, String locale);
- private static native String getCurrencyCodeNative(String locale);
+ public static native String getISO3CountryNative(String locale);
+ public static native String getISO3LanguageNative(String locale);
- private static native String getCurrencySymbolNative(String locale, String currencyCode);
+ public static native String getCurrencyCodeNative(String locale);
+ public static native String getCurrencySymbolNative(String locale, String currencyCode);
- private static native String getDisplayCountryNative(String countryCode, String locale);
-
- private static native String getDisplayLanguageNative(String languageCode, String locale);
-
- private static native String getDisplayVariantNative(String variantCode, String locale);
-
- private static native String getISO3CountryNative(String locale);
-
- private static native String getISO3LanguageNative(String locale);
+ public static native int getCurrencyFractionDigitsNative(String currencyCode);
private static native String[] getAvailableLocalesNative();
private static native String[] getISOLanguagesNative();
-
private static native String[] getISOCountriesNative();
private static native void getTimeZonesNative(String[][] arrayToFill, String locale);
@@ -539,5 +374,5 @@
private static native String getDisplayTimeZoneNative(String id, boolean isDST, int style,
String locale);
- private static native Object[][] getContentImpl(String locale, boolean needsTimeZones);
+ private static native Object[][] getContentImpl(String locale);
}
diff --git a/libcore/icu/src/main/native/ResourceInterface.cpp b/libcore/icu/src/main/native/ResourceInterface.cpp
index 731cf3f..243d7c4 100644
--- a/libcore/icu/src/main/native/ResourceInterface.cpp
+++ b/libcore/icu/src/main/native/ResourceInterface.cpp
@@ -54,9 +54,9 @@
int stringLength = string.length();
jchar *res = (jchar *) malloc(sizeof(jchar) * (stringLength + 1));
string.extract(res, stringLength+1, status);
- if(U_FAILURE(status)) {
+ if (U_FAILURE(status)) {
free(res);
- LOGI("Error getting string for getJStringFromUnicodeString");
+ LOGE("Error getting string for getJStringFromUnicodeString: %s", u_errorName(status));
status = U_ZERO_ERROR;
return NULL;
}
@@ -76,10 +76,7 @@
env->DeleteLocalRef(element);
}
-static jint getFractionDigitsNative(JNIEnv* env, jclass clazz,
- jstring currencyCode) {
- // LOGI("ENTER getFractionDigitsNative");
-
+static jint getCurrencyFractionDigitsNative(JNIEnv* env, jclass clazz, jstring currencyCode) {
UErrorCode status = U_ZERO_ERROR;
NumberFormat *fmt = NumberFormat::createCurrencyInstance(status);
@@ -229,135 +226,77 @@
static jstring getDisplayCountryNative(JNIEnv* env, jclass clazz,
jstring targetLocale, jstring locale) {
- // LOGI("ENTER getDisplayCountryNative");
-
- UErrorCode status = U_ZERO_ERROR;
Locale loc = getLocale(env, locale);
Locale targetLoc = getLocale(env, targetLocale);
-
+
UnicodeString string;
targetLoc.getDisplayCountry(loc, string);
-
- jstring result = getJStringFromUnicodeString(env, string);
-
- return result;
+ return getJStringFromUnicodeString(env, string);
}
static jstring getDisplayLanguageNative(JNIEnv* env, jclass clazz,
jstring targetLocale, jstring locale) {
- // LOGI("ENTER getDisplayLanguageNative");
Locale loc = getLocale(env, locale);
Locale targetLoc = getLocale(env, targetLocale);
UnicodeString string;
targetLoc.getDisplayLanguage(loc, string);
-
- jstring result = getJStringFromUnicodeString(env, string);
-
- return result;
+ return getJStringFromUnicodeString(env, string);
}
static jstring getDisplayVariantNative(JNIEnv* env, jclass clazz,
jstring targetLocale, jstring locale) {
- // LOGI("ENTER getDisplayVariantNative");
Locale loc = getLocale(env, locale);
Locale targetLoc = getLocale(env, targetLocale);
-
+
UnicodeString string;
targetLoc.getDisplayVariant(loc, string);
-
- jstring result = getJStringFromUnicodeString(env, string);
-
- return result;
+ return getJStringFromUnicodeString(env, string);
}
static jstring getISO3CountryNative(JNIEnv* env, jclass clazz, jstring locale) {
- // LOGI("ENTER getISO3CountryNative");
-
Locale loc = getLocale(env, locale);
-
- const char *string = loc.getISO3Country();
-
- jstring result = env->NewStringUTF(string);
-
- return result;
+ return env->NewStringUTF(loc.getISO3Country());
}
static jstring getISO3LanguageNative(JNIEnv* env, jclass clazz, jstring locale) {
- // LOGI("ENTER getISO3LanguageNative");
-
Locale loc = getLocale(env, locale);
-
- const char *string = loc.getISO3Language();
-
- jstring result = env->NewStringUTF(string);
-
+ return env->NewStringUTF(loc.getISO3Language());
+}
+
+static jobjectArray toStringArray(JNIEnv* env, const char* const* strings) {
+ size_t count = 0;
+ while (strings[count] != NULL) {
+ ++count;
+ }
+ jobjectArray result = env->NewObjectArray(count, string_class, NULL);
+ for (size_t i = 0; i < count; ++i) {
+ jstring s = env->NewStringUTF(strings[i]);
+ env->SetObjectArrayElement(result, i, s);
+ env->DeleteLocalRef(s);
+ }
return result;
}
static jobjectArray getISOCountriesNative(JNIEnv* env, jclass clazz) {
- // LOGI("ENTER getISOCountriesNative");
-
- const char* const* strings = Locale::getISOCountries();
-
- int count = 0;
- while(strings[count] != NULL) {
- count++;
- }
-
- jobjectArray result = env->NewObjectArray(count, string_class, NULL);
-
- jstring res;
- for(int i = 0; i < count; i++) {
- res = env->NewStringUTF(strings[i]);
- env->SetObjectArrayElement(result, i, res);
- env->DeleteLocalRef(res);
- }
- return result;
+ return toStringArray(env, Locale::getISOCountries());
}
static jobjectArray getISOLanguagesNative(JNIEnv* env, jclass clazz) {
- // LOGI("ENTER getISOLanguagesNative");
-
- const char* const* strings = Locale::getISOLanguages();
-
- const char *string = strings[0];
-
- int count = 0;
- while(strings[count] != NULL) {
- count++;
- }
-
- jobjectArray result = env->NewObjectArray(count, string_class, NULL);
-
- jstring res;
- for(int i = 0; i < count; i++) {
- res = env->NewStringUTF(strings[i]);
- env->SetObjectArrayElement(result, i, res);
- env->DeleteLocalRef(res);
- }
- return result;
+ return toStringArray(env, Locale::getISOLanguages());
}
static jobjectArray getAvailableLocalesNative(JNIEnv* env, jclass clazz) {
- // LOGI("ENTER getAvailableLocalesNative");
-
- int count = uloc_countAvailable();
-
+ size_t count = uloc_countAvailable();
jobjectArray result = env->NewObjectArray(count, string_class, NULL);
-
- jstring res;
- const char * string;
- for(int i = 0; i < count; i++) {
- string = uloc_getAvailable(i);
- res = env->NewStringUTF(string);
- env->SetObjectArrayElement(result, i, res);
- env->DeleteLocalRef(res);
+ for (size_t i = 0; i < count; ++i) {
+ jstring s = env->NewStringUTF(uloc_getAvailable(i));
+ env->SetObjectArrayElement(result, i, s);
+ env->DeleteLocalRef(s);
}
-
return result;
}
@@ -497,64 +436,53 @@
return result;
}
-static void getDayInitVector(JNIEnv *env, UResourceBundle *gregorian, int *values) {
-
- UErrorCode status = U_ZERO_ERROR;
+static void getDayIntVector(JNIEnv *env, UResourceBundle *gregorian, int *values) {
// get the First day of week and the minimal days in first week numbers
+ UErrorCode status = U_ZERO_ERROR;
UResourceBundle *gregorianElems = ures_getByKey(gregorian, "DateTimeElements", NULL, &status);
- if(U_FAILURE(status)) {
+ if (U_FAILURE(status)) {
return;
}
int intVectSize;
- const int *result;
- result = ures_getIntVector(gregorianElems, &intVectSize, &status);
- if(U_FAILURE(status)) {
+ const int* result = ures_getIntVector(gregorianElems, &intVectSize, &status);
+ if (U_FAILURE(status)) {
ures_close(gregorianElems);
return;
}
-
- if(intVectSize == 2) {
+
+ if (intVectSize == 2) {
values[0] = result[0];
values[1] = result[1];
}
ures_close(gregorianElems);
-
}
static jobjectArray getAmPmMarkers(JNIEnv *env, UResourceBundle *gregorian) {
-
- jobjectArray amPmMarkers;
- jstring pmU, amU;
-
UErrorCode status = U_ZERO_ERROR;
-
- UResourceBundle *gregorianElems;
-
- gregorianElems = ures_getByKey(gregorian, "AmPmMarkers", NULL, &status);
- if(U_FAILURE(status)) {
+ UResourceBundle *gregorianElems = ures_getByKey(gregorian, "AmPmMarkers", NULL, &status);
+ if (U_FAILURE(status)) {
return NULL;
}
- int lengthAm, lengthPm;
-
ures_resetIterator(gregorianElems);
+ int lengthAm, lengthPm;
const jchar* am = ures_getStringByIndex(gregorianElems, 0, &lengthAm, &status);
const jchar* pm = ures_getStringByIndex(gregorianElems, 1, &lengthPm, &status);
- if(U_FAILURE(status)) {
+ if (U_FAILURE(status)) {
ures_close(gregorianElems);
return NULL;
}
- amPmMarkers = env->NewObjectArray(2, string_class, NULL);
- amU = env->NewString(am, lengthAm);
+ jobjectArray amPmMarkers = env->NewObjectArray(2, string_class, NULL);
+ jstring amU = env->NewString(am, lengthAm);
env->SetObjectArrayElement(amPmMarkers, 0, amU);
env->DeleteLocalRef(amU);
- pmU = env->NewString(pm, lengthPm);
+ jstring pmU = env->NewString(pm, lengthPm);
env->SetObjectArrayElement(amPmMarkers, 1, pmU);
env->DeleteLocalRef(pmU);
ures_close(gregorianElems);
@@ -813,41 +741,26 @@
}
static jstring getDecimalPatternChars(JNIEnv *env, UResourceBundle *rootElems) {
-
UErrorCode status = U_ZERO_ERROR;
int zeroL, digitL, decSepL, groupL, listL, percentL, permillL, expL, currSepL, minusL;
- int patternLength;
-
- jchar *patternChars;
const jchar* zero = ures_getStringByIndex(rootElems, 4, &zeroL, &status);
-
const jchar* digit = ures_getStringByIndex(rootElems, 5, &digitL, &status);
-
const jchar* decSep = ures_getStringByIndex(rootElems, 0, &decSepL, &status);
-
const jchar* group = ures_getStringByIndex(rootElems, 1, &groupL, &status);
-
const jchar* list = ures_getStringByIndex(rootElems, 2, &listL, &status);
-
const jchar* percent = ures_getStringByIndex(rootElems, 3, &percentL, &status);
-
const jchar* permill = ures_getStringByIndex(rootElems, 8, &permillL, &status);
-
const jchar* exp = ures_getStringByIndex(rootElems, 7, &expL, &status);
-
const jchar* currSep = ures_getStringByIndex(rootElems, 0, &currSepL, &status);
-
const jchar* minus = ures_getStringByIndex(rootElems, 6, &minusL, &status);
- if(U_FAILURE(status)) {
+ if (U_FAILURE(status)) {
return NULL;
}
-
- patternChars = (jchar *) malloc(11 * sizeof(jchar));
-
+ jchar patternChars[11];
patternChars[0] = 0;
u_strncat(patternChars, zero, 1);
@@ -861,11 +774,7 @@
u_strncat(patternChars, currSep, 1);
u_strncat(patternChars, minus, 1);
- jstring decimalPatternChars = env->NewString(patternChars, 10);
-
- free(patternChars);
-
- return decimalPatternChars;
+ return env->NewString(patternChars, 10);
}
static jstring getIntCurrencyCode(JNIEnv *env, jclass clazz, jstring locale) {
@@ -891,32 +800,21 @@
}
static jstring getCurrencySymbol(JNIEnv *env, jclass clazz, jstring locale, jstring intCurrencySymbol) {
-
jstring result = getCurrencySymbolNative(env, clazz, locale, intCurrencySymbol);
- if(result == intCurrencySymbol) {
- return NULL;
- }
- return result;
-
+ return (result == intCurrencySymbol) ? NULL : result;
}
-static jobjectArray getContentImpl(JNIEnv* env, jclass clazz,
- jstring locale, jboolean needsTZ) {
-
- UErrorCode status = U_ZERO_ERROR;
-
+static jobjectArray getContentImpl(JNIEnv* env, jclass clazz, jstring locale) {
const char *loc = env->GetStringUTFChars(locale, NULL);
- UResourceBundle *root = ures_openU(NULL, loc, &status);
-
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle* root = ures_openU(NULL, loc, &status);
env->ReleaseStringUTFChars(locale, loc);
- if(U_FAILURE(status)) {
- LOGI("Error getting resources");
+ if (U_FAILURE(status)) {
+ LOGE("Error getting resources: %s", u_errorName(status));
status = U_ZERO_ERROR;
return NULL;
}
-
-
jclass obj_class = env->FindClass("[Ljava/lang/Object;");
jclass integer_class = env->FindClass("java/lang/Integer");
jmethodID integerInit = env->GetMethodID(integer_class, "<init>", "(I)V");
@@ -952,7 +850,6 @@
int counter = 0;
- int firstDayVals[2] = {-1, -1};
const jchar* nan = (const jchar *)NULL;
const jchar* inf = (const jchar *)NULL;
@@ -981,7 +878,8 @@
// adding the first day of week and minimal days in first week values
- getDayInitVector(env, gregorian, firstDayVals);
+ int firstDayVals[2] = {-1, -1};
+ getDayIntVector(env, gregorian, firstDayVals);
if((firstDayVals[0] != -1) && (firstDayVals[1] != -1)) {
firstDayOfWeek = env->NewObject(integer_class, integerInit, firstDayVals[0]);
minimalDaysInFirstWeek = env->NewObject(integer_class, integerInit, firstDayVals[1]);
@@ -1254,20 +1152,10 @@
ures_close(root);
- if(needsTZ == JNI_TRUE) {
- counter++; //add empty timezone
- }
-
-
-
// collect all content and put it into an array
result = env->NewObjectArray(counter, obj_class, NULL);
int index = 0;
-
- if(needsTZ == JNI_TRUE) {
- addObject(env, result, "timezones", NULL, index++);
- }
if(firstDayOfWeek != NULL && index < counter) {
addObject(env, result, "First_Day", firstDayOfWeek, index++);
}
@@ -1353,16 +1241,16 @@
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- {"getFractionDigitsNative", "(Ljava/lang/String;)I",
- (void*) getFractionDigitsNative},
+ {"getCurrencyFractionDigitsNative", "(Ljava/lang/String;)I",
+ (void*) getCurrencyFractionDigitsNative},
{"getCurrencyCodeNative", "(Ljava/lang/String;)Ljava/lang/String;",
(void*) getCurrencyCodeNative},
{"getCurrencySymbolNative", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
(void*) getCurrencySymbolNative},
- {"getDisplayCountryNative",
+ {"getDisplayCountryNative",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
(void*) getDisplayCountryNative},
- {"getDisplayLanguageNative",
+ {"getDisplayLanguageNative",
"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
(void*) getDisplayLanguageNative},
{"getDisplayVariantNative",
@@ -1380,14 +1268,14 @@
(void*) getISOLanguagesNative},
{"getAvailableLocalesNative", "()[Ljava/lang/String;",
(void*) getAvailableLocalesNative},
- {"getTimeZonesNative",
+ {"getTimeZonesNative",
"([[Ljava/lang/String;Ljava/lang/String;)V",
(void*) getTimeZonesNative},
- {"getDisplayTimeZoneNative",
+ {"getDisplayTimeZoneNative",
"(Ljava/lang/String;ZILjava/lang/String;)Ljava/lang/String;",
(void*) getDisplayTimeZoneNative},
- {"getContentImpl",
- "(Ljava/lang/String;Z)[[Ljava/lang/Object;",
+ {"getContentImpl",
+ "(Ljava/lang/String;)[[Ljava/lang/Object;",
(void*) getContentImpl},
};
diff --git a/libcore/luni/src/main/java/java/util/Calendar.java b/libcore/luni/src/main/java/java/util/Calendar.java
index 49a8c3f..3d1f4ad 100644
--- a/libcore/luni/src/main/java/java/util/Calendar.java
+++ b/libcore/luni/src/main/java/java/util/Calendar.java
@@ -691,7 +691,7 @@
// .getTimeZone(timezone.getID()), locale);
// setFirstDayOfWeek(icuCalendar.getFirstDayOfWeek());
// setMinimalDaysInFirstWeek(icuCalendar.getMinimalDaysInFirstWeek());
- ResourceBundle bundle = Locale.getBundle("Locale", locale); //$NON-NLS-1$
+ ResourceBundle bundle = com.ibm.icu4jni.util.Resources.getLocaleInstance(locale);
setFirstDayOfWeek(((Integer) bundle.getObject("First_Day")).intValue()); //$NON-NLS-1$
setMinimalDaysInFirstWeek(((Integer) bundle.getObject("Minimal_Days")) //$NON-NLS-1$
.intValue());
diff --git a/libcore/luni/src/main/java/java/util/Currency.java b/libcore/luni/src/main/java/java/util/Currency.java
index 79de49d..1673455 100644
--- a/libcore/luni/src/main/java/java/util/Currency.java
+++ b/libcore/luni/src/main/java/java/util/Currency.java
@@ -18,10 +18,14 @@
package java.util;
// BEGIN android-added
+import com.ibm.icu4jni.util.Resources;
+import java.util.logging.Logger;
import org.apache.harmony.luni.util.Msg;
// END android-added
+import java.security.AccessController;
import java.io.Serializable;
+import java.security.PrivilegedAction;
/**
* This class represents a currency as identified in the ISO 4217 currency
@@ -31,25 +35,36 @@
private static final long serialVersionUID = -158308464356906721L;
- private static Hashtable<String, Currency> codesToCurrencies = new Hashtable<String, Currency>();
+ private static final Hashtable<String, Currency> codesToCurrencies = new Hashtable<String, Currency>();
- private String currencyCode;
+ private final String currencyCode;
// BEGIN android-added
- private static String currencyVars = "EURO, HK, PREEURO"; //$NON-NLS-1$
-
+ // TODO: this isn't set if we're restored from serialized form,
+ // so getDefaultFractionDigits always returns 0!
private transient int defaultFractionDigits;
// END android-added
- /**
- * @param currencyCode
- */
private Currency(String currencyCode) {
+ // BEGIN android-changed
this.currencyCode = currencyCode;
+
+ // In some places the code XXX is used as the fall back currency.
+ // The RI returns -1, but ICU defaults to 2 for unknown currencies.
+ if (currencyCode.equals("XXX")) {
+ this.defaultFractionDigits = -1;
+ return;
+ }
+
+ this.defaultFractionDigits = Resources.getCurrencyFractionDigitsNative(currencyCode);
+ if (defaultFractionDigits < 0) {
+ throw new IllegalArgumentException(Msg.getString("K0322", currencyCode));
+ }
+ // END android-changed
}
/**
- * Returns the {@code Currency} instance for this currency code.
+ * Returns the {@code Currency} instance for the given currency code.
* <p>
*
* @param currencyCode
@@ -61,29 +76,14 @@
* code.
*/
public static Currency getInstance(String currencyCode) {
+ // BEGIN android-changed
Currency currency = codesToCurrencies.get(currencyCode);
-
if (currency == null) {
- // BEGIN android-added
- ResourceBundle bundle = Locale.getBundle(
- "ISO4CurrenciesToDigits", Locale.getDefault()); //$NON-NLS-1$
currency = new Currency(currencyCode);
-
- String defaultFractionDigits = null;
- try {
- defaultFractionDigits = bundle.getString(currencyCode);
- } catch (MissingResourceException e) {
- throw new IllegalArgumentException(
- org.apache.harmony.luni.util.Msg.getString(
- "K0322", currencyCode)); //$NON-NLS-1$
- }
- currency.defaultFractionDigits = Integer
- .parseInt(defaultFractionDigits);
- // END android-added
codesToCurrencies.put(currencyCode, currency);
}
-
return currency;
+ // END android-changed
}
/**
@@ -98,38 +98,20 @@
*/
public static Currency getInstance(Locale locale) {
// BEGIN android-changed
- // com.ibm.icu.util.Currency currency = null;
- // try {
- // currency = com.ibm.icu.util.Currency.getInstance(locale);
- // } catch (IllegalArgumentException e) {
- // return null;
- // }
- // if (currency == null) {
- // throw new IllegalArgumentException(locale.getCountry());
- // }
- // String currencyCode = currency.getCurrencyCode();
String country = locale.getCountry();
String variant = locale.getVariant();
- if (!variant.equals("") && currencyVars.indexOf(variant) > -1) { //$NON-NLS-1$
- country = country + "_" + variant; //$NON-NLS-1$
+ if (variant.length() > 0 && "EURO, HK, PREEURO".indexOf(variant) != -1) {
+ country = country + "_" + variant;
}
- ResourceBundle bundle = Locale.getBundle(
- "ISO4Currencies", Locale.getDefault()); //$NON-NLS-1$
- String currencyCode = null;
- try {
- currencyCode = bundle.getString(country);
- } catch (MissingResourceException e) {
- throw new IllegalArgumentException(Msg.getString(
- "K0323", locale.toString())); //$NON-NLS-1$
- }
- // END android-changed
-
- if (currencyCode.equals("None")) { //$NON-NLS-1$
+ String currencyCode = com.ibm.icu4jni.util.Resources.getCurrencyCodeNative(country);
+ if (currencyCode == null) {
+ throw new IllegalArgumentException(Msg.getString("K0323", locale.toString()));
+ } else if (currencyCode.equals("None")) {
return null;
}
-
return getInstance(currencyCode);
+ // END android-changed
}
/**
@@ -176,40 +158,38 @@
* locale.
*/
public String getSymbol(Locale locale) {
- if (locale.getCountry().equals("")) { //$NON-NLS-1$
+ // BEGIN android-changed
+ if (locale.getCountry().length() == 0) {
return currencyCode;
}
- // BEGIN android-changed
- // return com.ibm.icu.util.Currency.getInstance(currencyCode).getSymbol(locale);
- // check in the Locale bundle first, if the local has the same currency
- ResourceBundle bundle = Locale.getBundle("Locale", locale); //$NON-NLS-1$
- if (((String) bundle.getObject("IntCurrencySymbol")) //$NON-NLS-1$
- .equals(currencyCode)) {
- return (String) bundle.getObject("CurrencySymbol"); //$NON-NLS-1$
+ // Check the Locale bundle first, in case the locale has the same currency.
+ ResourceBundle localeBundle = com.ibm.icu4jni.util.Resources.getLocaleInstance(locale);
+ if (localeBundle.getString("IntCurrencySymbol").equals(currencyCode)) {
+ return localeBundle.getString("CurrencySymbol");
}
- // search for a Currency bundle
- bundle = null;
+ // check if the currency bundle for this locale has an entry for this currency
try {
- bundle = Locale.getBundle("Currency", locale); //$NON-NLS-1$
+ ResourceBundle currencyBundle = getCurrencyBundle(locale);
+
+ // is the bundle found for a different country? (for instance the
+ // default locale's currency bundle)
+ if (!currencyBundle.getLocale().getCountry().equals(locale.getCountry())) {
+ // TODO: the fact I never see output from this when running the tests suggests we
+ // don't have a test for this. Does it ever even happen? If it does, can we just
+ // ask ICU a slightly different question to get the behavior we want?
+ Logger.global.info("currencyBundle " + currencyBundle + " for " + locale +
+ " came back with locale " + currencyBundle.getLocale());
+ return currencyCode;
+ }
+
+ // Return the currency bundle's value, or currencyCode.
+ String result = (String) currencyBundle.handleGetObject(currencyCode);
+ return (result != null) ? result : currencyCode;
} catch (MissingResourceException e) {
return currencyCode;
}
-
- // is the bundle found for a different country? (for instance the
- // default locale's currency bundle)
- if (!bundle.getLocale().getCountry().equals(locale.getCountry())) {
- return currencyCode;
- }
-
- // check if the currency bundle for this locale
- // has an entry for this currency
- String result = (String) bundle.handleGetObject(currencyCode);
- if (result != null) {
- return result;
- }
- return currencyCode;
// END android-changed
}
@@ -241,4 +221,14 @@
private Object readResolve() {
return getInstance(currencyCode);
}
+
+ // TODO: remove this in favor of direct access (and no ResourceBundle cruft).
+ private static ResourceBundle getCurrencyBundle(final Locale locale) {
+ return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() {
+ public ResourceBundle run() {
+ String bundle = "org.apache.harmony.luni.internal.locale.Currency";
+ return ResourceBundle.getBundle(bundle, locale);
+ }
+ });
+ }
}
diff --git a/libcore/luni/src/main/java/java/util/Locale.java b/libcore/luni/src/main/java/java/util/Locale.java
index 1e97d3c..5337e48 100644
--- a/libcore/luni/src/main/java/java/util/Locale.java
+++ b/libcore/luni/src/main/java/java/util/Locale.java
@@ -25,7 +25,6 @@
import java.io.ObjectStreamField;
import java.io.Serializable;
import java.security.AccessController;
-import java.security.PrivilegedAction;
// import java.util.zip.ZipEntry;
// import java.util.zip.ZipFile;
@@ -200,6 +199,7 @@
private transient String countryCode;
private transient String languageCode;
private transient String variantCode;
+ private transient String cachedToStringResult;
// BEGIN android-removed
// private transient ULocale uLocale;
@@ -412,29 +412,18 @@
* the {@code Locale} for which the display name is retrieved.
* @return a country name.
*/
- public String getDisplayCountry(Locale locale) {
+ public String getDisplayCountry(Locale locale) {
// BEGIN android-changed
- // return ULocale.forLocale(this).getDisplayCountry(ULocale.forLocale(locale));
if (countryCode.length() == 0) {
return countryCode;
}
- try {
- // First try the specified locale
- ResourceBundle bundle = getBundle("Country", locale); //$NON-NLS-1$
- String result = bundle.getString(this.toString());
- if (result != null) {
- return result;
- }
- // Now use the default locale
- if (locale != Locale.getDefault()) {
- bundle = getBundle("Country", Locale.getDefault()); //$NON-NLS-1$
- }
- return bundle.getString(countryCode);
- } catch (MissingResourceException e) {
- return countryCode;
+ String result = Resources.getDisplayCountryNative(toString(), locale.toString());
+ if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+ result = Resources.getDisplayCountryNative(toString(), Locale.getDefault().toString());
}
+ return result;
// END android-changed
- }
+ }
/**
* Gets the full language name in the default {@code Locale} for the language code
@@ -456,29 +445,18 @@
* the {@code Locale} for which the display name is retrieved.
* @return a language name.
*/
- public String getDisplayLanguage(Locale locale) {
+ public String getDisplayLanguage(Locale locale) {
// BEGIN android-changed
- // return ULocale.forLocale(this).getDisplayLanguage(ULocale.forLocale(locale));
if (languageCode.length() == 0) {
return languageCode;
}
- try {
- // First try the specified locale
- ResourceBundle bundle = getBundle("Language", locale); //$NON-NLS-1$
- String result = bundle.getString(this.toString());
- if (result != null) {
- return result;
- }
- // Now use the default locale
- if (locale != Locale.getDefault()) {
- bundle = getBundle("Language", Locale.getDefault()); //$NON-NLS-1$
- }
- return bundle.getString(languageCode);
- } catch (MissingResourceException e) {
- return languageCode;
+ String result = Resources.getDisplayLanguageNative(toString(), locale.toString());
+ if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+ result = Resources.getDisplayLanguageNative(toString(), Locale.getDefault().toString());
}
+ return result;
// END android-changed
- }
+ }
/**
* Gets the full language, country, and variant names in the default {@code Locale}
@@ -547,29 +525,18 @@
* the {@code Locale} for which the display name is retrieved.
* @return a variant name.
*/
- public String getDisplayVariant(Locale locale) {
+ public String getDisplayVariant(Locale locale) {
// BEGIN android-changed
- // return ULocale.forLocale(this).getDisplayVariant(ULocale.forLocale(locale));
if (variantCode.length() == 0) {
return variantCode;
}
- try {
- // First try the specified locale
- ResourceBundle bundle = getBundle("Variant", locale); //$NON-NLS-1$
- String result = bundle.getString(this.toString());
- if (result != null) {
- return result;
- }
- // Now use the default locale
- if (locale != Locale.getDefault()) {
- bundle = getBundle("Variant", Locale.getDefault()); //$NON-NLS-1$
- }
- return bundle.getString(variantCode);
- } catch (MissingResourceException e) {
- return variantCode;
+ String result = Resources.getDisplayVariantNative(toString(), locale.toString());
+ if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
+ result = Resources.getDisplayVariantNative(toString(), Locale.getDefault().toString());
}
+ return result;
// END android-changed
- }
+ }
/**
* Gets the three letter ISO country code which corresponds to the country
@@ -579,16 +546,14 @@
* @throws MissingResourceException
* if there is no matching three letter ISO country code.
*/
- public String getISO3Country() throws MissingResourceException {
+ public String getISO3Country() throws MissingResourceException {
// BEGIN android-changed
- // return ULocale.forLocale(this).getISO3Country();
if (countryCode.length() == 0) {
- return ""; //$NON-NLS-1$
+ return countryCode;
}
- ResourceBundle bundle = getBundle("ISO3Countries", this); //$NON-NLS-1$
- return bundle.getString(this.toString());
+ return Resources.getISO3CountryNative(toString());
// END android-changed
- }
+ }
/**
* Gets the three letter ISO language code which corresponds to the language
@@ -598,16 +563,14 @@
* @throws MissingResourceException
* if there is no matching three letter ISO language code.
*/
- public String getISO3Language() throws MissingResourceException {
+ public String getISO3Language() throws MissingResourceException {
// BEGIN android-changed
- // return ULocale.forLocale(this).getISO3Language();
if (languageCode.length() == 0) {
- return ""; //$NON-NLS-1$
+ return languageCode;
}
- ResourceBundle bundle = getBundle("ISO3Languages", this); //$NON-NLS-1$
- return bundle.getString(this.toString());
+ return Resources.getISO3LanguageNative(toString());
// END android-changed
- }
+ }
/**
* Gets the list of two letter ISO country codes which can be used as the
@@ -617,7 +580,6 @@
*/
public static String[] getISOCountries() {
// BEGIN android-changed
- // return ULocale.getISOCountries();
return Resources.getISOCountries();
// END android-changed
}
@@ -628,12 +590,11 @@
*
* @return an array of strings.
*/
- public static String[] getISOLanguages() {
+ public static String[] getISOLanguages() {
// BEGIN android-changed
- // return ULocale.getISOLanguages();
return Resources.getISOLanguages();
// END android-changed
- }
+ }
/**
* Gets the language code for this {@code Locale} or the empty string of no language
@@ -646,7 +607,7 @@
}
/**
- * Gets the variant code for this {@code Locale} or an empty {@code String} of no variant
+ * Gets the variant code for this {@code Locale} or an empty {@code String} if no variant
* was set.
*
* @return a variant code.
@@ -704,33 +665,31 @@
*/
@Override
public final String toString() {
- StringBuilder result = new StringBuilder();
- result.append(languageCode);
- if (countryCode.length() > 0) {
- result.append('_');
- result.append(countryCode);
- }
- if (variantCode.length() > 0 && result.length() > 0) {
- if (0 == countryCode.length()) {
- result.append("__"); //$NON-NLS-1$
- } else {
- result.append('_');
- }
- result.append(variantCode);
- }
- return result.toString();
+ String result = cachedToStringResult;
+ return (result == null) ? (cachedToStringResult = toNewString()) : result;
}
- // BEGIN android-added
- static ResourceBundle getBundle(final String clName, final Locale locale) {
- return AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() {
- public ResourceBundle run() {
- return ResourceBundle.getBundle("org.apache.harmony.luni.internal.locale." //$NON-NLS-1$
- + clName, locale);
- }
- });
+ private String toNewString() {
+ // The string form of a locale that only has a variant is the empty string.
+ if (languageCode.length() == 0 && countryCode.length() == 0) {
+ return "";
+ }
+ // Otherwise, the output format is "ll_cc_variant", where language and country are always
+ // two letters, but the variant is an arbitrary length. A size of 11 characters has room
+ // for "en_US_POSIX", the largest "common" value. (In practice, the string form is almost
+ // always 5 characters: "ll_cc".)
+ StringBuilder result = new StringBuilder(11);
+ result.append(languageCode);
+ if (countryCode.length() > 0 || variantCode.length() > 0) {
+ result.append('_');
+ }
+ result.append(countryCode);
+ if (variantCode.length() > 0) {
+ result.append('_');
+ }
+ result.append(variantCode);
+ return result.toString();
}
- // END android-added
private static final ObjectStreamField[] serialPersistentFields = {
new ObjectStreamField("country", String.class), //$NON-NLS-1$
diff --git a/libcore/text/src/main/java/java/text/Format.java b/libcore/text/src/main/java/java/text/Format.java
index 8abe605..7660f8e 100644
--- a/libcore/text/src/main/java/java/text/Format.java
+++ b/libcore/text/src/main/java/java/text/Format.java
@@ -89,15 +89,8 @@
}
// BEGIN android-added
- static ResourceBundle getBundle(final Locale locale) {
- return AccessController
- .doPrivileged(new PrivilegedAction<ResourceBundle>() {
- public ResourceBundle run() {
- return ResourceBundle
- .getBundle(
- "org.apache.harmony.luni.internal.locale.Locale", locale); //$NON-NLS-1$
- }
- });
+ static ResourceBundle getBundle(Locale locale) {
+ return com.ibm.icu4jni.util.Resources.getLocaleInstance(locale);
}
// END android-added