Fix a couple of Locale bugs discovered by ICU4J tests.

ULocaleTest revealed two issues :
- We weren't handling the legacy ja_JP_JP and th_TH_TH locales
  correctly.
- We weren't lower-casing the extension key in forLanguageTag. This
  shouldn't matter since language tags are case insensitive, by
  definition but the convention is to keep them lowercase. This also
  fixes a bug in the builder where extension keys were case sensitive
  since we weren't normalizing them properly.

bug: 20252611
Change-Id: Id15823186c282aeac9adb937d200dc3409d580df
diff --git a/luni/src/main/java/java/util/Locale.java b/luni/src/main/java/java/util/Locale.java
index 1885f83..7226e1c 100644
--- a/luni/src/main/java/java/util/Locale.java
+++ b/luni/src/main/java/java/util/Locale.java
@@ -744,12 +744,13 @@
 
             final String normalizedValue = value.toLowerCase(Locale.ROOT).replace('_', '-');
             final String[] subtags = normalizedValue.split("-");
+            final char normalizedKey = Character.toLowerCase(key);
 
             // Lengths for subtags in the private use extension should be [1, 8] chars.
             // For all other extensions, they should be [2, 8] chars.
             //
             // http://www.rfc-editor.org/rfc/bcp/bcp47.txt
-            final int minimumLength = (key == PRIVATE_USE_EXTENSION) ? 1 : 2;
+            final int minimumLength = (normalizedKey == PRIVATE_USE_EXTENSION) ? 1 : 2;
             for (String subtag : subtags) {
                 if (!isValidBcp47Alphanum(subtag, minimumLength, 8)) {
                     throw new IllformedLocaleException(
@@ -759,14 +760,14 @@
 
             // We need to take special action in the case of unicode extensions,
             // since we claim to understand their keywords and attributes.
-            if (key == UNICODE_LOCALE_EXTENSION) {
+            if (normalizedKey == UNICODE_LOCALE_EXTENSION) {
                 // First clear existing attributes and keywords.
                 extensions.clear();
                 attributes.clear();
 
                 parseUnicodeExtension(subtags, keywords, attributes);
             } else {
-                extensions.put(key, normalizedValue);
+                extensions.put(normalizedKey, normalizedValue);
             }
 
             return this;
@@ -986,6 +987,27 @@
             this.unicodeKeywords = Collections.unmodifiableMap(keywordsCopy);
             this.extensions = Collections.unmodifiableMap(extensionsCopy);
         } else {
+
+            // The locales ja_JP_JP and th_TH_TH are ill formed since their variant is too
+            // short, however they have been used to represent a locale with the japanese imperial
+            // calendar and thai numbering respectively. We add an extension in their constructor
+            // to modernize them.
+            if ("ja".equals(language) && "JP".equals(country) && "JP".equals(variant)) {
+                Map<String, String> keywordsCopy = new TreeMap<>(unicodeKeywords);
+                keywordsCopy.put("ca", "japanese");
+                unicodeKeywords = keywordsCopy;
+            } else if ("th".equals(language) && "TH".equals(country) && "TH".equals(variant)) {
+                Map<String, String> keywordsCopy = new TreeMap<>(unicodeKeywords);
+                keywordsCopy.put("nu", "thai");
+                unicodeKeywords = keywordsCopy;
+            }
+
+            if (!unicodeKeywords.isEmpty() || !unicodeAttributes.isEmpty()) {
+                Map<Character, String> extensionsCopy = new TreeMap<>(extensions);
+                addUnicodeExtensionToExtensionsMap(unicodeAttributes, unicodeKeywords, extensionsCopy);
+                extensions = extensionsCopy;
+            }
+
             this.unicodeAttributes = unicodeAttributes;
             this.unicodeKeywords = unicodeKeywords;
             this.extensions = extensions;
@@ -2134,7 +2156,7 @@
                         return extensionKeyIndex;
                     }
 
-                    final String key = subtags[extensionKeyIndex];
+                    final String key = subtags[extensionKeyIndex].toLowerCase(Locale.ROOT);
                     if (extensions.containsKey(key.charAt(0))) {
                         return extensionKeyIndex;
                     }
@@ -2146,7 +2168,7 @@
                 // Mark the start of the next extension. Also keep track of whether this
                 // is a private use extension, and throw an error if it doesn't come last.
                 extensionKeyIndex = i;
-                if ("x".equals(subtag)) {
+                if ("x".equals(subtag.toLowerCase(Locale.ROOT))) {
                     privateUseExtensionIndex = i;
                 } else if (privateUseExtensionIndex != -1) {
                     // The private use extension must come last.
@@ -2169,7 +2191,7 @@
                 return extensionKeyIndex;
             }
 
-            final String key = subtags[extensionKeyIndex];
+            final String key = subtags[extensionKeyIndex].toLowerCase(Locale.ROOT);
             if (extensions.containsKey(key.charAt(0))) {
                 return extensionKeyIndex;
             }
diff --git a/luni/src/test/java/libcore/java/util/LocaleTest.java b/luni/src/test/java/libcore/java/util/LocaleTest.java
index e1e84ab..9005f25 100644
--- a/luni/src/test/java/libcore/java/util/LocaleTest.java
+++ b/luni/src/test/java/libcore/java/util/LocaleTest.java
@@ -1203,4 +1203,38 @@
             System.setUnchangeableSystemProperty("user.locale", userLocale);
         }
     }
+
+    // http://b/20252611
+    public void testLegacyLocalesWithExtensions() {
+        Locale ja_JP_JP = new Locale("ja", "JP", "JP");
+        assertEquals("ca-japanese", ja_JP_JP.getExtension(Locale.UNICODE_LOCALE_EXTENSION));
+        assertEquals("japanese", ja_JP_JP.getUnicodeLocaleType("ca"));
+
+        Locale th_TH_TH = new Locale("th", "TH", "TH");
+        assertEquals("nu-thai", th_TH_TH.getExtension(Locale.UNICODE_LOCALE_EXTENSION));
+        assertEquals("thai", th_TH_TH.getUnicodeLocaleType("nu"));
+    }
+
+    // http://b/20252611
+    public void testLowerCaseExtensionKeys() {
+        // We must lowercase extension keys in forLanguageTag..
+        Locale ar_EG = Locale.forLanguageTag("ar-EG-U-nu-arab");
+        assertEquals("nu-arab", ar_EG.getExtension(Locale.UNICODE_LOCALE_EXTENSION));
+        assertEquals("ar-EG-u-nu-arab", ar_EG.toLanguageTag());
+
+        // ... and in builders.
+        Locale.Builder b = new Locale.Builder();
+        b.setLanguage("ar");
+        b.setRegion("EG");
+        b.setExtension('U', "nu-arab");
+        assertEquals("ar-EG-u-nu-arab", b.build().toLanguageTag());
+
+        // Corollary : extension keys are case insensitive.
+        b = new Locale.Builder();
+        b.setLanguage("ar");
+        b.setRegion("EG");
+        b.setExtension('U', "nu-arab");
+        b.setExtension('u', "nu-thai");
+        assertEquals("ar-EG-u-nu-thai", b.build().toLanguageTag());
+    }
 }