summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2014-05-29 17:41:25 -0700
committerNarayan Kamath <narayan@google.com>2014-06-16 11:47:41 +0100
commita94266074c7b82720fd2cecfb37ab8da85f1b296 (patch)
tree3a0b903bb2bbaaeb4fb8360deeb35eccabee2e9e
parentf577d7594f3acc1d97e119c508e8e4edfeb1f20b (diff)
downloadlibcore-a94266074c7b82720fd2cecfb37ab8da85f1b296.zip
libcore-a94266074c7b82720fd2cecfb37ab8da85f1b296.tar.gz
libcore-a94266074c7b82720fd2cecfb37ab8da85f1b296.tar.bz2
Pass BCP-47 tags and not Locale.toString results to ICU.
ICU can't handle the new toString forms for scripts etc. and it's also guaranteed to deal with BCP-47 tags correctly. Most of the changes in this patch are required to keep backwards compatibility for getDisplayCountry string etc. in the face of the transformations toLanguageTag performs. A few tests were changed, but for the better. The tagalog -> filipino charlie foxtrot will be dealt with in a follow up change. Co-Authored-By: Narayan Kamath <narayan@google.com> Change-Id: Ia7f26d92a0e38c4bbb1d839c0fbd8ad16a473bf5
-rw-r--r--benchmarks/src/benchmarks/regression/IcuBenchmark.java2
-rw-r--r--benchmarks/src/benchmarks/regression/StringCaseMappingBenchmark.java4
-rw-r--r--include/ScopedIcuLocale.h62
-rw-r--r--luni/src/main/java/java/lang/CaseMapper.java8
-rw-r--r--luni/src/main/java/java/text/BreakIterator.java35
-rw-r--r--luni/src/main/java/java/util/Currency.java6
-rw-r--r--luni/src/main/java/java/util/Locale.java111
-rw-r--r--luni/src/main/java/libcore/icu/ICU.java143
-rw-r--r--luni/src/main/java/libcore/icu/LocaleData.java4
-rw-r--r--luni/src/main/java/libcore/icu/NativeBreakIterator.java18
-rw-r--r--luni/src/main/java/libcore/icu/NativeCollation.java7
-rw-r--r--luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java2
-rw-r--r--luni/src/main/native/IcuUtilities.cpp4
-rw-r--r--luni/src/main/native/IcuUtilities.h2
-rw-r--r--luni/src/main/native/libcore_icu_AlphabeticIndex.cpp17
-rw-r--r--luni/src/main/native/libcore_icu_DateIntervalFormat.cpp8
-rw-r--r--luni/src/main/native/libcore_icu_ICU.cpp195
-rw-r--r--luni/src/main/native/libcore_icu_NativeBreakIterator.cpp18
-rw-r--r--luni/src/main/native/libcore_icu_NativeCollation.cpp5
-rw-r--r--luni/src/main/native/libcore_icu_TimeZoneNames.cpp19
-rw-r--r--luni/src/test/java/libcore/icu/ICUTest.java107
-rw-r--r--luni/src/test/java/libcore/java/util/LocaleTest.java23
22 files changed, 511 insertions, 289 deletions
diff --git a/benchmarks/src/benchmarks/regression/IcuBenchmark.java b/benchmarks/src/benchmarks/regression/IcuBenchmark.java
index ee8270a..2aed36b 100644
--- a/benchmarks/src/benchmarks/regression/IcuBenchmark.java
+++ b/benchmarks/src/benchmarks/regression/IcuBenchmark.java
@@ -26,7 +26,7 @@ import libcore.icu.ICU;
public class IcuBenchmark extends SimpleBenchmark {
public void time_getBestDateTimePattern(int reps) throws Exception {
for (int rep = 0; rep < reps; ++rep) {
- ICU.getBestDateTimePattern("dEEEMMM", "US");
+ ICU.getBestDateTimePattern("dEEEMMM", new Locale("en", "US"));
}
}
}
diff --git a/benchmarks/src/benchmarks/regression/StringCaseMappingBenchmark.java b/benchmarks/src/benchmarks/regression/StringCaseMappingBenchmark.java
index cde257b..ae6b6b6 100644
--- a/benchmarks/src/benchmarks/regression/StringCaseMappingBenchmark.java
+++ b/benchmarks/src/benchmarks/regression/StringCaseMappingBenchmark.java
@@ -106,13 +106,13 @@ public class StringCaseMappingBenchmark extends SimpleBenchmark {
public void timeToUpperCase_ICU(int reps) {
for (int i = 0; i < reps; ++i) {
- libcore.icu.ICU.toUpperCase(s.value, Locale.US.toString());
+ libcore.icu.ICU.toUpperCase(s.value, Locale.US);
}
}
public void timeToLowerCase_ICU(int reps) {
for (int i = 0; i < reps; ++i) {
- libcore.icu.ICU.toLowerCase(s.value, Locale.US.toString());
+ libcore.icu.ICU.toLowerCase(s.value, Locale.US);
}
}
diff --git a/include/ScopedIcuLocale.h b/include/ScopedIcuLocale.h
new file mode 100644
index 0000000..2109e03
--- /dev/null
+++ b/include/ScopedIcuLocale.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef SCOPED_ICU_LOCALE_H_included
+#define SCOPED_ICU_LOCALE_H_included
+
+#include "JNIHelp.h"
+#include "ScopedUtfChars.h"
+#include "unicode/locid.h"
+
+class ScopedIcuLocale {
+ public:
+ ScopedIcuLocale(JNIEnv* env, jstring javaLocaleName) : mEnv(env) {
+ mLocale.setToBogus();
+
+ if (javaLocaleName == NULL) {
+ jniThrowNullPointerException(mEnv, "javaLocaleName == null");
+ return;
+ }
+
+ const ScopedUtfChars localeName(env, javaLocaleName);
+ if (localeName.c_str() == NULL) {
+ return;
+ }
+
+ mLocale = Locale::createFromName(localeName.c_str());
+ }
+
+ ~ScopedIcuLocale() {
+ }
+
+ bool valid() const {
+ return !mLocale.isBogus();
+ }
+
+ Locale& locale() {
+ return mLocale;
+ }
+
+ private:
+ JNIEnv* const mEnv;
+ Locale mLocale;
+
+ // Disallow copy and assignment.
+ ScopedIcuLocale(const ScopedIcuLocale&);
+ void operator=(const ScopedIcuLocale&);
+};
+
+#endif // SCOPED_ICU_LOCALE_H_included
diff --git a/luni/src/main/java/java/lang/CaseMapper.java b/luni/src/main/java/java/lang/CaseMapper.java
index 4e411d1..1da621c 100644
--- a/luni/src/main/java/java/lang/CaseMapper.java
+++ b/luni/src/main/java/java/lang/CaseMapper.java
@@ -49,7 +49,7 @@ class CaseMapper {
// Note that Greek isn't a particularly hard case for toLowerCase, only toUpperCase.
String languageCode = locale.getLanguage();
if (languageCode.equals("tr") || languageCode.equals("az") || languageCode.equals("lt")) {
- return ICU.toLowerCase(s, locale.toString());
+ return ICU.toLowerCase(s, locale);
}
char[] newValue = null;
@@ -59,7 +59,7 @@ class CaseMapper {
char newCh;
if (ch == LATIN_CAPITAL_I_WITH_DOT || Character.isHighSurrogate(ch)) {
// Punt these hard cases.
- return ICU.toLowerCase(s, locale.toString());
+ return ICU.toLowerCase(s, locale);
} else if (ch == GREEK_CAPITAL_SIGMA && isFinalSigma(value, offset, count, i)) {
newCh = GREEK_SMALL_FINAL_SIGMA;
} else {
@@ -150,7 +150,7 @@ class CaseMapper {
public static String toUpperCase(Locale locale, String s, char[] value, int offset, int count) {
String languageCode = locale.getLanguage();
if (languageCode.equals("tr") || languageCode.equals("az") || languageCode.equals("lt")) {
- return ICU.toUpperCase(s, locale.toString());
+ return ICU.toUpperCase(s, locale);
}
if (languageCode.equals("el")) {
return EL_UPPER.get().transliterate(s);
@@ -161,7 +161,7 @@ class CaseMapper {
for (int o = offset, end = offset + count; o < end; o++) {
char ch = value[o];
if (Character.isHighSurrogate(ch)) {
- return ICU.toUpperCase(s, locale.toString());
+ return ICU.toUpperCase(s, locale);
}
int index = upperIndex(ch);
if (index == -1) {
diff --git a/luni/src/main/java/java/text/BreakIterator.java b/luni/src/main/java/java/text/BreakIterator.java
index b14647c..81545b2 100644
--- a/luni/src/main/java/java/text/BreakIterator.java
+++ b/luni/src/main/java/java/text/BreakIterator.java
@@ -268,13 +268,9 @@ public abstract class BreakIterator implements Cloneable {
/**
* Returns a new instance of {@code BreakIterator} to iterate over
* characters using the given locale.
- *
- * @param where
- * the given locale.
- * @return a new instance of {@code BreakIterator} using the given locale.
*/
- public static BreakIterator getCharacterInstance(Locale where) {
- return new RuleBasedBreakIterator(NativeBreakIterator.getCharacterInstance(where));
+ public static BreakIterator getCharacterInstance(Locale locale) {
+ return new RuleBasedBreakIterator(NativeBreakIterator.getCharacterInstance(locale));
}
/**
@@ -290,14 +286,9 @@ public abstract class BreakIterator implements Cloneable {
/**
* Returns a new instance of {@code BreakIterator} to iterate over
* line breaks using the given locale.
- *
- * @param where
- * the given locale.
- * @return a new instance of {@code BreakIterator} using the given locale.
- * @throws NullPointerException if {@code where} is {@code null}.
*/
- public static BreakIterator getLineInstance(Locale where) {
- return new RuleBasedBreakIterator(NativeBreakIterator.getLineInstance(where));
+ public static BreakIterator getLineInstance(Locale locale) {
+ return new RuleBasedBreakIterator(NativeBreakIterator.getLineInstance(locale));
}
/**
@@ -313,14 +304,9 @@ public abstract class BreakIterator implements Cloneable {
/**
* Returns a new instance of {@code BreakIterator} to iterate over
* sentence-breaks using the given locale.
- *
- * @param where
- * the given locale.
- * @return a new instance of {@code BreakIterator} using the given locale.
- * @throws NullPointerException if {@code where} is {@code null}.
*/
- public static BreakIterator getSentenceInstance(Locale where) {
- return new RuleBasedBreakIterator(NativeBreakIterator.getSentenceInstance(where));
+ public static BreakIterator getSentenceInstance(Locale locale) {
+ return new RuleBasedBreakIterator(NativeBreakIterator.getSentenceInstance(locale));
}
/**
@@ -336,14 +322,9 @@ public abstract class BreakIterator implements Cloneable {
/**
* Returns a new instance of {@code BreakIterator} to iterate over
* word-breaks using the given locale.
- *
- * @param where
- * the given locale.
- * @return a new instance of {@code BreakIterator} using the given locale.
- * @throws NullPointerException if {@code where} is {@code null}.
*/
- public static BreakIterator getWordInstance(Locale where) {
- return new RuleBasedBreakIterator(NativeBreakIterator.getWordInstance(where));
+ public static BreakIterator getWordInstance(Locale locale) {
+ return new RuleBasedBreakIterator(NativeBreakIterator.getWordInstance(locale));
}
/**
diff --git a/luni/src/main/java/java/util/Currency.java b/luni/src/main/java/java/util/Currency.java
index e8ecdde..a535bc7 100644
--- a/luni/src/main/java/java/util/Currency.java
+++ b/luni/src/main/java/java/util/Currency.java
@@ -35,7 +35,7 @@ public final class Currency implements Serializable {
private Currency(String currencyCode) {
this.currencyCode = currencyCode;
- String symbol = ICU.getCurrencySymbol(Locale.US.toString(), currencyCode);
+ String symbol = ICU.getCurrencySymbol(Locale.US, currencyCode);
if (symbol == null) {
throw new IllegalArgumentException("Unsupported ISO 4217 currency code: " +
currencyCode);
@@ -123,7 +123,7 @@ public final class Currency implements Serializable {
* @since 1.7
*/
public String getDisplayName(Locale locale) {
- return ICU.getCurrencyDisplayName(locale.toString(), currencyCode);
+ return ICU.getCurrencyDisplayName(locale, currencyCode);
}
/**
@@ -168,7 +168,7 @@ public final class Currency implements Serializable {
}
// Try ICU, and fall back to the currency code if ICU has nothing.
- String symbol = ICU.getCurrencySymbol(locale.toString(), currencyCode);
+ String symbol = ICU.getCurrencySymbol(locale, currencyCode);
return symbol != null ? symbol : currencyCode;
}
diff --git a/luni/src/main/java/java/util/Locale.java b/luni/src/main/java/java/util/Locale.java
index 5f24138..b59385b 100644
--- a/luni/src/main/java/java/util/Locale.java
+++ b/luni/src/main/java/java/util/Locale.java
@@ -782,7 +782,8 @@ public final class Locale implements Cloneable, Serializable {
/**
* Returns a locale for a given BCP-47 language tag. This method is more
* lenient than {@link Builder#setLanguageTag}. For a given language tag, parsing
- * will proceed upto the first malformed subtag. All subsequent tags are discarded.
+ * will proceed up to the first malformed subtag. All subsequent tags are discarded.
+ * Note that language tags use {@code -} rather than {@code _}, for example {@code en-US}.
*
* @throws NullPointerException if {@code languageTag} is {@code null}.
*
@@ -891,17 +892,14 @@ public final class Locale implements Cloneable, Serializable {
if (hasValidatedFields) {
Set<String> attribsCopy = new TreeSet<String>(unicodeAttributes);
- Map<String, String> keywordsCopy = new TreeMap<String, String>(
- unicodeKeywords);
- Map<Character, String> extensionsCopy = new TreeMap<Character, String>(
- extensions);
+ Map<String, String> keywordsCopy = new TreeMap<String, String>(unicodeKeywords);
+ Map<Character, String> extensionsCopy = new TreeMap<Character, String>(extensions);
// We need to transform the list of attributes & keywords set on the
// builder to a unicode locale extension. i.e, if we have any keywords
// or attributes set, Locale#getExtension('u') should return a well
// formed extension.
- addUnicodeExtensionToExtensionsMap(attribsCopy, keywordsCopy,
- extensionsCopy);
+ addUnicodeExtensionToExtensionsMap(attribsCopy, keywordsCopy, extensionsCopy);
this.unicodeAttributes = Collections.unmodifiableSet(attribsCopy);
this.unicodeKeywords = Collections.unmodifiableMap(keywordsCopy);
@@ -1006,10 +1004,16 @@ public final class Locale implements Cloneable, Serializable {
if (countryCode.isEmpty()) {
return "";
}
- String result = ICU.getDisplayCountryNative(getIcuLocaleId(), locale.getIcuLocaleId());
+
+ try {
+ Builder.normalizeAndValidateRegion(countryCode);
+ } catch (IllformedLocaleException ex) {
+ return countryCode;
+ }
+
+ String result = ICU.getDisplayCountry(this, locale);
if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
- result = ICU.getDisplayCountryNative(getIcuLocaleId(),
- Locale.getDefault().getIcuLocaleId());
+ result = ICU.getDisplayCountry(this, Locale.getDefault());
}
return result;
}
@@ -1030,19 +1034,24 @@ public final class Locale implements Cloneable, Serializable {
return "";
}
- // http://b/8049507 --- frameworks/base should use fil_PH instead of tl_PH.
- // Until then, we're stuck covering their tracks, making it look like they're
- // using "fil" when they're not.
- String localeString = toString();
- if (languageCode.equals("tl")) {
- localeString = toNewString("fil", countryCode, variantCode, scriptCode,
- extensions);
+ // Hacks for backward compatibility.
+ //
+ // Our language tag will contain "und" if the languageCode is invalid
+ // or missing. ICU will then return "langue indéterminée" or the equivalent
+ // display language for the indeterminate language code.
+ //
+ // Sigh... ugh... and what not.
+ try {
+ Builder.normalizeAndValidateLanguage(languageCode);
+ } catch (IllformedLocaleException ex) {
+ return languageCode;
}
- String result = ICU.getDisplayLanguageNative(localeString, locale.getIcuLocaleId());
+ // TODO: We need a new hack or a complete fix for http://b/8049507 --- We would
+ // cover the frameworks' tracks when they were using "tl" instead of "fil".
+ String result = ICU.getDisplayLanguage(this, locale);
if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
- result = ICU.getDisplayLanguageNative(localeString,
- Locale.getDefault().getIcuLocaleId());
+ result = ICU.getDisplayLanguage(this, Locale.getDefault());
}
return result;
}
@@ -1127,13 +1136,27 @@ public final class Locale implements Cloneable, Serializable {
* returned.
*/
public String getDisplayVariant(Locale locale) {
- if (variantCode.length() == 0) {
+ if (variantCode.isEmpty()) {
+ return "";
+ }
+
+ try {
+ Builder.normalizeAndValidateVariant(variantCode);
+ } catch (IllformedLocaleException ilfe) {
return variantCode;
}
- String result = ICU.getDisplayVariantNative(getIcuLocaleId(), locale.getIcuLocaleId());
+
+ String result = ICU.getDisplayVariant(this, locale);
if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
- result = ICU.getDisplayVariantNative(getIcuLocaleId(),
- Locale.getDefault().getIcuLocaleId());
+ result = ICU.getDisplayVariant(this, Locale.getDefault());
+ }
+
+ // The "old style" locale constructors allow us to pass in variants that aren't
+ // valid BCP-47 variant subtags. When that happens, toLanguageTag will not emit
+ // them. Note that we know variantCode.length() > 0 due to the isEmpty check at
+ // the beginning of this function.
+ if (result.isEmpty()) {
+ return variantCode;
}
return result;
}
@@ -1144,7 +1167,7 @@ public final class Locale implements Cloneable, Serializable {
* @throws MissingResourceException if there's no 3-letter country code for this locale.
*/
public String getISO3Country() {
- String code = ICU.getISO3CountryNative(getIcuLocaleId());
+ String code = ICU.getISO3Country(this);
if (!countryCode.isEmpty() && code.isEmpty()) {
throw new MissingResourceException("No 3-letter country code for locale: " + this, "FormatData_" + this, "ShortCountry");
}
@@ -1157,7 +1180,15 @@ public final class Locale implements Cloneable, Serializable {
* @throws MissingResourceException if there's no 3-letter language code for this locale.
*/
public String getISO3Language() {
- String code = ICU.getISO3LanguageNative(getIcuLocaleId());
+ // For backward compatibility, we must return "" for an empty language
+ // code and not "und" which is the accurate ISO-639-3 code for an
+ // undetermined language.
+ if (languageCode.isEmpty()) {
+ return "";
+ }
+
+ String code = ICU.getISO3Language(this);
+
if (!languageCode.isEmpty() && code.isEmpty()) {
throw new MissingResourceException("No 3-letter language code for locale: " + this, "FormatData_" + this, "ShortLanguage");
}
@@ -1233,10 +1264,9 @@ public final class Locale implements Cloneable, Serializable {
return "";
}
- String result = ICU.getDisplayScriptNative(getIcuLocaleId(), locale.getIcuLocaleId());
+ String result = ICU.getDisplayScript(this, locale);
if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
- result = ICU.getDisplayScriptNative(getIcuLocaleId(),
- Locale.getDefault().getIcuLocaleId());
+ result = ICU.getDisplayScript(this, Locale.getDefault());
}
return result;
@@ -1257,7 +1287,7 @@ public final class Locale implements Cloneable, Serializable {
* where they will appear after a subtag whose value is {@code "lvariant"}.
*
* It's also important to note that the BCP-47 tag is well formed in the sense
- * that it is unambiguously parsable into its specified components. We do not
+ * that it is unambiguously parseable into its specified components. We do not
* require that any of the components are registered with the applicable registries.
* For example, we do not require scripts to be a registered ISO 15924 scripts or
* languages to appear in the ISO-639-2 code list.
@@ -1558,8 +1588,9 @@ public final class Locale implements Cloneable, Serializable {
if (locale == null) {
throw new NullPointerException("locale == null");
}
+ String languageTag = locale.toLanguageTag();
defaultLocale = locale;
- ICU.setDefaultLocale(ICU.localeIdFromLocale(locale));
+ ICU.setDefaultLocale(languageTag);
}
/**
@@ -1577,20 +1608,12 @@ public final class Locale implements Cloneable, Serializable {
public final String toString() {
String result = cachedToStringResult;
if (result == null) {
- result = cachedToStringResult = toNewString(languageCode, countryCode,
- variantCode, scriptCode, extensions);
+ result = cachedToStringResult = toNewString(languageCode, countryCode, variantCode,
+ scriptCode, extensions);
}
return result;
}
- private String getIcuLocaleId() {
- if (cachedIcuLocaleId == null) {
- cachedIcuLocaleId = ICU.localeIdFromLocale(this);
- }
-
- return cachedIcuLocaleId;
- }
-
private static String toNewString(String languageCode, String countryCode,
String variantCode, String scriptCode, Map<Character, String> extensions) {
// The string form of a locale that only has a variant is the empty string.
@@ -1605,8 +1628,7 @@ public final class Locale implements Cloneable, Serializable {
StringBuilder result = new StringBuilder(11);
result.append(languageCode);
- final boolean hasScriptOrExtensions = !scriptCode.isEmpty() ||
- !extensions.isEmpty();
+ final boolean hasScriptOrExtensions = !scriptCode.isEmpty() || !extensions.isEmpty();
if (!countryCode.isEmpty() || !variantCode.isEmpty() || hasScriptOrExtensions) {
result.append('_');
@@ -1812,8 +1834,7 @@ public final class Locale implements Cloneable, Serializable {
return true;
}
- private static boolean isValidBcp47Alpha(String string,
- int lowerBound, int upperBound) {
+ private static boolean isValidBcp47Alpha(String string, int lowerBound, int upperBound) {
final int length = string.length();
if (length < lowerBound || length > upperBound) {
return false;
diff --git a/luni/src/main/java/libcore/icu/ICU.java b/luni/src/main/java/libcore/icu/ICU.java
index cf04ff9..407ebfd 100644
--- a/luni/src/main/java/libcore/icu/ICU.java
+++ b/luni/src/main/java/libcore/icu/ICU.java
@@ -239,70 +239,6 @@ public final class ICU {
true /* has validated fields */);
}
- /**
- * Builds an ICU locale ID from the given locale. The format is very
- * straightforward. It is a series of subtags in BCP 47 order
- * {@code lang[_script][_country][_variant]} followed by the keyword
- * separator {@code @} followed by a list of keywords. Each keyword is
- * a key value pair, and appear in the form {@code k1=v1;k2=v2;...}.
- *
- * In this use case, each key is an extension identifier, and each value
- * is the value of the extension.
- */
- public static String localeIdFromLocale(Locale l) {
- StringBuilder b = new StringBuilder(16);
- b.append(l.getLanguage());
-
- final boolean hasScript = !l.getScript().isEmpty();
- final boolean hasCountry = !l.getCountry().isEmpty();
- final boolean hasVariant = !l.getVariant().isEmpty();
-
- if (hasScript || hasCountry || hasVariant) {
- b.append('_');
- if (hasScript) {
- b.append(l.getScript());
- if (hasCountry || hasVariant) {
- b.append('_');
- }
- }
-
- if (hasCountry) {
- b.append(l.getCountry());
- if (hasVariant) {
- b.append('_');
- }
- }
-
- b.append(l.getVariant());
- }
-
- if (!l.getExtensionKeys().isEmpty()) {
- b.append('@');
- // The private use extension ('x') must show up last in the list
- // so we cache its value here and append it right at the end.
- String privateUseExtensionValue = null;
- for (char c : l.getExtensionKeys()) {
- if (c == Locale.PRIVATE_USE_EXTENSION) {
- privateUseExtensionValue = l.getExtension(Locale.PRIVATE_USE_EXTENSION);
- } else {
- b.append(c);
- b.append('=');
- b.append(l.getExtension(c));
- b.append(';');
- }
- }
-
- if (privateUseExtensionValue != null) {
- b.append(Locale.PRIVATE_USE_EXTENSION);
- b.append('=');
- b.append(privateUseExtensionValue);
- b.append(';');
- }
- }
-
- return b.toString();
- }
-
public static Locale[] localesFromStrings(String[] localeNames) {
// We need to remove duplicates caused by the conversion of "he" to "iw", et cetera.
// Java needs the obsolete code, ICU needs the modern code, but we let ICU know about
@@ -349,19 +285,20 @@ public final class ICU {
return localesFromStrings(getAvailableNumberFormatLocalesNative());
}
- public static String getBestDateTimePattern(String skeleton, String localeName) {
- String key = skeleton + "\t" + localeName;
+ public static String getBestDateTimePattern(String skeleton, Locale locale) {
+ String languageTag = locale.toLanguageTag();
+ String key = skeleton + "\t" + languageTag;
synchronized (CACHED_PATTERNS) {
String pattern = CACHED_PATTERNS.get(key);
if (pattern == null) {
- pattern = getBestDateTimePatternNative(skeleton, localeName);
+ pattern = getBestDateTimePatternNative(skeleton, languageTag);
CACHED_PATTERNS.put(key, pattern);
}
return pattern;
}
}
- private static native String getBestDateTimePatternNative(String skeleton, String localeName);
+ private static native String getBestDateTimePatternNative(String skeleton, String languageTag);
public static char[] getDateFormatOrder(String pattern) {
char[] result = new char[3];
@@ -421,8 +358,17 @@ public final class ICU {
// --- Case mapping.
- public static native String toLowerCase(String s, String localeName);
- public static native String toUpperCase(String s, String localeName);
+ public static String toLowerCase(String s, Locale locale) {
+ return toLowerCase(s, locale.toLanguageTag());
+ }
+
+ private static native String toLowerCase(String s, String languageTag);
+
+ public static String toUpperCase(String s, Locale locale) {
+ return toUpperCase(s, locale.toLanguageTag());
+ }
+
+ private static native String toUpperCase(String s, String languageTag);
// --- Errors.
@@ -448,18 +394,57 @@ public final class ICU {
public static native String[] getAvailableCurrencyCodes();
public static native String getCurrencyCode(String countryCode);
- public static native String getCurrencyDisplayName(String locale, String currencyCode);
+
+ public static String getCurrencyDisplayName(Locale locale, String currencyCode) {
+ return getCurrencyDisplayName(locale.toLanguageTag(), currencyCode);
+ }
+
+ private static native String getCurrencyDisplayName(String languageTag, String currencyCode);
+
public static native int getCurrencyFractionDigits(String currencyCode);
public static native int getCurrencyNumericCode(String currencyCode);
- public static native String getCurrencySymbol(String locale, 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);
- public static native String getDisplayScriptNative(String variantCode, String locale);
+ public static String getCurrencySymbol(Locale locale, String currencyCode) {
+ return getCurrencySymbol(locale.toLanguageTag(), currencyCode);
+ }
+
+ private static native String getCurrencySymbol(String languageTag, String currencyCode);
+
+ public static String getDisplayCountry(Locale targetLocale, Locale locale) {
+ return getDisplayCountryNative(targetLocale.toLanguageTag(), locale.toLanguageTag());
+ }
+
+ private static native String getDisplayCountryNative(String targetLanguageTag, String languageTag);
+
+ public static String getDisplayLanguage(Locale targetLocale, Locale locale) {
+ return getDisplayLanguageNative(targetLocale.toLanguageTag(), locale.toLanguageTag());
+ }
+
+ private static native String getDisplayLanguageNative(String targetLanguageTag, String languageTag);
+
+ public static String getDisplayVariant(Locale targetLocale, Locale locale) {
+ return getDisplayVariantNative(targetLocale.toLanguageTag(), locale.toLanguageTag());
+ }
+
+ private static native String getDisplayVariantNative(String targetLanguageTag, String languageTag);
+
+ public static String getDisplayScript(Locale targetLocale, Locale locale) {
+ return getDisplayScriptNative(targetLocale.toLanguageTag(), locale.toLanguageTag());
+ }
+
+ private static native String getDisplayScriptNative(String targetLanguageTag, String languageTag);
+
+ public static String getISO3Country(Locale locale) {
+ return getISO3CountryNative(locale.toLanguageTag());
+ }
+
+ private static native String getISO3CountryNative(String languageTag);
+
+ public static String getISO3Language(Locale locale) {
+ return getISO3LanguageNative(locale.toLanguageTag());
+ }
- public static native String getISO3CountryNative(String locale);
- public static native String getISO3LanguageNative(String locale);
+ private static native String getISO3LanguageNative(String languageTag);
public static native String addLikelySubtags(String locale);
public static native String getScript(String locale);
@@ -471,6 +456,6 @@ public final class ICU {
static native boolean initLocaleDataNative(String locale, LocaleData result);
- public static native void setDefaultLocale(String locale);
+ public static native void setDefaultLocale(String languageTag);
public static native String getDefaultLocale();
}
diff --git a/luni/src/main/java/libcore/icu/LocaleData.java b/luni/src/main/java/libcore/icu/LocaleData.java
index 49228b3..845ba32 100644
--- a/luni/src/main/java/libcore/icu/LocaleData.java
+++ b/luni/src/main/java/libcore/icu/LocaleData.java
@@ -176,8 +176,8 @@ public final class LocaleData {
}
// Get the "h:mm a" and "HH:mm" 12- and 24-hour time format strings.
- localeData.timeFormat12 = ICU.getBestDateTimePattern("hm", locale.toString());
- localeData.timeFormat24 = ICU.getBestDateTimePattern("Hm", locale.toString());
+ localeData.timeFormat12 = ICU.getBestDateTimePattern("hm", locale);
+ localeData.timeFormat24 = ICU.getBestDateTimePattern("Hm", locale);
// Fix up a couple of patterns.
if (localeData.fullTimeFormat != null) {
diff --git a/luni/src/main/java/libcore/icu/NativeBreakIterator.java b/luni/src/main/java/libcore/icu/NativeBreakIterator.java
index 7168d96..992aac2 100644
--- a/luni/src/main/java/libcore/icu/NativeBreakIterator.java
+++ b/luni/src/main/java/libcore/icu/NativeBreakIterator.java
@@ -138,23 +138,23 @@ public final class NativeBreakIterator implements Cloneable {
}
public int preceding(int offset) {
- return precedingImpl(this.address, this.string, offset);
+ return precedingImpl(this.address, this.string, offset);
}
- public static NativeBreakIterator getCharacterInstance(Locale where) {
- return new NativeBreakIterator(getCharacterInstanceImpl(where.toString()), BI_CHAR_INSTANCE);
+ public static NativeBreakIterator getCharacterInstance(Locale locale) {
+ return new NativeBreakIterator(getCharacterInstanceImpl(locale.toLanguageTag()), BI_CHAR_INSTANCE);
}
- public static NativeBreakIterator getLineInstance(Locale where) {
- return new NativeBreakIterator(getLineInstanceImpl(where.toString()), BI_LINE_INSTANCE);
+ public static NativeBreakIterator getLineInstance(Locale locale) {
+ return new NativeBreakIterator(getLineInstanceImpl(locale.toLanguageTag()), BI_LINE_INSTANCE);
}
- public static NativeBreakIterator getSentenceInstance(Locale where) {
- return new NativeBreakIterator(getSentenceInstanceImpl(where.toString()), BI_SENT_INSTANCE);
+ public static NativeBreakIterator getSentenceInstance(Locale locale) {
+ return new NativeBreakIterator(getSentenceInstanceImpl(locale.toLanguageTag()), BI_SENT_INSTANCE);
}
- public static NativeBreakIterator getWordInstance(Locale where) {
- return new NativeBreakIterator(getWordInstanceImpl(where.toString()), BI_WORD_INSTANCE);
+ public static NativeBreakIterator getWordInstance(Locale locale) {
+ return new NativeBreakIterator(getWordInstanceImpl(locale.toLanguageTag()), BI_WORD_INSTANCE);
}
private static native long getCharacterInstanceImpl(String locale);
diff --git a/luni/src/main/java/libcore/icu/NativeCollation.java b/luni/src/main/java/libcore/icu/NativeCollation.java
index 64e0278..b4b4f46 100644
--- a/luni/src/main/java/libcore/icu/NativeCollation.java
+++ b/luni/src/main/java/libcore/icu/NativeCollation.java
@@ -10,6 +10,8 @@
package libcore.icu;
+import java.util.Locale;
+
/**
* Package static class for declaring all native methods for collation use.
* @author syn wee quek
@@ -26,7 +28,10 @@ public final class NativeCollation {
public static native long getCollationElementIterator(long address, String source);
public static native String getRules(long address);
public static native byte[] getSortKey(long address, String source);
- public static native long openCollator(String locale);
+ public static long openCollator(Locale locale) {
+ return openCollator(locale.toLanguageTag());
+ }
+ private static native long openCollator(String languageTag);
public static native long openCollatorFromRules(String rules, int normalizationMode, int collationStrength);
public static native long safeClone(long address);
public static native void setAttribute(long address, int type, int value);
diff --git a/luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java b/luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java
index 3ea942d..b23013b 100644
--- a/luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java
+++ b/luni/src/main/java/libcore/icu/RuleBasedCollatorICU.java
@@ -52,7 +52,7 @@ public final class RuleBasedCollatorICU implements Cloneable {
}
public RuleBasedCollatorICU(Locale locale) {
- address = NativeCollation.openCollator(locale.toString());
+ address = NativeCollation.openCollator(locale);
}
private RuleBasedCollatorICU(long address) {
diff --git a/luni/src/main/native/IcuUtilities.cpp b/luni/src/main/native/IcuUtilities.cpp
index c6f3950..7ce2168 100644
--- a/luni/src/main/native/IcuUtilities.cpp
+++ b/luni/src/main/native/IcuUtilities.cpp
@@ -28,10 +28,6 @@
#include "unicode/uloc.h"
#include "unicode/ustring.h"
-Locale getLocale(JNIEnv* env, jstring localeName) {
- return Locale::createFromName(ScopedUtfChars(env, localeName).c_str());
-}
-
jobjectArray fromStringEnumeration(JNIEnv* env, UErrorCode& status, const char* provider, StringEnumeration* se) {
if (maybeThrowIcuException(env, provider, status)) {
return NULL;
diff --git a/luni/src/main/native/IcuUtilities.h b/luni/src/main/native/IcuUtilities.h
index ffcfcda..737379e 100644
--- a/luni/src/main/native/IcuUtilities.h
+++ b/luni/src/main/native/IcuUtilities.h
@@ -23,9 +23,7 @@
#include "jni.h"
#include "ustrenum.h" // For UStringEnumeration.
#include "unicode/utypes.h" // For UErrorCode.
-#include "unicode/locid.h" // For Locale.
-extern Locale getLocale(JNIEnv* env, jstring localeName);
extern jobjectArray fromStringEnumeration(JNIEnv* env, UErrorCode& status, const char* provider, StringEnumeration*);
bool maybeThrowIcuException(JNIEnv* env, const char* function, UErrorCode error);
diff --git a/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp b/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp
index bb05193..e0638bd 100644
--- a/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp
+++ b/luni/src/main/native/libcore_icu_AlphabeticIndex.cpp
@@ -20,6 +20,7 @@
#include "JNIHelp.h"
#include "JniConstants.h"
#include "JniException.h"
+#include "ScopedIcuLocale.h"
#include "ScopedJavaUnicodeString.h"
#include "unicode/alphaindex.h"
#include "unicode/uniset.h"
@@ -28,9 +29,13 @@ static AlphabeticIndex* fromPeer(jlong peer) {
return reinterpret_cast<AlphabeticIndex*>(static_cast<uintptr_t>(peer));
}
-static jlong AlphabeticIndex_create(JNIEnv* env, jclass, jstring javaLocale) {
+static jlong AlphabeticIndex_create(JNIEnv* env, jclass, jstring javaLocaleName) {
UErrorCode status = U_ZERO_ERROR;
- AlphabeticIndex* ai = new AlphabeticIndex(getLocale(env, javaLocale), status);
+ ScopedIcuLocale icuLocale(env, javaLocaleName);
+ if (!icuLocale.valid()) {
+ return 0;
+ }
+ AlphabeticIndex* ai = new AlphabeticIndex(icuLocale.locale(), status);
if (maybeThrowIcuException(env, "AlphabeticIndex", status)) {
return 0;
}
@@ -53,10 +58,14 @@ static void AlphabeticIndex_setMaxLabelCount(JNIEnv* env, jclass, jlong peer, ji
maybeThrowIcuException(env, "AlphabeticIndex::setMaxLabelCount", status);
}
-static void AlphabeticIndex_addLabels(JNIEnv* env, jclass, jlong peer, jstring javaLocale) {
+static void AlphabeticIndex_addLabels(JNIEnv* env, jclass, jlong peer, jstring javaLocaleName) {
AlphabeticIndex* ai = fromPeer(peer);
+ ScopedIcuLocale icuLocale(env, javaLocaleName);
+ if (!icuLocale.valid()) {
+ return;
+ }
UErrorCode status = U_ZERO_ERROR;
- ai->addLabels(getLocale(env, javaLocale), status);
+ ai->addLabels(icuLocale.locale(), status);
maybeThrowIcuException(env, "AlphabeticIndex::addLabels", status);
}
diff --git a/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp b/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp
index 72bc631..a3258c1 100644
--- a/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp
+++ b/luni/src/main/native/libcore_icu_DateIntervalFormat.cpp
@@ -18,13 +18,17 @@
#include "IcuUtilities.h"
#include "JniConstants.h"
+#include "ScopedIcuLocale.h"
#include "ScopedJavaUnicodeString.h"
#include "UniquePtr.h"
#include "cutils/log.h"
#include "unicode/dtitvfmt.h"
static jlong DateIntervalFormat_createDateIntervalFormat(JNIEnv* env, jclass, jstring javaSkeleton, jstring javaLocaleName, jstring javaTzName) {
- Locale locale = getLocale(env, javaLocaleName);
+ ScopedIcuLocale icuLocale(env, javaLocaleName);
+ if (!icuLocale.valid()) {
+ return 0;
+ }
ScopedJavaUnicodeString skeletonHolder(env, javaSkeleton);
if (!skeletonHolder.valid()) {
@@ -32,7 +36,7 @@ static jlong DateIntervalFormat_createDateIntervalFormat(JNIEnv* env, jclass, js
}
UErrorCode status = U_ZERO_ERROR;
- DateIntervalFormat* formatter(DateIntervalFormat::createInstance(skeletonHolder.unicodeString(), locale, status));
+ DateIntervalFormat* formatter(DateIntervalFormat::createInstance(skeletonHolder.unicodeString(), icuLocale.locale(), status));
if (maybeThrowIcuException(env, "DateIntervalFormat::createInstance", status)) {
return 0;
}
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp
index 7b1aac1..8cf58bc 100644
--- a/luni/src/main/native/libcore_icu_ICU.cpp
+++ b/luni/src/main/native/libcore_icu_ICU.cpp
@@ -21,6 +21,7 @@
#include "JniConstants.h"
#include "JniException.h"
#include "ScopedFd.h"
+#include "ScopedIcuLocale.h"
#include "ScopedJavaUnicodeString.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
@@ -96,30 +97,30 @@ class ScopedResourceBundle {
DISALLOW_COPY_AND_ASSIGN(ScopedResourceBundle);
};
-static jstring ICU_addLikelySubtags(JNIEnv* env, jclass, jstring javaLocale) {
+static jstring ICU_addLikelySubtags(JNIEnv* env, jclass, jstring javaLocaleName) {
UErrorCode status = U_ZERO_ERROR;
- ScopedUtfChars localeID(env, javaLocale);
+ ScopedUtfChars localeID(env, javaLocaleName);
char maximizedLocaleID[ULOC_FULLNAME_CAPACITY];
uloc_addLikelySubtags(localeID.c_str(), maximizedLocaleID, sizeof(maximizedLocaleID), &status);
if (U_FAILURE(status)) {
- return javaLocale;
+ return javaLocaleName;
}
return env->NewStringUTF(maximizedLocaleID);
}
-static jstring ICU_getScript(JNIEnv* env, jclass, jstring javaLocale) {
- UErrorCode status = U_ZERO_ERROR;
- ScopedUtfChars localeID(env, javaLocale);
- char script[ULOC_SCRIPT_CAPACITY];
- uloc_getScript(localeID.c_str(), script, sizeof(script), &status);
- if (U_FAILURE(status)) {
- return NULL;
- }
- return env->NewStringUTF(script);
+static jstring ICU_getScript(JNIEnv* env, jclass, jstring javaLocaleName) {
+ ScopedIcuLocale icuLocale(env, javaLocaleName);
+ if (!icuLocale.valid()) {
+ return NULL;
+ }
+ return env->NewStringUTF(icuLocale.locale().getScript());
}
static jstring ICU_localeForLanguageTag(JNIEnv* env, jclass, jstring languageTag, jboolean strict) {
ScopedUtfChars languageTagChars(env, languageTag);
+ if (languageTagChars.c_str() == NULL) {
+ return NULL;
+ }
// Naively assume that in the average case, the size of
// the normalized language tag will be very nearly the same as the
@@ -158,8 +159,7 @@ static jstring ICU_localeForLanguageTag(JNIEnv* env, jclass, jstring languageTag
// NOTE: The cast is safe because parsedLength can never be negative thanks
// to the check above. ICU does not document any negative return values for
// that field, but check for it anyway.
- if ((strict == JNI_TRUE) &&
- (static_cast<uint32_t>(parsedLength) != languageTagChars.size())) {
+ if ((strict == JNI_TRUE) && (static_cast<uint32_t>(parsedLength) != languageTagChars.size())) {
return NULL;
}
@@ -228,9 +228,9 @@ static jstring ICU_getCurrencyCode(JNIEnv* env, jclass, jstring javaCountryCode)
return (charCount == 0) ? env->NewStringUTF("XXX") : env->NewString(chars, charCount);
}
-static jstring getCurrencyName(JNIEnv* env, jstring javaLocaleName, jstring javaCurrencyCode, UCurrNameStyle nameStyle) {
- ScopedUtfChars localeName(env, javaLocaleName);
- if (localeName.c_str() == NULL) {
+static jstring getCurrencyName(JNIEnv* env, jstring javaLanguageTag, jstring javaCurrencyCode, UCurrNameStyle nameStyle) {
+ ScopedUtfChars languageTag(env, javaLanguageTag);
+ if (languageTag.c_str() == NULL) {
return NULL;
}
ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode);
@@ -241,7 +241,7 @@ static jstring getCurrencyName(JNIEnv* env, jstring javaLocaleName, jstring java
UErrorCode status = U_ZERO_ERROR;
UBool isChoiceFormat = false;
int32_t charCount;
- const UChar* chars = ucurr_getName(icuCurrencyCode.getTerminatedBuffer(), localeName.c_str(),
+ const UChar* chars = ucurr_getName(icuCurrencyCode.getTerminatedBuffer(), languageTag.c_str(),
nameStyle, &isChoiceFormat, &charCount, &status);
if (status == U_USING_DEFAULT_WARNING) {
if (nameStyle == UCURR_SYMBOL_NAME) {
@@ -260,54 +260,88 @@ static jstring getCurrencyName(JNIEnv* env, jstring javaLocaleName, jstring java
return (charCount == 0) ? NULL : env->NewString(chars, charCount);
}
-static jstring ICU_getCurrencyDisplayName(JNIEnv* env, jclass, jstring javaLocaleName, jstring javaCurrencyCode) {
- return getCurrencyName(env, javaLocaleName, javaCurrencyCode, UCURR_LONG_NAME);
+static jstring ICU_getCurrencyDisplayName(JNIEnv* env, jclass, jstring javaLanguageTag, jstring javaCurrencyCode) {
+ return getCurrencyName(env, javaLanguageTag, javaCurrencyCode, UCURR_LONG_NAME);
}
-static jstring ICU_getCurrencySymbol(JNIEnv* env, jclass, jstring javaLocaleName, jstring javaCurrencyCode) {
- return getCurrencyName(env, javaLocaleName, javaCurrencyCode, UCURR_SYMBOL_NAME);
+static jstring ICU_getCurrencySymbol(JNIEnv* env, jclass, jstring javaLanguageTag, jstring javaCurrencyCode) {
+ return getCurrencyName(env, javaLanguageTag, javaCurrencyCode, UCURR_SYMBOL_NAME);
}
-static jstring ICU_getDisplayCountryNative(JNIEnv* env, jclass, jstring targetLocale, jstring locale) {
- Locale loc = getLocale(env, locale);
- Locale targetLoc = getLocale(env, targetLocale);
- UnicodeString str;
- targetLoc.getDisplayCountry(loc, str);
- return env->NewString(str.getBuffer(), str.length());
+static jstring ICU_getDisplayCountryNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
+ ScopedIcuLocale icuLocale(env, javaLanguageTag);
+ if (!icuLocale.valid()) {
+ return NULL;
+ }
+ ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
+ if (!icuTargetLocale.valid()) {
+ return NULL;
+ }
+
+ UnicodeString str;
+ icuTargetLocale.locale().getDisplayCountry(icuLocale.locale(), str);
+ return env->NewString(str.getBuffer(), str.length());
}
-static jstring ICU_getDisplayLanguageNative(JNIEnv* env, jclass, jstring targetLocale, jstring locale) {
- Locale loc = getLocale(env, locale);
- Locale targetLoc = getLocale(env, targetLocale);
- UnicodeString str;
- targetLoc.getDisplayLanguage(loc, str);
- return env->NewString(str.getBuffer(), str.length());
+static jstring ICU_getDisplayLanguageNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
+ ScopedIcuLocale icuLocale(env, javaLanguageTag);
+ if (!icuLocale.valid()) {
+ return NULL;
+ }
+ ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
+ if (!icuTargetLocale.valid()) {
+ return NULL;
+ }
+
+ UnicodeString str;
+ icuTargetLocale.locale().getDisplayLanguage(icuLocale.locale(), str);
+ return env->NewString(str.getBuffer(), str.length());
}
-static jstring ICU_getDisplayScriptNative(JNIEnv* env, jclass, jstring targetLocale, jstring locale) {
- Locale loc = getLocale(env, locale);
- Locale targetLoc = getLocale(env, targetLocale);
- UnicodeString str;
- targetLoc.getDisplayScript(loc, str);
- return env->NewString(str.getBuffer(), str.length());
+static jstring ICU_getDisplayScriptNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
+ ScopedIcuLocale icuLocale(env, javaLanguageTag);
+ if (!icuLocale.valid()) {
+ return NULL;
+ }
+ ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
+ if (!icuTargetLocale.valid()) {
+ return NULL;
+ }
+
+ UnicodeString str;
+ icuTargetLocale.locale().getDisplayScript(icuLocale.locale(), str);
+ return env->NewString(str.getBuffer(), str.length());
}
-static jstring ICU_getDisplayVariantNative(JNIEnv* env, jclass, jstring targetLocale, jstring locale) {
- Locale loc = getLocale(env, locale);
- Locale targetLoc = getLocale(env, targetLocale);
- UnicodeString str;
- targetLoc.getDisplayVariant(loc, str);
- return env->NewString(str.getBuffer(), str.length());
+static jstring ICU_getDisplayVariantNative(JNIEnv* env, jclass, jstring javaTargetLanguageTag, jstring javaLanguageTag) {
+ ScopedIcuLocale icuLocale(env, javaLanguageTag);
+ if (!icuLocale.valid()) {
+ return NULL;
+ }
+ ScopedIcuLocale icuTargetLocale(env, javaTargetLanguageTag);
+ if (!icuTargetLocale.valid()) {
+ return NULL;
+ }
+
+ UnicodeString str;
+ icuTargetLocale.locale().getDisplayVariant(icuLocale.locale(), str);
+ return env->NewString(str.getBuffer(), str.length());
}
-static jstring ICU_getISO3CountryNative(JNIEnv* env, jclass, jstring locale) {
- Locale loc = getLocale(env, locale);
- return env->NewStringUTF(loc.getISO3Country());
+static jstring ICU_getISO3CountryNative(JNIEnv* env, jclass, jstring javaLanguageTag) {
+ ScopedIcuLocale icuLocale(env, javaLanguageTag);
+ if (!icuLocale.valid()) {
+ return NULL;
+ }
+ return env->NewStringUTF(icuLocale.locale().getISO3Country());
}
-static jstring ICU_getISO3LanguageNative(JNIEnv* env, jclass, jstring locale) {
- Locale loc = getLocale(env, locale);
- return env->NewStringUTF(loc.getISO3Language());
+static jstring ICU_getISO3LanguageNative(JNIEnv* env, jclass, jstring javaLanguageTag) {
+ ScopedIcuLocale icuLocale(env, javaLanguageTag);
+ if (!icuLocale.valid()) {
+ return NULL;
+ }
+ return env->NewStringUTF(icuLocale.locale().getISO3Language());
}
static jobjectArray ICU_getISOCountriesNative(JNIEnv* env, jclass) {
@@ -538,7 +572,10 @@ static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLocale
return JNI_FALSE; // ICU has a fixed-length limit.
}
- Locale locale = getLocale(env, javaLocaleName);
+ ScopedIcuLocale icuLocale(env, javaLocaleName);
+ if (!icuLocale.valid()) {
+ return JNI_FALSE;
+ }
// Get the DateTimePatterns.
UErrorCode status = U_ZERO_ERROR;
@@ -557,7 +594,7 @@ static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLocale
// Get the "Yesterday", "Today", and "Tomorrow" strings.
bool foundYesterdayTodayAndTomorrow = false;
for (LocaleNameIterator it(localeName.c_str(), status); it.HasNext(); it.Up()) {
- if (getYesterdayTodayAndTomorrow(env, localeData, locale, it.Get())) {
+ if (getYesterdayTodayAndTomorrow(env, localeData, icuLocale.locale(), it.Get())) {
foundYesterdayTodayAndTomorrow = true;
break;
}
@@ -568,7 +605,7 @@ static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLocale
}
status = U_ZERO_ERROR;
- UniquePtr<Calendar> cal(Calendar::createInstance(locale, status));
+ UniquePtr<Calendar> cal(Calendar::createInstance(icuLocale.locale(), status));
if (U_FAILURE(status)) {
return JNI_FALSE;
}
@@ -578,7 +615,7 @@ static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLocale
// Get DateFormatSymbols.
status = U_ZERO_ERROR;
- DateFormatSymbols dateFormatSym(locale, status);
+ DateFormatSymbols dateFormatSym(icuLocale.locale(), status);
if (U_FAILURE(status)) {
return JNI_FALSE;
}
@@ -631,8 +668,8 @@ static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLocale
status = U_ZERO_ERROR;
// For numberPatterns and symbols.
- setNumberPatterns(env, localeData, locale);
- setDecimalFormatSymbolsData(env, localeData, locale);
+ setNumberPatterns(env, localeData, icuLocale.locale());
+ setDecimalFormatSymbolsData(env, localeData, icuLocale.locale());
jstring countryCode = env->NewStringUTF(Locale::createFromName(localeName.c_str()).getCountry());
jstring internationalCurrencySymbol = ICU_getCurrencyCode(env, NULL, countryCode);
@@ -655,25 +692,33 @@ static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLocale
return JNI_TRUE;
}
-static jstring ICU_toLowerCase(JNIEnv* env, jclass, jstring javaString, jstring localeName) {
+static jstring ICU_toLowerCase(JNIEnv* env, jclass, jstring javaString, jstring javaLanguageTag) {
ScopedJavaUnicodeString scopedString(env, javaString);
if (!scopedString.valid()) {
return NULL;
}
+ ScopedIcuLocale icuLocale(env, javaLanguageTag);
+ if (!icuLocale.valid()) {
+ return NULL;
+ }
UnicodeString& s(scopedString.unicodeString());
UnicodeString original(s);
- s.toLower(getLocale(env, localeName));
+ s.toLower(icuLocale.locale());
return s == original ? javaString : env->NewString(s.getBuffer(), s.length());
}
-static jstring ICU_toUpperCase(JNIEnv* env, jclass, jstring javaString, jstring localeName) {
+static jstring ICU_toUpperCase(JNIEnv* env, jclass, jstring javaString, jstring javaLanguageTag) {
ScopedJavaUnicodeString scopedString(env, javaString);
if (!scopedString.valid()) {
return NULL;
}
+ ScopedIcuLocale icuLocale(env, javaLanguageTag);
+ if (!icuLocale.valid()) {
+ return NULL;
+ }
UnicodeString& s(scopedString.unicodeString());
UnicodeString original(s);
- s.toUpper(getLocale(env, localeName));
+ s.toUpper(icuLocale.locale());
return s == original ? javaString : env->NewString(s.getBuffer(), s.length());
}
@@ -708,10 +753,14 @@ static jobject ICU_getAvailableCurrencyCodes(JNIEnv* env, jclass) {
return fromStringEnumeration(env, status, "ucurr_openISOCurrencies", &e);
}
-static jstring ICU_getBestDateTimePatternNative(JNIEnv* env, jclass, jstring javaSkeleton, jstring javaLocaleName) {
- Locale locale = getLocale(env, javaLocaleName);
+static jstring ICU_getBestDateTimePatternNative(JNIEnv* env, jclass, jstring javaSkeleton, jstring javaLanguageTag) {
+ ScopedIcuLocale icuLocale(env, javaLanguageTag);
+ if (!icuLocale.valid()) {
+ return NULL;
+ }
+
UErrorCode status = U_ZERO_ERROR;
- UniquePtr<DateTimePatternGenerator> generator(DateTimePatternGenerator::createInstance(locale, status));
+ UniquePtr<DateTimePatternGenerator> generator(DateTimePatternGenerator::createInstance(icuLocale.locale(), status));
if (maybeThrowIcuException(env, "DateTimePatternGenerator::createInstance", status)) {
return NULL;
}
@@ -728,16 +777,14 @@ static jstring ICU_getBestDateTimePatternNative(JNIEnv* env, jclass, jstring jav
return env->NewString(result.getBuffer(), result.length());
}
-static void ICU_setDefaultLocale(JNIEnv* env, jclass, jstring javaLocaleName) {
- Locale locale = getLocale(env, javaLocaleName);
- UErrorCode status = U_ZERO_ERROR;
+static void ICU_setDefaultLocale(JNIEnv* env, jclass, jstring javaLanguageTag) {
+ ScopedIcuLocale icuLocale(env, javaLanguageTag);
+ if (!icuLocale.valid()) {
+ return;
+ }
- // TODO: Should we check whether locale.isBogus() here ? ICU will
- // accept bogus locales as the default without complaint. It
- // shouldn't make a difference in practice, users that set a bogus
- // locale as the default shouldn't have any realistic expectation that
- // things like defaults etc. will work correctly.
- Locale::setDefault(locale, status);
+ UErrorCode status = U_ZERO_ERROR;
+ Locale::setDefault(icuLocale.locale(), status);
maybeThrowIcuException(env, "Locale::setDefault", status);
}
diff --git a/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp b/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
index 0c8c3c9..ef0c2a9 100644
--- a/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
+++ b/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp
@@ -20,6 +20,7 @@
#include "JNIHelp.h"
#include "JniConstants.h"
#include "JniException.h"
+#include "ScopedIcuLocale.h"
#include "ScopedUtfChars.h"
#include "unicode/brkiter.h"
#include "unicode/putil.h"
@@ -107,13 +108,12 @@ class BreakIteratorAccessor {
};
#define MAKE_BREAK_ITERATOR_INSTANCE(F) \
- UErrorCode status = U_ZERO_ERROR; \
- const ScopedUtfChars localeChars(env, javaLocale); \
- if (localeChars.c_str() == NULL) { \
+ ScopedIcuLocale icuLocale(env, javaLocaleName); \
+ if (!icuLocale.valid()) { \
return 0; \
} \
- Locale locale(Locale::createFromName(localeChars.c_str())); \
- BreakIterator* it = F(locale, status); \
+ UErrorCode status = U_ZERO_ERROR; \
+ BreakIterator* it = F(icuLocale.locale(), status); \
if (maybeThrowIcuException(env, "ubrk_open", status)) { \
return 0; \
} \
@@ -143,19 +143,19 @@ static jint NativeBreakIterator_followingImpl(JNIEnv* env, jclass, jlong address
return it->following(offset);
}
-static jlong NativeBreakIterator_getCharacterInstanceImpl(JNIEnv* env, jclass, jstring javaLocale) {
+static jlong NativeBreakIterator_getCharacterInstanceImpl(JNIEnv* env, jclass, jstring javaLocaleName) {
MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createCharacterInstance);
}
-static jlong NativeBreakIterator_getLineInstanceImpl(JNIEnv* env, jclass, jstring javaLocale) {
+static jlong NativeBreakIterator_getLineInstanceImpl(JNIEnv* env, jclass, jstring javaLocaleName) {
MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createLineInstance);
}
-static jlong NativeBreakIterator_getSentenceInstanceImpl(JNIEnv* env, jclass, jstring javaLocale) {
+static jlong NativeBreakIterator_getSentenceInstanceImpl(JNIEnv* env, jclass, jstring javaLocaleName) {
MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createSentenceInstance);
}
-static jlong NativeBreakIterator_getWordInstanceImpl(JNIEnv* env, jclass, jstring javaLocale) {
+static jlong NativeBreakIterator_getWordInstanceImpl(JNIEnv* env, jclass, jstring javaLocaleName) {
MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createWordInstance);
}
diff --git a/luni/src/main/native/libcore_icu_NativeCollation.cpp b/luni/src/main/native/libcore_icu_NativeCollation.cpp
index 00ec9ae..4ce42ec 100644
--- a/luni/src/main/native/libcore_icu_NativeCollation.cpp
+++ b/luni/src/main/native/libcore_icu_NativeCollation.cpp
@@ -180,11 +180,12 @@ static jint NativeCollation_next(JNIEnv* env, jclass, jlong address) {
return result;
}
-static jlong NativeCollation_openCollator(JNIEnv* env, jclass, jstring localeName) {
- ScopedUtfChars localeChars(env, localeName);
+static jlong NativeCollation_openCollator(JNIEnv* env, jclass, jstring javaLocaleName) {
+ ScopedUtfChars localeChars(env, javaLocaleName);
if (localeChars.c_str() == NULL) {
return 0;
}
+
UErrorCode status = U_ZERO_ERROR;
UCollator* c = ucol_open(localeChars.c_str(), &status);
maybeThrowIcuException(env, "ucol_open", status);
diff --git a/luni/src/main/native/libcore_icu_TimeZoneNames.cpp b/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
index ef1743e..faf87f1 100644
--- a/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
+++ b/luni/src/main/native/libcore_icu_TimeZoneNames.cpp
@@ -20,6 +20,7 @@
#include "JNIHelp.h"
#include "JniConstants.h"
#include "JniException.h"
+#include "ScopedIcuLocale.h"
#include "ScopedJavaUnicodeString.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
@@ -59,11 +60,14 @@ static bool setStringArrayElement(JNIEnv* env, jobjectArray array, int i, const
return true;
}
-static void TimeZoneNames_fillZoneStrings(JNIEnv* env, jclass, jstring localeName, jobjectArray result) {
- Locale locale = getLocale(env, localeName);
+static void TimeZoneNames_fillZoneStrings(JNIEnv* env, jclass, jstring javaLocaleName, jobjectArray result) {
+ ScopedIcuLocale icuLocale(env, javaLocaleName);
+ if (!icuLocale.valid()) {
+ return;
+ }
UErrorCode status = U_ZERO_ERROR;
- UniquePtr<TimeZoneNames> names(TimeZoneNames::createInstance(locale, status));
+ UniquePtr<TimeZoneNames> names(TimeZoneNames::createInstance(icuLocale.locale(), status));
if (maybeThrowIcuException(env, "TimeZoneNames::createInstance", status)) {
return;
}
@@ -118,11 +122,14 @@ static void TimeZoneNames_fillZoneStrings(JNIEnv* env, jclass, jstring localeNam
}
}
-static jstring TimeZoneNames_getExemplarLocation(JNIEnv* env, jclass, jstring javaLocale, jstring javaTz) {
- Locale locale = getLocale(env, javaLocale);
+static jstring TimeZoneNames_getExemplarLocation(JNIEnv* env, jclass, jstring javaLocaleName, jstring javaTz) {
+ ScopedIcuLocale icuLocale(env, javaLocaleName);
+ if (!icuLocale.valid()) {
+ return NULL;
+ }
UErrorCode status = U_ZERO_ERROR;
- UniquePtr<TimeZoneNames> names(TimeZoneNames::createInstance(locale, status));
+ UniquePtr<TimeZoneNames> names(TimeZoneNames::createInstance(icuLocale.locale(), status));
if (maybeThrowIcuException(env, "TimeZoneNames::createInstance", status)) {
return NULL;
}
diff --git a/luni/src/test/java/libcore/icu/ICUTest.java b/luni/src/test/java/libcore/icu/ICUTest.java
index 60ed0ca..be2da25 100644
--- a/luni/src/test/java/libcore/icu/ICUTest.java
+++ b/luni/src/test/java/libcore/icu/ICUTest.java
@@ -16,6 +16,8 @@
package libcore.icu;
+import java.text.BreakIterator;
+import java.text.Collator;
import java.util.Arrays;
import java.util.Locale;
@@ -42,12 +44,12 @@ public class ICUTest extends junit.framework.TestCase {
}
public void test_getBestDateTimePattern() throws Exception {
- assertEquals("d MMMM", ICU.getBestDateTimePattern("MMMMd", "ca_ES"));
- assertEquals("d 'de' MMMM", ICU.getBestDateTimePattern("MMMMd", "es_ES"));
- assertEquals("d. MMMM", ICU.getBestDateTimePattern("MMMMd", "de_CH"));
- assertEquals("MMMM d", ICU.getBestDateTimePattern("MMMMd", "en_US"));
- assertEquals("d LLLL", ICU.getBestDateTimePattern("MMMMd", "fa_IR"));
- assertEquals("M月d日", ICU.getBestDateTimePattern("MMMMd", "ja_JP"));
+ assertEquals("d MMMM", ICU.getBestDateTimePattern("MMMMd", new Locale("ca", "ES")));
+ assertEquals("d 'de' MMMM", ICU.getBestDateTimePattern("MMMMd", new Locale("es", "ES")));
+ assertEquals("d. MMMM", ICU.getBestDateTimePattern("MMMMd", new Locale("de", "CH")));
+ assertEquals("MMMM d", ICU.getBestDateTimePattern("MMMMd", new Locale("en", "US")));
+ assertEquals("d LLLL", ICU.getBestDateTimePattern("MMMMd", new Locale("fa", "IR")));
+ assertEquals("M月d日", ICU.getBestDateTimePattern("MMMMd", new Locale("ja", "JP")));
}
public void test_localeFromString() throws Exception {
@@ -73,7 +75,7 @@ public class ICUTest extends junit.framework.TestCase {
}
private String best(Locale l, String skeleton) {
- return ICU.getBestDateTimePattern(skeleton, l.toString());
+ return ICU.getBestDateTimePattern(skeleton, l);
}
public void test_getDateFormatOrder() throws Exception {
@@ -123,4 +125,95 @@ public class ICUTest extends junit.framework.TestCase {
} catch (IllegalArgumentException expected) {
}
}
+
+ public void testScriptsPassedToIcu() throws Exception {
+ Locale sr_Cyrl_BA = Locale.forLanguageTag("sr-Cyrl-BA");
+ Locale sr_Cyrl_ME = Locale.forLanguageTag("sr-Cyrl-ME");
+ Locale sr_Latn_BA = Locale.forLanguageTag("sr-Latn-BA");
+ Locale sr_Latn_ME = Locale.forLanguageTag("sr-Latn-ME");
+
+ assertEquals("sr_BA_#Cyrl", sr_Cyrl_BA.toString());
+ assertEquals("Cyrl", sr_Cyrl_BA.getScript());
+
+ assertEquals("sr_ME_#Cyrl", sr_Cyrl_ME.toString());
+ assertEquals("Cyrl", sr_Cyrl_ME.getScript());
+
+ assertEquals("sr_BA_#Latn", sr_Latn_BA.toString());
+ assertEquals("Latn", sr_Latn_BA.getScript());
+
+ assertEquals("sr_ME_#Latn", sr_Latn_ME.toString());
+ assertEquals("Latn", sr_Latn_ME.getScript());
+
+ assertEquals("Српски", sr_Cyrl_BA.getDisplayLanguage(sr_Cyrl_BA));
+ assertEquals("Босна и Херцеговина", sr_Cyrl_BA.getDisplayCountry(sr_Cyrl_BA));
+ assertEquals("Ћирилица", sr_Cyrl_BA.getDisplayScript(sr_Cyrl_BA));
+ assertEquals("", sr_Cyrl_BA.getDisplayVariant(sr_Cyrl_BA));
+
+ assertEquals("Српски", sr_Cyrl_ME.getDisplayLanguage(sr_Cyrl_ME));
+ assertEquals("Црна Гора", sr_Cyrl_ME.getDisplayCountry(sr_Cyrl_ME));
+ assertEquals("Ћирилица", sr_Cyrl_ME.getDisplayScript(sr_Cyrl_ME));
+ assertEquals("", sr_Cyrl_ME.getDisplayVariant(sr_Cyrl_ME));
+
+ assertEquals("Srpski", sr_Latn_BA.getDisplayLanguage(sr_Latn_BA));
+ assertEquals("Bosna i Hercegovina", sr_Latn_BA.getDisplayCountry(sr_Latn_BA));
+ assertEquals("Latinica", sr_Latn_BA.getDisplayScript(sr_Latn_BA));
+ assertEquals("", sr_Latn_BA.getDisplayVariant(sr_Latn_BA));
+
+ assertEquals("Srpski", sr_Latn_ME.getDisplayLanguage(sr_Latn_ME));
+ assertEquals("Crna Gora", sr_Latn_ME.getDisplayCountry(sr_Latn_ME));
+ assertEquals("Latinica", sr_Latn_ME.getDisplayScript(sr_Latn_ME));
+ assertEquals("", sr_Latn_ME.getDisplayVariant(sr_Latn_ME));
+
+ assertEquals("BIH", sr_Cyrl_BA.getISO3Country());
+ assertEquals("srp", sr_Cyrl_BA.getISO3Language());
+ assertEquals("MNE", sr_Cyrl_ME.getISO3Country());
+ assertEquals("srp", sr_Cyrl_ME.getISO3Language());
+ assertEquals("BIH", sr_Latn_BA.getISO3Country());
+ assertEquals("srp", sr_Latn_BA.getISO3Language());
+ assertEquals("MNE", sr_Latn_ME.getISO3Country());
+ assertEquals("srp", sr_Latn_ME.getISO3Language());
+
+ BreakIterator.getCharacterInstance(sr_Cyrl_BA);
+ BreakIterator.getCharacterInstance(sr_Cyrl_ME);
+ BreakIterator.getCharacterInstance(sr_Latn_BA);
+ BreakIterator.getCharacterInstance(sr_Latn_ME);
+
+ BreakIterator.getLineInstance(sr_Cyrl_BA);
+ BreakIterator.getLineInstance(sr_Cyrl_ME);
+ BreakIterator.getLineInstance(sr_Latn_BA);
+ BreakIterator.getLineInstance(sr_Latn_ME);
+
+ BreakIterator.getSentenceInstance(sr_Cyrl_BA);
+ BreakIterator.getSentenceInstance(sr_Cyrl_ME);
+ BreakIterator.getSentenceInstance(sr_Latn_BA);
+ BreakIterator.getSentenceInstance(sr_Latn_ME);
+
+ BreakIterator.getWordInstance(sr_Cyrl_BA);
+ BreakIterator.getWordInstance(sr_Cyrl_ME);
+ BreakIterator.getWordInstance(sr_Latn_BA);
+ BreakIterator.getWordInstance(sr_Latn_ME);
+
+ Collator.getInstance(sr_Cyrl_BA);
+ Collator.getInstance(sr_Cyrl_ME);
+ Collator.getInstance(sr_Latn_BA);
+ Collator.getInstance(sr_Latn_ME);
+
+ // TODO: This needs to be fixed. We shouldn't output attribute key
+ // expansions in the language tag or the toString output. The tests
+ // will fail with something like:
+ //
+ // expected:<de-u-co[-phonebk-kf-upper-kn]> but was:
+ // <de-u-co[lcasefirst-upper-collation-phonebook-colnumeric-yes]>
+ Locale l = Locale.forLanguageTag("de-u-co-phonebk-kf-upper-kn");
+ assertEquals("de__#u-co-phonebk-kf-upper-kn", l.toString());
+ assertEquals("de-u-co-phonebk-kf-upper-kn", l.toLanguageTag());
+
+ Collator c = Collator.getInstance(l);
+ assertTrue(c.compare("2", "11") < 0);
+ assertTrue(c.compare("11", "ae") < 0);
+ assertTrue(c.compare("ae", "Ä") < 0);
+ assertTrue(c.compare("Ä", "ä") < 0);
+ assertTrue(c.compare("ä", "AF") < 0);
+ assertTrue(c.compare("AF", "af") < 0);
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/LocaleTest.java b/luni/src/test/java/libcore/java/util/LocaleTest.java
index b87dc97..0512b13 100644
--- a/luni/src/test/java/libcore/java/util/LocaleTest.java
+++ b/luni/src/test/java/libcore/java/util/LocaleTest.java
@@ -39,9 +39,22 @@ public class LocaleTest extends junit.framework.TestCase {
// and variant, but a display name made up of the raw strings.
// Newer releases return slightly different results, but no less unreasonable.
assertEquals("aabbcc", invalid.getDisplayLanguage());
- assertEquals("", invalid.getDisplayCountry());
- assertEquals("DDEEFF_GGHHII", invalid.getDisplayVariant());
- assertEquals("aabbcc (DDEEFF,DDEEFF_GGHHII)", invalid.getDisplayName());
+ assertEquals("DDEEFF", invalid.getDisplayCountry());
+ assertEquals("GGHHII", invalid.getDisplayVariant());
+ assertEquals("aabbcc (DDEEFF,GGHHII)", invalid.getDisplayName());
+ }
+
+ public void test_getDisplayName_emptyCodes() {
+ Locale emptyLanguage = new Locale("", "DdeEFf");
+ assertEquals("", emptyLanguage.getDisplayLanguage());
+
+ Locale emptyCountry = new Locale("AaBbCc", "");
+ assertEquals("", emptyCountry.getDisplayCountry());
+
+ Locale emptyCountryAndLanguage = new Locale("", "", "Farl");
+ assertEquals("", emptyCountryAndLanguage.getDisplayLanguage());
+ assertEquals("", emptyCountryAndLanguage.getDisplayCountry());
+ assertEquals("Farl", emptyCountryAndLanguage.getDisplayVariant());
}
// http://b/2611311; if there's no display language/country/variant, use the raw codes.
@@ -53,8 +66,8 @@ public class LocaleTest extends junit.framework.TestCase {
assertEquals("xx", unknown.getDisplayLanguage());
assertEquals("YY", unknown.getDisplayCountry());
- assertEquals("TRADITIONAL", unknown.getDisplayVariant());
- assertEquals("xx (YY,TRADITIONAL)", unknown.getDisplayName());
+ assertEquals("Traditional", unknown.getDisplayVariant());
+ assertEquals("xx (YY,Traditional)", unknown.getDisplayName());
}
public void test_getDisplayName_easy() throws Exception {