Stop using ResourceBundle for locale data.

This offers an additional speed increase and gets rid of a lot of native code.
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 0ceb287..43ac3f2 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
@@ -17,6 +17,7 @@
 package com.ibm.icu4jni.text;
 
 import com.ibm.icu4jni.text.NativeDecimalFormat.UNumberFormatSymbol;
+import com.ibm.icu4jni.util.LocaleData;
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
@@ -36,18 +37,15 @@
     }
     
     public DecimalFormatSymbols(Locale locale) {
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
         this.loc = locale;
-        ResourceBundle bundle = com.ibm.icu4jni.util.Resources.getLocaleInstance(locale);
-        String pattern = bundle.getString("Number");
-        this.addr = NativeDecimalFormat.openDecimalFormatImpl(
-                locale.toString(), pattern);
-        String currSymbol = bundle.getString("CurrencySymbol");
-        String intCurrSymbol = bundle.getString("IntCurrencySymbol");
+        this.addr = NativeDecimalFormat.openDecimalFormatImpl(locale.toString(),
+                localeData.numberPattern);
         NativeDecimalFormat.setSymbol(this.addr,
-                UNumberFormatSymbol.UNUM_CURRENCY_SYMBOL.ordinal(), currSymbol);
+                UNumberFormatSymbol.UNUM_CURRENCY_SYMBOL.ordinal(), localeData.currencySymbol);
         NativeDecimalFormat.setSymbol(this.addr,
                 UNumberFormatSymbol.UNUM_INTL_CURRENCY_SYMBOL.ordinal(), 
-                intCurrSymbol);
+                localeData.internationalCurrencySymbol);
     }
     
     @Override
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/util/LocaleData.java b/libcore/icu/src/main/java/com/ibm/icu4jni/util/LocaleData.java
new file mode 100644
index 0000000..1e91574
--- /dev/null
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/util/LocaleData.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.ibm.icu4jni.util;
+
+/**
+ * Passes locale-specific from ICU native code to Java.
+ * <p>
+ * Note that you share these; you must not alter any of the fields, nor their array elements
+ * in the case of arrays. If you ever expose any of these things to user code, you must give
+ * them a clone rather than the original.
+ */
+public class LocaleData {
+    public Integer firstDayOfWeek;
+    public Integer minimalDaysInFirstWeek;
+    
+    public String[] amPm;
+    
+    public String[] eras;
+    
+    public String[] longMonthNames;
+    public String[] shortMonthNames;
+    
+    public String[] longWeekdayNames;
+    public String[] shortWeekdayNames;
+    
+    public String fullTimeFormat;
+    public String longTimeFormat;
+    public String mediumTimeFormat;
+    public String shortTimeFormat;
+    
+    public String fullDateFormat;
+    public String longDateFormat;
+    public String mediumDateFormat;
+    public String shortDateFormat;
+    
+    public String decimalPatternChars;
+    
+    public String infinity;
+    public String NaN;
+    
+    public String currencySymbol;
+    public String internationalCurrencySymbol;
+    
+    public String numberPattern;
+    public String integerPattern;
+    public String currencyPattern;
+    public String percentPattern;
+    
+    @Override public String toString() {
+        return "LocaleData[" +
+                "firstDayOfWeek=" + firstDayOfWeek + "," +
+                "minimalDaysInFirstWeek=" + minimalDaysInFirstWeek + "," +
+                "amPm=" + amPm + "," +
+                "eras=" + eras + "," +
+                "longMonthNames=" + longMonthNames + "," +
+                "shortMonthNames=" + shortMonthNames + "," +
+                "longWeekdayNames=" + longWeekdayNames + "," +
+                "shortWeekdayNames=" + shortWeekdayNames + "," +
+                "fullTimeFormat=" + fullTimeFormat + "," +
+                "longTimeFormat=" + longTimeFormat + "," +
+                "mediumTimeFormat=" + mediumTimeFormat + "," +
+                "shortTimeFormat=" + shortTimeFormat + "," +
+                "fullDateFormat=" + fullDateFormat + "," +
+                "longDateFormat=" + longDateFormat + "," +
+                "mediumDateFormat=" + mediumDateFormat + "," +
+                "shortDateFormat=" + shortDateFormat + "," +
+                "decimalPatternChars=" + decimalPatternChars + "," +
+                "infinity=" + infinity + "," +
+                "NaN=" + NaN + "," +
+                "currencySymbol=" + currencySymbol + "," +
+                "internationalCurrencySymbol=" + internationalCurrencySymbol + "," +
+                "numberPattern=" + numberPattern + "," +
+                "integerPattern=" + integerPattern + "," +
+                "currencyPattern=" + currencyPattern + "," +
+                "percentPattern=" + percentPattern + "]";
+    }
+    
+    public void overrideWithDataFrom(LocaleData overrides) {
+        if (overrides.firstDayOfWeek != null) {
+            firstDayOfWeek = overrides.firstDayOfWeek;
+        }
+        if (overrides.minimalDaysInFirstWeek != null) {
+            minimalDaysInFirstWeek = overrides.minimalDaysInFirstWeek;
+        }
+        if (overrides.amPm != null) {
+            amPm = overrides.amPm;
+        }
+        if (overrides.eras != null) {
+            eras = overrides.eras;
+        }
+        if (overrides.longMonthNames != null) {
+            longMonthNames = overrides.longMonthNames;
+        }
+        if (overrides.shortMonthNames != null) {
+            shortMonthNames = overrides.shortMonthNames;
+        }
+        if (overrides.longWeekdayNames != null) {
+            longWeekdayNames = overrides.longWeekdayNames;
+        }
+        if (overrides.shortWeekdayNames != null) {
+            shortWeekdayNames = overrides.shortWeekdayNames;
+        }
+        if (overrides.fullTimeFormat != null) {
+            fullTimeFormat = overrides.fullTimeFormat;
+        }
+        if (overrides.longTimeFormat != null) {
+            longTimeFormat = overrides.longTimeFormat;
+        }
+        if (overrides.mediumTimeFormat != null) {
+            mediumTimeFormat = overrides.mediumTimeFormat;
+        }
+        if (overrides.shortTimeFormat != null) {
+            shortTimeFormat = overrides.shortTimeFormat;
+        }
+        if (overrides.fullDateFormat != null) {
+            fullDateFormat = overrides.fullDateFormat;
+        }
+        if (overrides.longDateFormat != null) {
+            longDateFormat = overrides.longDateFormat;
+        }
+        if (overrides.mediumDateFormat != null) {
+            mediumDateFormat = overrides.mediumDateFormat;
+        }
+        if (overrides.shortDateFormat != null) {
+            shortDateFormat = overrides.shortDateFormat;
+        }
+        if (overrides.decimalPatternChars != null) {
+            decimalPatternChars = overrides.decimalPatternChars;
+        }
+        if (overrides.NaN != null) {
+            NaN = overrides.NaN;
+        }
+        if (overrides.infinity != null) {
+            infinity = overrides.infinity;
+        }
+        if (overrides.currencySymbol != null) {
+            currencySymbol = overrides.currencySymbol;
+        }
+        if (overrides.internationalCurrencySymbol != null) {
+            internationalCurrencySymbol = overrides.internationalCurrencySymbol;
+        }
+        if (overrides.numberPattern != null) {
+            numberPattern = overrides.numberPattern;
+        }
+        if (overrides.integerPattern != null) {
+            integerPattern = overrides.integerPattern;
+        }
+        if (overrides.currencyPattern != null) {
+            currencyPattern = overrides.currencyPattern;
+        }
+        if (overrides.percentPattern != null) {
+            percentPattern = overrides.percentPattern;
+        }
+    }
+}
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 41bf3e3..8f09029 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
@@ -33,8 +33,8 @@
  */
 public class Resources {
     // A cache for the locale-specific data.
-    private static final ConcurrentHashMap<String, LocaleResourceBundle> localeInstanceCache =
-            new ConcurrentHashMap<String, LocaleResourceBundle>();
+    private static final ConcurrentHashMap<String, LocaleData> localeDataCache =
+            new ConcurrentHashMap<String, LocaleData>();
 
     /**
      * Cache for ISO language names.
@@ -57,40 +57,37 @@
     private static String[] availableTimezones = null;
 
     /**
-     * Returns a LocaleResourceBundle corresponding to the given locale.
-     * TODO: return something that allows cheap static field lookup rather than
-     * expensive chained hash table lookup.
+     * Returns a shared LocaleData for the given locale.
      */
-    public static ResourceBundle getLocaleInstance(Locale locale) {
+    public static LocaleData getLocaleData(Locale locale) {
         if (locale == null) {
             locale = Locale.getDefault();
         }
         String localeName = locale.toString();
-        LocaleResourceBundle bundle = localeInstanceCache.get(localeName);
-        if (bundle != null) {
-            return bundle;
+        LocaleData localeData = localeDataCache.get(localeName);
+        if (localeData != null) {
+            return localeData;
         }
-        bundle = makeLocaleResourceBundle(locale);
-        localeInstanceCache.put(localeName, bundle);
-        boolean absent = (localeInstanceCache.putIfAbsent(localeName, bundle) == null);
-        return absent ? bundle : localeInstanceCache.get(localeName);
+        localeData = makeLocaleData(locale);
+        boolean absent = (localeDataCache.putIfAbsent(localeName, localeData) == null);
+        return absent ? localeData : localeDataCache.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();
+    private static LocaleData makeLocaleData(Locale locale) {
         String language = locale.getLanguage();
-        if (locale.getVariant().length() > 0) {
-            result.setParent(getLocaleInstance(new Locale(language, country, "")));
+        String country = locale.getCountry();
+        String variant = locale.getVariant();
+        // Start with data from the parent (next-most-specific) locale...
+        LocaleData result = new LocaleData();
+        if (variant.length() > 0) {
+            result.overrideWithDataFrom(getLocaleData(new Locale(language, country, "")));
         } else if (country.length() > 0) {
-            result.setParent(getLocaleInstance(new Locale(language, "", "")));
+            result.overrideWithDataFrom(getLocaleData(new Locale(language, "", "")));
         } else if (language.length() > 0) {
-            result.setParent(getLocaleInstance(new Locale("", "", "")));
+            result.overrideWithDataFrom(getLocaleData(new Locale("", "", "")));
         }
-        
+        // Override with data from this locale.
+        result.overrideWithDataFrom(initLocaleData(locale));
         return result;
     }
 
@@ -270,7 +267,7 @@
         return createTimeZoneNamesFor(locale);
     }
 
-    private static String[][] clone2dStringArray(String[][] array) {
+    public static String[][] clone2dStringArray(String[][] array) {
         String[][] result = new String[array.length][];
         for (int i = 0; i < array.length; ++i) {
             result[i] = array[i].clone();
@@ -308,48 +305,6 @@
 
     }
 
-    /**
-     * 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 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.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 ----------------------------
 
     public static native String getDisplayCountryNative(String countryCode, String locale);
@@ -374,5 +329,25 @@
     private static native String getDisplayTimeZoneNative(String id, boolean isDST, int style,
             String locale);
 
-    private static native Object[][] getContentImpl(String locale);
+    private static LocaleData initLocaleData(Locale locale) {
+        LocaleData localeData = new LocaleData();
+        if (!initLocaleDataImpl(locale.toString(), localeData)) {
+            throw new AssertionError("couldn't initialize LocaleData for locale " + locale);
+        }
+        if (localeData.fullTimeFormat != null) {
+            // There are some full time format patterns in ICU that use the pattern character 'v'.
+            // Java doesn't accept this, so we replace it with 'z' which has about the same result
+            // as 'v', the timezone name.
+            // 'v' -> "PT", 'z' -> "PST", v is the generic timezone and z the standard tz
+            // "vvvv" -> "Pacific Time", "zzzz" -> "Pacific Standard Time"
+            localeData.fullTimeFormat = localeData.fullTimeFormat.replace('v', 'z');
+        }
+        if (localeData.numberPattern != null) {
+            String numberPattern = localeData.numberPattern;
+            localeData.integerPattern = numberPattern.substring(0, numberPattern.indexOf('.'));
+        }
+        return localeData;
+    }
+
+    private static native boolean initLocaleDataImpl(String locale, LocaleData result);
 }
diff --git a/libcore/icu/src/main/native/ResourceInterface.cpp b/libcore/icu/src/main/native/ResourceInterface.cpp
index abb00a0..151b23e 100644
--- a/libcore/icu/src/main/native/ResourceInterface.cpp
+++ b/libcore/icu/src/main/native/ResourceInterface.cpp
@@ -66,17 +66,6 @@
     return result;
 }
 
-static void addObject(JNIEnv* env, jobjectArray result, const char* keyStr, jobject elem, int index) {
-    jclass objArray_class = env->FindClass("java/lang/Object");
-    jobjectArray element = env->NewObjectArray(2, objArray_class, NULL);
-    jstring key = env->NewStringUTF(keyStr);
-    env->SetObjectArrayElement(element, 0, key);
-    env->SetObjectArrayElement(element, 1, elem);
-    env->SetObjectArrayElement(result, index, element);
-    env->DeleteLocalRef(key);
-    env->DeleteLocalRef(element);
-} 
-
 static jint getCurrencyFractionDigitsNative(JNIEnv* env, jclass clazz, jstring currencyCode) {
     UErrorCode status = U_ZERO_ERROR;
     
@@ -159,13 +148,13 @@
         return NULL;
     }
 
-    ScopedResourceBundle rootElems(ures_getByKey(root.get(), "Currencies", NULL, &status));
+    ScopedResourceBundle currencies(ures_getByKey(root.get(), "Currencies", NULL, &status));
     if (U_FAILURE(status)) {
         return NULL;
     }
 
     const char* currName = env->GetStringUTFChars(currencyCode, NULL);
-    ScopedResourceBundle currencyElems(ures_getByKey(rootElems.get(), currName, NULL, &status));
+    ScopedResourceBundle currencyElems(ures_getByKey(currencies.get(), currName, NULL, &status));
     env->ReleaseStringUTFChars(currencyCode, currName);
     if (U_FAILURE(status)) {
         return NULL;
@@ -354,22 +343,23 @@
     return result;
 }
 
-static void getDayIntVector(JNIEnv* env, UResourceBundle* gregorian, int* values) {
-
+static bool 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;
     ScopedResourceBundle gregorianElems(ures_getByKey(gregorian, "DateTimeElements", NULL, &status));
     if (U_FAILURE(status)) {
-        return;
+        return false;
     }
 
     int intVectSize;
     const int* result = ures_getIntVector(gregorianElems.get(), &intVectSize, &status);
     if (U_FAILURE(status) || intVectSize != 2) {
-        return;
+        return false;
     }
+
     values[0] = result[0];
     values[1] = result[1];
+    return true;
 }
 
 static jobjectArray getAmPmMarkers(JNIEnv* env, UResourceBundle* gregorian) {
@@ -556,456 +546,139 @@
     return env->NewString(patternChars, 10);
 }
 
-static jstring getIntCurrencyCode(JNIEnv* env, jclass clazz, jstring locale) {
+static jstring getIntCurrencyCode(JNIEnv* env, jstring locale) {
     const char* locStr = env->GetStringUTFChars(locale, NULL);
-    char country[3] = {0,0,0};
 
-    // getting the 2 character country name
-    if(strlen(locStr) < 5) {
+    // Extract the 2-character country name.
+    if (strlen(locStr) < 5) {
         env->ReleaseStringUTFChars(locale, locStr);
         return NULL;
     }
-    if(locStr[3] < 'A' || locStr[3] > 'Z' || locStr[4] < 'A' || locStr[4] > 'Z') {
+    if (locStr[3] < 'A' || locStr[3] > 'Z' || locStr[4] < 'A' || locStr[4] > 'Z') {
         env->ReleaseStringUTFChars(locale, locStr);
         return NULL;
     }
+
+    char country[3] = {0,0,0};
     country[0] = locStr[3];
     country[1] = locStr[4];
 
     env->ReleaseStringUTFChars(locale, locStr);
 
-    return getCurrencyCodeNative(env, clazz, env->NewStringUTF(country));
+    return getCurrencyCodeNative(env, NULL, env->NewStringUTF(country));
 }
 
-static jobjectArray getContentImpl(JNIEnv* env, jclass clazz, jstring locale) {
+static void setIntegerField(JNIEnv* env, jobject obj, const char* fieldName, int value) {
+    // Convert our int to a java.lang.Integer.
+    // TODO: switch to Integer.valueOf, add error checking.
+    jclass integerClass = env->FindClass("java/lang/Integer");
+    jmethodID constructor = env->GetMethodID(integerClass, "<init>", "(I)V");
+    jobject integerValue = env->NewObject(integerClass, constructor, value);
+    // Set the field.
+    jclass localeDataClass = env->FindClass("com/ibm/icu4jni/util/LocaleData");
+    jfieldID fid = env->GetFieldID(localeDataClass, fieldName, "Ljava/lang/Integer;");
+    env->SetObjectField(obj, fid, integerValue);
+}
+
+static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, jstring value) {
+    jclass localeDataClass = env->FindClass("com/ibm/icu4jni/util/LocaleData");
+    jfieldID fid = env->GetFieldID(localeDataClass, fieldName, "Ljava/lang/String;");
+    env->SetObjectField(obj, fid, value);
+}
+
+static void setStringArrayField(JNIEnv* env, jobject obj, const char* fieldName, jobjectArray value) {
+    jclass localeDataClass = env->FindClass("com/ibm/icu4jni/util/LocaleData");
+    jfieldID fid = env->GetFieldID(localeDataClass, fieldName, "[Ljava/lang/String;");
+    env->SetObjectField(obj, fid, value);
+}
+
+static void setStringField(JNIEnv* env, jobject obj, const char* fieldName, UResourceBundle* bundle, int index) {
+    UErrorCode status = U_ZERO_ERROR;
+    int charCount;
+    const UChar* chars = ures_getStringByIndex(bundle, index, &charCount, &status);
+    if (U_SUCCESS(status)) {
+        setStringField(env, obj, fieldName, env->NewString(chars, charCount));
+    }
+}
+
+static jboolean initLocaleDataImpl(JNIEnv* env, jclass clazz, jstring locale, jobject localeData) {
     const char* loc = env->GetStringUTFChars(locale, NULL);
     UErrorCode status = U_ZERO_ERROR;
-    UResourceBundle* root = ures_openU(NULL, loc, &status);
+    ScopedResourceBundle root(ures_openU(NULL, loc, &status));
     env->ReleaseStringUTFChars(locale, loc);
     if (U_FAILURE(status)) {
-        LOGE("Error getting resources: %s", u_errorName(status));
+        LOGE("Error getting ICU resource bundle: %s", u_errorName(status));
         status = U_ZERO_ERROR;
-        return NULL;
+        return JNI_FALSE;
     }
 
-    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");
-    jobjectArray result;
+    ScopedResourceBundle calendar(ures_getByKey(root.get(), "calendar", NULL, &status));
+    if (U_FAILURE(status)) {
+        return JNI_FALSE;
+    }
 
-    jobject firstDayOfWeek = NULL;
-    jobject minimalDaysInFirstWeek = NULL;
-    jobjectArray amPmMarkers = NULL;
-    jobjectArray eras = NULL;
-    jobjectArray weekdays = NULL;
-    jobjectArray shortWeekdays = NULL;
-    jobjectArray months = NULL;
-    jobjectArray shortMonths = NULL;
-    jstring time_SHORT = NULL;
-    jstring time_MEDIUM = NULL;
-    jstring time_LONG = NULL;
-    jstring time_FULL = NULL;
-    jstring date_SHORT = NULL;
-    jstring date_MEDIUM = NULL;
-    jstring date_LONG = NULL;
-    jstring date_FULL = NULL;
-    jstring decimalPatternChars = NULL;
-    jstring naN = NULL;
-    jstring infinity = NULL;
+    ScopedResourceBundle gregorian(ures_getByKey(calendar.get(), "gregorian", NULL, &status));
+    if (U_FAILURE(status)) {
+        return JNI_FALSE;
+    }
+
+    int firstDayVals[2];
+    if (getDayIntVector(env, gregorian.get(), firstDayVals)) {
+        setIntegerField(env, localeData, "firstDayOfWeek", firstDayVals[0]);
+        setIntegerField(env, localeData, "minimalDaysInFirstWeek", firstDayVals[1]);
+    }
+
+    setStringArrayField(env, localeData, "amPm", getAmPmMarkers(env, gregorian.get()));
+    setStringArrayField(env, localeData, "eras", getEras(env, gregorian.get()));
+
+    setStringArrayField(env, localeData, "longMonthNames", getLongMonthNames(env, gregorian.get()));
+    setStringArrayField(env, localeData, "shortMonthNames", getShortMonthNames(env, gregorian.get()));
+    setStringArrayField(env, localeData, "longWeekdayNames", getLongWeekdayNames(env, gregorian.get()));
+    setStringArrayField(env, localeData, "shortWeekdayNames", getShortWeekdayNames(env, gregorian.get()));
+
+    ScopedResourceBundle gregorianElems(ures_getByKey(gregorian.get(), "DateTimePatterns", NULL, &status));
+    if (U_SUCCESS(status)) {
+        setStringField(env, localeData, "fullTimeFormat", gregorianElems.get(), 0);
+        setStringField(env, localeData, "longTimeFormat", gregorianElems.get(), 1);
+        setStringField(env, localeData, "mediumTimeFormat", gregorianElems.get(), 2);
+        setStringField(env, localeData, "shortTimeFormat", gregorianElems.get(), 3);
+        setStringField(env, localeData, "fullDateFormat", gregorianElems.get(), 4);
+        setStringField(env, localeData, "longDateFormat", gregorianElems.get(), 5);
+        setStringField(env, localeData, "mediumDateFormat", gregorianElems.get(), 6);
+        setStringField(env, localeData, "shortDateFormat", gregorianElems.get(), 7);
+    }
+    status = U_ZERO_ERROR;
+
+    ScopedResourceBundle numberElements(ures_getByKey(root.get(), "NumberElements", NULL, &status));
+    if (U_SUCCESS(status) && ures_getSize(numberElements.get()) >= 11) {
+        setStringField(env, localeData, "decimalPatternChars", getDecimalPatternChars(env, numberElements.get()));
+        setStringField(env, localeData, "infinity", numberElements.get(), 9);
+        setStringField(env, localeData, "NaN", numberElements.get(), 10);
+    }
+    status = U_ZERO_ERROR;
+
+    jstring internationalCurrencySymbol = getIntCurrencyCode(env, locale);
     jstring currencySymbol = NULL;
-    jstring intCurrencySymbol = NULL;
-    jstring numberPattern = NULL;
-    jstring integerPattern = NULL;
-    jstring currencyPattern = NULL;
-    jstring percentPattern = NULL;
-    jobjectArray zones = NULL;
-
-    int counter = 0;
-
-
-    const jchar* nan = NULL;
-    const jchar* inf = NULL;
-    int nanL, infL;
-
-
-    UResourceBundle* gregorian;
-    UResourceBundle* gregorianElems;
-    UResourceBundle* rootElems;
-
-
-
-
-    // get the resources needed
-    rootElems = ures_getByKey(root, "calendar", NULL, &status);
-    if(U_FAILURE(status)) {
-        return NULL;
-    }
-
-    gregorian = ures_getByKey(rootElems, "gregorian", NULL, &status);
-    if(U_FAILURE(status)) {
-        ures_close(rootElems);
-        return NULL;
-    }
-
-
-
-    // adding the first day of week and minimal days in first week values
-    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]);
-        // adding First_Day and Minimal_Days integer to the result
-        counter += 2;
-    }
-
-
-    // adding ampm string array to the result");
-    amPmMarkers = getAmPmMarkers(env, gregorian);
-    if(amPmMarkers != NULL) {
-        counter++;
-    }
-
-
-    // adding eras string array to the result
-    eras = getEras(env, gregorian);
-    if(eras != NULL) {
-        counter++;
-    }
-
-
-    // adding month names string array to the result
-    months = getLongMonthNames(env, gregorian);
-    if(months != NULL) {
-        counter++;
-    }
-
-
-    // adding short month names string array to the result
-    shortMonths = getShortMonthNames(env, gregorian);
-    if(shortMonths != NULL) {
-        counter++;
-    }
-
-
-    // adding day names string array to the result
-    weekdays = getLongWeekdayNames(env, gregorian);
-    if(weekdays != NULL) {
-        counter++;
-    }
-
-
-    // adding short day names string array to the result
-    shortWeekdays = getShortWeekdayNames(env, gregorian);
-    if(shortWeekdays != NULL) {
-        counter++;
-    }
-
-    const UChar* pattern;
-    jchar check[2] = {0, 0};
-    u_uastrcpy(check, "v");
-    jchar replacement[2] = {0, 0};
-    u_uastrcpy(replacement, "z");
-    jchar* pos;
-    jchar* patternCopy;
-    int patternLength;
-
-    // adding date and time format patterns to the result
-    gregorianElems = ures_getByKey(gregorian, "DateTimePatterns", NULL, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-        goto endOfCalendar;
-    }
-
-    pattern = ures_getStringByIndex(gregorianElems, 0, &patternLength, &status);
-    // there are some patterns in icu that use the pattern character 'v'
-    // java doesn't accept this, so it gets replaced by 'z' which has
-    // about the same result as 'v', the timezone name. 
-    // 'v' -> "PT", 'z' -> "PST", v is the generic timezone and z the standard tz
-    // "vvvv" -> "Pacific Time", "zzzz" -> "Pacific Standard Time"
-    patternCopy = new jchar[patternLength + 1];
-    u_strcpy(patternCopy, pattern);
-    if(U_FAILURE(status)) {
-        delete[] patternCopy;
-        status = U_ZERO_ERROR;
-        goto endOfCalendar;
-    }
-    while((pos = u_strchr(patternCopy, check[0])) != NULL) {
-        u_memset(pos, replacement[0], 1);
-    }
-    time_FULL = env->NewString(patternCopy, patternLength);
-    delete[] patternCopy;
-    counter++;
-
-    pattern = ures_getStringByIndex(gregorianElems, 1, &patternLength, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-        goto endOfCalendar;
-    }
-    time_LONG = env->NewString(pattern, patternLength);
-    counter++;
-
-    pattern = ures_getStringByIndex(gregorianElems, 2, &patternLength, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-        goto endOfCalendar;
-    }
-    time_MEDIUM = env->NewString(pattern, patternLength);
-    counter++;
-
-    pattern = ures_getStringByIndex(gregorianElems, 3, &patternLength, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-        goto endOfCalendar;
-    }
-    time_SHORT = env->NewString(pattern, patternLength);
-    counter++;
-
-    pattern = ures_getStringByIndex(gregorianElems, 4, &patternLength, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-        goto endOfCalendar;
-    }
-    date_FULL = env->NewString(pattern, patternLength);
-    counter++;
-
-    pattern = ures_getStringByIndex(gregorianElems, 5, &patternLength, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-        goto endOfCalendar;
-    }
-    date_LONG = env->NewString(pattern, patternLength);
-    counter++;
-
-    pattern = ures_getStringByIndex(gregorianElems, 6, &patternLength, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-        goto endOfCalendar;
-    }
-    date_MEDIUM = env->NewString(pattern, patternLength);
-    counter++;
-
-    pattern = ures_getStringByIndex(gregorianElems, 7, &patternLength, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-        goto endOfCalendar;
-    }
-    date_SHORT = env->NewString(pattern, patternLength);
-    counter++;
-
-
-endOfCalendar:
-
-    if(gregorianElems != NULL) {
-        ures_close(gregorianElems);
-    }
-    ures_close(gregorian);
-    ures_close(rootElems);
-
-
-    rootElems = ures_getByKey(root, "NumberElements", NULL, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-    }
-
-    if(ures_getSize(rootElems) >= 11) {
-
-        // adding decimal pattern chars to the result
-        decimalPatternChars = getDecimalPatternChars(env, rootElems);
-        if(decimalPatternChars != NULL) {
-            counter++;
-        }
-
-        // adding NaN pattern char to the result
-        nan = ures_getStringByIndex(rootElems, 10, &nanL, &status);
-        if(U_SUCCESS(status)) {
-            naN = env->NewString(nan, nanL);
-            counter++;
-        }
-        status = U_ZERO_ERROR;
-
-        // adding infinity pattern char to the result
-        inf = ures_getStringByIndex(rootElems, 9, &infL, &status);
-        if(U_SUCCESS(status)) {
-            infinity = env->NewString(inf, infL);
-            counter++;
-        }
-        status = U_ZERO_ERROR;
-    }
-
-    ures_close(rootElems);
-
-
-    // adding intl currency code to result
-    intCurrencySymbol = getIntCurrencyCode(env, clazz, locale);
-    if(intCurrencySymbol != NULL) {
-        // adding currency symbol to result
-        currencySymbol = getCurrencySymbolNative(env, clazz, locale, intCurrencySymbol);
-        // TODO: this is broken; the two will never be identical *unless*
-        // they're NULL. Given that string equality is hard here, and this
-        // code has always been broken, does this matter?
-        if (currencySymbol == intCurrencySymbol) {
-            currencySymbol = NULL;
-        }
+    if (internationalCurrencySymbol != NULL) {
+        currencySymbol = getCurrencySymbolNative(env, clazz, locale, internationalCurrencySymbol);
     } else {
-        intCurrencySymbol = env->NewStringUTF("XXX");
+        internationalCurrencySymbol = env->NewStringUTF("XXX");
     }
-    if(currencySymbol == NULL) {
-        // creating a new string explicitly with the UTF-8 encoding of "\u00a4"
+    if (currencySymbol == NULL) {
+        // This is the UTF-8 encoding of U+00A4 (CURRENCY SIGN).
         currencySymbol = env->NewStringUTF("\xc2\xa4");
     }
-    counter += 2;
+    setStringField(env, localeData, "currencySymbol", currencySymbol);
+    setStringField(env, localeData, "internationalCurrencySymbol", internationalCurrencySymbol);
 
-
-    // adding number format patterns to the result
-    int numOfEntries;
-    int decSepOffset;
-    NumberFormat* nf;
-    jchar* tmpPattern;
-
-    rootElems = ures_getByKey(root, "NumberPatterns", NULL, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-        goto zones;
+    ScopedResourceBundle numberPatterns(ures_getByKey(root.get(), "NumberPatterns", NULL, &status));
+    if (U_SUCCESS(status) && ures_getSize(numberPatterns.get()) >= 3) {
+        setStringField(env, localeData, "numberPattern", numberPatterns.get(), 0);
+        setStringField(env, localeData, "currencyPattern", numberPatterns.get(), 1);
+        setStringField(env, localeData, "percentPattern", numberPatterns.get(), 2);
     }
 
-    numOfEntries = ures_getSize(rootElems);
-    if(numOfEntries < 3) {
-        ures_close(rootElems);
-        goto zones;
-    }
-
-    // number pattern
-    pattern = ures_getStringByIndex(rootElems, 0, &patternLength, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-        ures_close(rootElems);
-        goto zones;
-    }
-    numberPattern = env->NewString(pattern, patternLength);
-    counter++;
-
-    // integer pattern derived from number pattern
-    // We need to convert a C string literal to a UChar string for u_strcspn.
-    static const char c_decSep[] = ".";
-    UChar decSep[sizeof(c_decSep)];
-    u_charsToUChars(c_decSep, decSep, sizeof(c_decSep));
-    decSepOffset = u_strcspn(pattern, decSep);
-    tmpPattern = new jchar[decSepOffset + 1];
-    u_strncpy(tmpPattern, pattern, decSepOffset);
-    integerPattern = env->NewString(tmpPattern, decSepOffset);
-    delete[] tmpPattern;
-    counter++;
-
-    // currency pattern
-    pattern = ures_getStringByIndex(rootElems, 1, &patternLength, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-        ures_close(rootElems);
-        goto zones;
-    }
-    currencyPattern = env->NewString(pattern, patternLength);
-    counter++;
-
-    // percent pattern
-    pattern = ures_getStringByIndex(rootElems, 2, &patternLength, &status);
-    if(U_FAILURE(status)) {
-        status = U_ZERO_ERROR;
-        ures_close(rootElems);
-        goto zones;
-    }
-    percentPattern = env->NewString(pattern, patternLength);
-    counter++;
-
-    ures_close(rootElems);
-
-zones:
-
-    ures_close(root);
-
-
-    // collect all content and put it into an array
-    result = env->NewObjectArray(counter, obj_class, NULL);
-
-    int index = 0;
-    if(firstDayOfWeek != NULL && index < counter) {
-        addObject(env, result, "First_Day", firstDayOfWeek, index++);
-    }
-    if(minimalDaysInFirstWeek != NULL && index < counter) {
-        addObject(env, result, "Minimal_Days", minimalDaysInFirstWeek, index++);
-    }
-    if(amPmMarkers != NULL && index < counter) {
-        addObject(env, result, "ampm", amPmMarkers, index++);
-    }
-    if(eras != NULL && index < counter) {
-        addObject(env, result, "eras", eras, index++);
-    }
-    if(weekdays != NULL && index < counter) {
-        addObject(env, result, "weekdays", weekdays, index++);
-    }
-    if(shortWeekdays != NULL && index < counter) {
-        addObject(env, result, "shortWeekdays", shortWeekdays, index++);
-    }
-    if(months != NULL && index < counter) {
-        addObject(env, result, "months", months, index++);
-    }
-    if(shortMonths != NULL && index < counter) {
-        addObject(env, result, "shortMonths", shortMonths, index++);
-    }
-    if(time_SHORT != NULL && index < counter) {
-        addObject(env, result, "Time_SHORT", time_SHORT, index++);
-    }
-    if(time_MEDIUM != NULL && index < counter) {
-        addObject(env, result, "Time_MEDIUM", time_MEDIUM, index++);
-    }
-    if(time_LONG != NULL && index < counter) {
-        addObject(env, result, "Time_LONG", time_LONG, index++);
-    }
-    if(time_FULL != NULL && index < counter) {
-        addObject(env, result, "Time_FULL", time_FULL, index++);
-    }
-    if(date_SHORT != NULL && index < counter) {
-        addObject(env, result, "Date_SHORT", date_SHORT, index++);
-    }
-    if(date_MEDIUM != NULL && index < counter) {
-        addObject(env, result, "Date_MEDIUM", date_MEDIUM, index++);
-    }
-    if(date_LONG != NULL && index < counter) {
-        addObject(env, result, "Date_LONG", date_LONG, index++);
-    }
-    if(date_FULL != NULL && index < counter) {
-        addObject(env, result, "Date_FULL", date_FULL, index++);
-    }
-    if(decimalPatternChars != NULL && index < counter) {
-        addObject(env, result, "DecimalPatternChars", decimalPatternChars, index++);
-    }
-    if(naN != NULL && index < counter) {
-        addObject(env, result, "NaN", naN, index++);
-    }
-    if(infinity != NULL && index < counter) {
-        addObject(env, result, "Infinity", infinity, index++);
-    }
-    if(currencySymbol != NULL && index < counter) {
-        addObject(env, result, "CurrencySymbol", currencySymbol, index++);
-    }
-    if(intCurrencySymbol != NULL && index < counter) {
-        addObject(env, result, "IntCurrencySymbol", intCurrencySymbol, index++);
-    }
-    if(numberPattern != NULL && index < counter) {
-        addObject(env, result, "Number", numberPattern, index++);
-    }
-    if(integerPattern != NULL && index < counter) {
-        addObject(env, result, "Integer", integerPattern, index++);
-    }
-    if(currencyPattern != NULL && index < counter) {
-        addObject(env, result, "Currency", currencyPattern, index++);
-    }
-    if(percentPattern != NULL && index < counter) {
-        addObject(env, result, "Percent", percentPattern, index++);
-    }
-
-    return result;
-
+    return JNI_TRUE;
 }
 
 static JNINativeMethod gMethods[] = {
@@ -1043,9 +716,9 @@
     {"getDisplayTimeZoneNative",
             "(Ljava/lang/String;ZILjava/lang/String;)Ljava/lang/String;",
             (void*) getDisplayTimeZoneNative},
-    {"getContentImpl",
-            "(Ljava/lang/String;)[[Ljava/lang/Object;",
-            (void*) getContentImpl},
+    {"initLocaleDataImpl",
+            "(Ljava/lang/String;Lcom/ibm/icu4jni/util/LocaleData;)Z",
+            (void*) initLocaleDataImpl},
 };
 
 int register_com_ibm_icu4jni_util_Resources(JNIEnv* env) {
diff --git a/libcore/luni/src/main/java/java/util/Calendar.java b/libcore/luni/src/main/java/java/util/Calendar.java
index 3d1f4ad..7f2e92d 100644
--- a/libcore/luni/src/main/java/java/util/Calendar.java
+++ b/libcore/luni/src/main/java/java/util/Calendar.java
@@ -23,6 +23,8 @@
 import java.io.ObjectStreamField;
 import java.io.Serializable;
 
+import com.ibm.icu4jni.util.LocaleData;
+
 /**
  * {@code Calendar} is an abstract base class for converting between a
  * {@code Date} object and a set of integer fields such as
@@ -686,15 +688,9 @@
     protected Calendar(TimeZone timezone, Locale locale) {
         this(timezone);
         // BEGIN android-changed
-        // com.ibm.icu.util.Calendar icuCalendar = com.ibm.icu.util.Calendar
-        //         .getInstance(com.ibm.icu.util.SimpleTimeZone
-        //                 .getTimeZone(timezone.getID()), locale);
-        // setFirstDayOfWeek(icuCalendar.getFirstDayOfWeek());
-        // setMinimalDaysInFirstWeek(icuCalendar.getMinimalDaysInFirstWeek());
-        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());
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+        setFirstDayOfWeek(localeData.firstDayOfWeek.intValue());
+        setMinimalDaysInFirstWeek(localeData.minimalDaysInFirstWeek.intValue());
         // END android-changed
     }
 
diff --git a/libcore/luni/src/main/java/java/util/Currency.java b/libcore/luni/src/main/java/java/util/Currency.java
index 1673455..9ce92f6 100644
--- a/libcore/luni/src/main/java/java/util/Currency.java
+++ b/libcore/luni/src/main/java/java/util/Currency.java
@@ -18,6 +18,7 @@
 package java.util;
 
 // BEGIN android-added
+import com.ibm.icu4jni.util.LocaleData;
 import com.ibm.icu4jni.util.Resources;
 import java.util.logging.Logger;
 import org.apache.harmony.luni.util.Msg;
@@ -163,10 +164,10 @@
             return currencyCode;
         }
 
-        // 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");
+        // Check the locale first, in case the locale has the same currency.
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+        if (localeData.internationalCurrencySymbol.equals(currencyCode)) {
+            return localeData.currencySymbol;
         }
 
         // check if the currency bundle for this locale has an entry for this currency
diff --git a/libcore/text/src/main/java/java/text/DateFormat.java b/libcore/text/src/main/java/java/text/DateFormat.java
index 531bed8..80f38c9 100644
--- a/libcore/text/src/main/java/java/text/DateFormat.java
+++ b/libcore/text/src/main/java/java/text/DateFormat.java
@@ -31,6 +31,7 @@
 // BEGIN android-added
 import java.util.TimeZone;
 
+import com.ibm.icu4jni.util.LocaleData;
 import org.apache.harmony.text.internal.nls.Messages;
 
 /**
@@ -470,9 +471,8 @@
     public final static DateFormat getDateInstance(int style, Locale locale) {
         checkDateStyle(style);
         // BEGIN android-changed
-        ResourceBundle bundle = getBundle(locale);
-        String pattern = bundle.getString("Date_" + getStyleName(style)); //$NON-NLS-1$
-        return new SimpleDateFormat(pattern, locale);
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+        return new SimpleDateFormat(getDateFormat(localeData, style), locale);
         // END android-changed
     }
 
@@ -528,9 +528,8 @@
         checkTimeStyle(timeStyle);
         checkDateStyle(dateStyle);
         // BEGIN android-changed
-        ResourceBundle bundle = getBundle(locale);
-        String pattern = bundle.getString("Date_" + getStyleName(dateStyle)) //$NON-NLS-1$
-                + " " + bundle.getString("Time_" + getStyleName(timeStyle)); //$NON-NLS-1$ //$NON-NLS-2$
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+        String pattern = getDateFormat(localeData, dateStyle) + " " + getTimeFormat(localeData, timeStyle);
         return new SimpleDateFormat(pattern, locale);
         // END android-changed
     }
@@ -555,26 +554,37 @@
         return numberFormat;
     }
 
-    static String getStyleName(int style) {
-        String styleName;
+    // BEGIN android-added
+    protected static String getDateFormat(LocaleData localeData, int style) {
         switch (style) {
-            case SHORT:
-                styleName = "SHORT"; //$NON-NLS-1$
-                break;
-            case MEDIUM:
-                styleName = "MEDIUM"; //$NON-NLS-1$
-                break;
-            case LONG:
-                styleName = "LONG"; //$NON-NLS-1$
-                break;
-            case FULL:
-                styleName = "FULL"; //$NON-NLS-1$
-                break;
-            default:
-                styleName = ""; //$NON-NLS-1$
+        case SHORT:
+            return localeData.shortDateFormat;
+        case MEDIUM:
+            return localeData.mediumDateFormat;
+        case LONG:
+            return localeData.longDateFormat;
+        case FULL:
+            return localeData.fullDateFormat;
         }
-        return styleName;
+        throw new AssertionError();
     }
+    // END android-added
+
+    // BEGIN android-added
+    protected static String getTimeFormat(LocaleData localeData, int style) {
+        switch (style) {
+        case SHORT:
+            return localeData.shortTimeFormat;
+        case MEDIUM:
+            return localeData.mediumTimeFormat;
+        case LONG:
+            return localeData.longTimeFormat;
+        case FULL:
+            return localeData.fullTimeFormat;
+        }
+        throw new AssertionError();
+    }
+    // END android-added
 
     /**
      * Returns a {@code DateFormat} instance for formatting and parsing time
@@ -620,9 +630,8 @@
     public final static DateFormat getTimeInstance(int style, Locale locale) {
         checkTimeStyle(style);
         // BEGIN android-changed
-        ResourceBundle bundle = getBundle(locale);
-        String pattern = bundle.getString("Time_" + getStyleName(style)); //$NON-NLS-1$
-        return new SimpleDateFormat(pattern, locale);
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+        return new SimpleDateFormat(getTimeFormat(localeData, style), locale);
         // END android-changed
     }
 
diff --git a/libcore/text/src/main/java/java/text/DateFormatSymbols.java b/libcore/text/src/main/java/java/text/DateFormatSymbols.java
index e8e1f69..767a301 100644
--- a/libcore/text/src/main/java/java/text/DateFormatSymbols.java
+++ b/libcore/text/src/main/java/java/text/DateFormatSymbols.java
@@ -31,6 +31,7 @@
 // END android-added
 
 // BEGIN android-added
+import com.ibm.icu4jni.util.LocaleData;
 import com.ibm.icu4jni.util.Resources;
 // END android-added
 /**
@@ -121,16 +122,16 @@
      *            the locale.
      */
     public DateFormatSymbols(Locale locale) {
-        // BEGIN android-changed
-        localPatternChars = SimpleDateFormat.patternChars;
-        ResourceBundle bundle = Format.getBundle(locale);
-        ampms = bundle.getStringArray("ampm"); //$NON-NLS-1$
-        eras = bundle.getStringArray("eras"); //$NON-NLS-1$
-        months = bundle.getStringArray("months"); //$NON-NLS-1$
-        shortMonths = bundle.getStringArray("shortMonths"); //$NON-NLS-1$
-        shortWeekdays = bundle.getStringArray("shortWeekdays"); //$NON-NLS-1$
-        weekdays = bundle.getStringArray("weekdays"); //$NON-NLS-1$
         this.locale = locale;
+        // BEGIN android-changed
+        this.localPatternChars = SimpleDateFormat.patternChars;
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+        this.ampms = localeData.amPm;
+        this.eras = localeData.eras;
+        this.months = localeData.longMonthNames;
+        this.shortMonths = localeData.shortMonthNames;
+        this.weekdays = localeData.longWeekdayNames;
+        this.shortWeekdays = localeData.shortWeekdayNames;
         // END android-changed
     }
 
@@ -334,13 +335,8 @@
      */
     public String[][] getZoneStrings() {
         // BEGIN android-changed
-        String[][] zoneStrings = internalZoneStrings();
+        return Resources.clone2dStringArray(internalZoneStrings());
         // END android-changed
-        String[][] clone = new String[zoneStrings.length][];
-        for (int i = zoneStrings.length; --i >= 0;) {
-            clone[i] = zoneStrings[i].clone();
-        }
-        return clone;
     }
 
     @Override
@@ -477,6 +473,6 @@
      *            the two-dimensional array of strings.
      */
     public void setZoneStrings(String[][] data) {
-        zoneStrings = data.clone();
+        zoneStrings = Resources.clone2dStringArray(data);
     }
 }
diff --git a/libcore/text/src/main/java/java/text/DecimalFormat.java b/libcore/text/src/main/java/java/text/DecimalFormat.java
index 7a0f529..480d79d 100644
--- a/libcore/text/src/main/java/java/text/DecimalFormat.java
+++ b/libcore/text/src/main/java/java/text/DecimalFormat.java
@@ -32,6 +32,8 @@
 import java.util.Currency;
 import java.util.Locale;
 
+import com.ibm.icu4jni.util.LocaleData;
+
 /**
  * A concrete subclass of {@link NumberFormat} that formats decimal numbers. It
  * has a variety of features designed to make it possible to parse and format
@@ -565,8 +567,8 @@
         icuSymbols = new com.ibm.icu4jni.text.DecimalFormatSymbols(locale);
         symbols = new DecimalFormatSymbols(locale);
         // BEGIN android-changed
-        dform = new com.ibm.icu4jni.text.DecimalFormat(
-                getPattern(Locale.getDefault(), "Number"), icuSymbols);
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(Locale.getDefault());
+        dform = new com.ibm.icu4jni.text.DecimalFormat(localeData.numberPattern, icuSymbols);
         // END android-changed
 
         super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
diff --git a/libcore/text/src/main/java/java/text/DecimalFormatSymbols.java b/libcore/text/src/main/java/java/text/DecimalFormatSymbols.java
index 46849ef..1a35d0a 100644
--- a/libcore/text/src/main/java/java/text/DecimalFormatSymbols.java
+++ b/libcore/text/src/main/java/java/text/DecimalFormatSymbols.java
@@ -33,6 +33,8 @@
 import java.util.ResourceBundle;
 // END android-added
 
+import com.ibm.icu4jni.util.LocaleData;
+
 /**
  * Encapsulates the set of symbols (such as the decimal separator, the grouping
  * separator, and so on) needed by {@code DecimalFormat} to format numbers.
@@ -82,10 +84,10 @@
      */
     public DecimalFormatSymbols(Locale locale) {
         // BEGIN android-changed
-        ResourceBundle bundle = Format.getBundle(locale);
-        patternChars = bundle.getString("DecimalPatternChars").toCharArray(); //$NON-NLS-1$
-        infinity = bundle.getString("Infinity"); //$NON-NLS-1$
-        NaN = bundle.getString("NaN"); //$NON-NLS-1$
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+        this.patternChars = localeData.decimalPatternChars.toCharArray();
+        this.infinity = localeData.infinity;
+        this.NaN = localeData.NaN;
         this.locale = locale;
         try {
             currency = Currency.getInstance(locale);
@@ -93,8 +95,8 @@
             intlCurrencySymbol = currency.getCurrencyCode();
         } catch (IllegalArgumentException e) {
             currency = Currency.getInstance("XXX"); //$NON-NLS-1$
-            currencySymbol = bundle.getString("CurrencySymbol"); //$NON-NLS-1$
-            intlCurrencySymbol = bundle.getString("IntCurrencySymbol"); //$NON-NLS-1$
+            currencySymbol = localeData.currencySymbol;
+            intlCurrencySymbol = localeData.internationalCurrencySymbol;
         }
         // END android-changed
     }
diff --git a/libcore/text/src/main/java/java/text/Format.java b/libcore/text/src/main/java/java/text/Format.java
index 7660f8e..eb1b837 100644
--- a/libcore/text/src/main/java/java/text/Format.java
+++ b/libcore/text/src/main/java/java/text/Format.java
@@ -88,12 +88,6 @@
         }
     }
 
-    // BEGIN android-added
-    static ResourceBundle getBundle(Locale locale) {
-        return com.ibm.icu4jni.util.Resources.getLocaleInstance(locale);
-    }
-    // END android-added
-
     String convertPattern(String template, String fromChars, String toChars,
             boolean check) {
         if (!check && fromChars.equals(toChars)) {
diff --git a/libcore/text/src/main/java/java/text/NumberFormat.java b/libcore/text/src/main/java/java/text/NumberFormat.java
index 23b0e27..ecf4483 100644
--- a/libcore/text/src/main/java/java/text/NumberFormat.java
+++ b/libcore/text/src/main/java/java/text/NumberFormat.java
@@ -32,6 +32,7 @@
 import java.util.ResourceBundle;
 // END android-added
 
+import com.ibm.icu4jni.util.LocaleData;
 import org.apache.harmony.text.internal.nls.Messages;
 
 /**
@@ -356,7 +357,8 @@
      */
     public static NumberFormat getCurrencyInstance(Locale locale) {
         // BEGIN android-changed
-        return getInstance(locale, "Currency"); //$NON-NLS-1$
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+        return getInstance(locale, localeData.currencyPattern);
         // END android-changed
     }
 
@@ -380,9 +382,10 @@
      */
     public static NumberFormat getIntegerInstance(Locale locale) {
         // BEGIN android-changed
-        NumberFormat format = getInstance(locale, "Integer"); //$NON-NLS-1$
-        format.setParseIntegerOnly(true);
-        return format;
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+        NumberFormat result = getInstance(locale, localeData.integerPattern);
+        result.setParseIntegerOnly(true);
+        return result;
         // END android-changed
     }
 
@@ -409,9 +412,8 @@
     }
 
     // BEGIN android-added
-    static NumberFormat getInstance(Locale locale, String type) {
-        return new DecimalFormat(getPattern(locale, type),
-                new DecimalFormatSymbols(locale));
+    private static NumberFormat getInstance(Locale locale, String pattern) {
+        return new DecimalFormat(pattern, new DecimalFormatSymbols(locale));
     }
     // END android-added
 
@@ -477,17 +479,11 @@
      */
     public static NumberFormat getNumberInstance(Locale locale) {
         // BEGIN android-changed
-        return getInstance(locale, "Number"); //$NON-NLS-1$
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+        return getInstance(locale, localeData.numberPattern);
         // END android-changed
     }
 
-    // BEGIN android-added
-    static String getPattern(Locale locale, String type) {
-        ResourceBundle bundle = getBundle(locale);
-        return bundle.getString(type);
-    }
-    // END android-added
-
     /**
      * Returns a {@code NumberFormat} for formatting and parsing percentage
      * values for the default locale.
@@ -508,7 +504,8 @@
      */
     public static NumberFormat getPercentInstance(Locale locale) {
         // BEGIN android-changed
-        return getInstance(locale, "Percent"); //$NON-NLS-1$
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+        return getInstance(locale, localeData.percentPattern);
         // END android-changed
     }
 
diff --git a/libcore/text/src/main/java/java/text/SimpleDateFormat.java b/libcore/text/src/main/java/java/text/SimpleDateFormat.java
index 47ff930..9f54ba1 100644
--- a/libcore/text/src/main/java/java/text/SimpleDateFormat.java
+++ b/libcore/text/src/main/java/java/text/SimpleDateFormat.java
@@ -36,6 +36,7 @@
 // END android-added
 import java.util.Vector;
 
+import com.ibm.icu4jni.util.LocaleData;
 import org.apache.harmony.text.internal.nls.Messages;
 
 /**
@@ -618,10 +619,8 @@
 
     // BEGIN android-added
     private static String defaultPattern() {
-        ResourceBundle bundle = getBundle(Locale.getDefault());
-        String styleName = getStyleName(SHORT);
-        return bundle.getString("Date_" + styleName) + " " //$NON-NLS-1$ //$NON-NLS-2$
-                + bundle.getString("Time_" + styleName); //$NON-NLS-1$
+        LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(Locale.getDefault());
+        return getDateFormat(localeData, SHORT) + " " + getTimeFormat(localeData, SHORT);
     }
     // END android-added