Fix Serbian Latin subtype handling

This CL also adds unit tests for Hinglish and Serbian Latin.

Bug: 9687668
Bug: 17169632
Change-Id: Ib9aa1bcdf5b390a9d8c61f07165beacf850e2692
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index 817bb51..08d8bb2 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -39,6 +39,8 @@
         <item>hi_ZZ</item>
         <item>sr_ZZ</item>
     </string-array>
+    <string name="subtype_in_root_locale_hi_ZZ">Hinglish</string>
+    <string name="subtype_in_root_locale_sr_ZZ">Srpski</string>
 
     <!-- Generic subtype label -->
     <string name="subtype_generic">%s</string>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 583c3b1..e1a72c4 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -214,8 +214,7 @@
     <!-- Description for Hinglish (https://en.wikipedia.org/wiki/Hinglish) keyboard subtype [CHAR LIMIT=25] -->
     <string name="subtype_hi_ZZ">Hinglish</string>
     <!-- Description for Serbian (Latin) keyboard subtype [CHAR LIMIT=25]
-         (Latin) can be an abbreviation to fit in the CHAR LIMIT.
-         Note for Serbian translator: this should be translated with Latin script and (Latin) should be omitted. -->
+         (Latin) can be an abbreviation to fit in the CHAR LIMIT. -->
     <string name="subtype_sr_ZZ">Serbian (Latin)</string>
     <!-- Description for English (UK) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25]
          (UK) should be an abbreviation of United Kingdom to fit in the CHAR LIMIT.
@@ -233,16 +232,14 @@
          This should be identical to subtype_hi_ZZ aside from the trailing (%s). -->
     <string name="subtype_with_layout_hi_ZZ">Hinglish (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</string>
     <!-- Description for Serbian (Latin) keyboard subtype with explicit keyboard layout [CHAR LIMIT=25]
-         This should be identical to subtype_sr_ZZ aside from the trailing (%s).
-         Note for Serbian translator: this should be translated with Latin script. -->
+         This should be identical to subtype_sr_ZZ aside from the trailing (%s). -->
     <string name="subtype_with_layout_sr_ZZ">Serbian (<xliff:g id="KEYBOARD_LAYOUT" example="QWERTY">%s</xliff:g>)</string>
     <!-- Description for "LANGUAGE_NAME" (Traditional) keyboard subtype [CHAR LIMIT=25]
          (Traditional) can be an abbreviation to fit in the CHAR LIMIT. -->
     <string name="subtype_generic_traditional"><xliff:g id="LANGUAGE_NAME" example="Nepali">%s</xliff:g> (Traditional)</string>
     <!-- Description for "LANGUAGE_NAME" (Compact) keyboard subtype [CHAR LIMIT=25]
-         (Compact) can be an abbreviation to fit in the CHAR LIMIT.
-         TODO: Remove translatable=false once we are settled down with the naming. -->
-    <string name="subtype_generic_compact" translatable="false"><xliff:g id="LANGUAGE_NAME" example="Hindi">%s</xliff:g> (Compact)</string>
+         (Compact) can be an abbreviation to fit in the CHAR LIMIT. -->
+    <string name="subtype_generic_compact"><xliff:g id="LANGUAGE_NAME" example="Hindi">%s</xliff:g> (Compact)</string>
     <!-- This string is displayed in a language list that allows to choose a language for
 suggestions in a software keyboard. This setting won't give suggestions in any particular
 language, hence "No language".
diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
index eb85c1b..3e6680b 100644
--- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
@@ -31,7 +31,6 @@
 
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Locale;
 
 /**
@@ -59,7 +58,8 @@
     // Keyboard layout to subtype name resource id map.
     private static final HashMap<String, Integer> sKeyboardLayoutToNameIdsMap = new HashMap<>();
     // Exceptional locale whose name should be displayed in Locale.ROOT.
-    static final HashSet<String> sExceptionalLocaleDisplayedInRootLocale = new HashSet<>();
+    private static final HashMap<String, Integer> sExceptionalLocaleDisplayedInRootLocale =
+            new HashMap<>();
     // Exceptional locale to subtype name resource id map.
     private static final HashMap<String, Integer> sExceptionalLocaleToNameIdsMap = new HashMap<>();
     // Exceptional locale to subtype name with layout resource id map.
@@ -73,6 +73,8 @@
             "string/subtype_with_layout_";
     private static final String SUBTYPE_NAME_RESOURCE_NO_LANGUAGE_PREFIX =
             "string/subtype_no_language_";
+    private static final String SUBTYPE_NAME_RESOURCE_IN_ROOT_LOCALE_PREFIX =
+            "string/subtype_in_root_locale_";
     // Keyboard layout set name for the subtypes that don't have a keyboardLayoutSet extra value.
     // This is for compatibility to keep the same subtype ids as pre-JellyBean.
     private static final HashMap<String, String> sLocaleAndExtraValueToKeyboardLayoutSetMap =
@@ -117,7 +119,10 @@
         final String[] exceptionalLocaleInRootLocale = res.getStringArray(
                 R.array.subtype_locale_displayed_in_root_locale);
         for (int i = 0; i < exceptionalLocaleInRootLocale.length; i++) {
-            sExceptionalLocaleDisplayedInRootLocale.add(exceptionalLocaleInRootLocale[i]);
+            final String localeString = exceptionalLocaleInRootLocale[i];
+            final String resourceName = SUBTYPE_NAME_RESOURCE_IN_ROOT_LOCALE_PREFIX + localeString;
+            final int resId = res.getIdentifier(resourceName, null, RESOURCE_PACKAGE_NAME);
+            sExceptionalLocaleDisplayedInRootLocale.put(localeString, resId);
         }
 
         final String[] exceptionalLocales = res.getStringArray(
@@ -171,7 +176,7 @@
         if (NO_LANGUAGE.equals(localeString)) {
             return sResources.getConfiguration().locale;
         }
-        if (sExceptionalLocaleDisplayedInRootLocale.contains(localeString)) {
+        if (sExceptionalLocaleDisplayedInRootLocale.containsKey(localeString)) {
             return Locale.ROOT;
         }
         return LocaleUtils.constructLocaleFromString(localeString);
@@ -190,7 +195,7 @@
     public static String getSubtypeLanguageDisplayName(final String localeString) {
         final Locale displayLocale = getDisplayLocaleOfSubtypeLocale(localeString);
         final String languageString;
-        if (sExceptionalLocaleDisplayedInRootLocale.contains(localeString)) {
+        if (sExceptionalLocaleDisplayedInRootLocale.containsKey(localeString)) {
             languageString = localeString;
         } else {
             final Locale locale = LocaleUtils.constructLocaleFromString(localeString);
@@ -205,7 +210,16 @@
             // No language subtype should be displayed in system locale.
             return sResources.getString(R.string.subtype_no_language);
         }
-        final Integer exceptionalNameResId = sExceptionalLocaleToNameIdsMap.get(localeString);
+        final Integer exceptionalNameResId;
+        if (displayLocale.equals(Locale.ROOT)
+                && sExceptionalLocaleDisplayedInRootLocale.containsKey(localeString)) {
+            exceptionalNameResId = sExceptionalLocaleDisplayedInRootLocale.get(localeString);
+        } else if (sExceptionalLocaleToNameIdsMap.containsKey(localeString)) {
+            exceptionalNameResId = sExceptionalLocaleToNameIdsMap.get(localeString);
+        } else {
+            exceptionalNameResId = null;
+        }
+
         final String displayName;
         if (exceptionalNameResId != null) {
             final RunInLocale<String> getExceptionalName = new RunInLocale<String>() {