Refactor make-keyboard-text

Change-Id: Ifaf955ae896a18e5cbc9c1af5a1b7e15942eb886
diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java
index a74096e..8e0f213 100644
--- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java
+++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/JarUtils.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.keyboard.tools;
 
+import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
@@ -58,7 +59,7 @@
         public boolean accept(String dirName, String name);
     }
 
-    public static ArrayList<String> getNameListing(final JarFile jar, final JarFilter filter) {
+    public static ArrayList<String> getEntryNameListing(final JarFile jar, final JarFilter filter) {
         final ArrayList<String> result = new ArrayList<String>();
         final Enumeration<JarEntry> entries = jar.entries();
         while (entries.hasMoreElements()) {
@@ -74,12 +75,42 @@
         return result;
     }
 
-    public static ArrayList<String> getNameListing(final JarFile jar, final String filterName) {
-        return getNameListing(jar, new JarFilter() {
+    public static ArrayList<String> getEntryNameListing(final JarFile jar,
+            final String filterName) {
+        return getEntryNameListing(jar, new JarFilter() {
             @Override
             public boolean accept(final String dirName, final String name) {
                 return name.equals(filterName);
             }
         });
     }
+
+    // The language is taken from string resource jar entry name (values-<language>/)
+    // or {@link LocaleUtils#DEFAULT_LANGUAGE_NAME} for the default string resource
+    // directory (values/).
+    public static String getLanguageFromEntryName(final String jarEntryName) {
+        final String dirName = jarEntryName.substring(0, jarEntryName.lastIndexOf('/'));
+        final int pos = dirName.lastIndexOf('/');
+        final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName;
+        final int languagePos = parentName.indexOf('-');
+        if (languagePos < 0) {
+            // Default resource name.
+            return LocaleUtils.DEFAULT_LANGUAGE_NAME;
+        }
+        final String language = parentName.substring(languagePos + 1);
+        final int countryPos = language.indexOf("-r");
+        if (countryPos < 0) {
+            return language;
+        }
+        return language.replace("-r", "_");
+    }
+
+    public static void close(final Closeable stream) {
+        try {
+            if (stream != null) {
+                stream.close();
+            }
+        } catch (IOException e) {
+        }
+    }
 }
diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/LocaleUtils.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/LocaleUtils.java
index 9fdc1f6..3a0ba2b 100644
--- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/LocaleUtils.java
+++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/LocaleUtils.java
@@ -26,6 +26,10 @@
  * for the make-keyboard-text tool.
  */
 public final class LocaleUtils {
+    public static final String DEFAULT_LANGUAGE_NAME = "DEFAULT";
+    public static final String NO_LANGUAGE_CODE = "zz";
+    public static final String NO_LANGUAGE_DISPLAY_NAME = "Alphabet";
+
     private LocaleUtils() {
         // Intentional empty constructor for utility class.
     }
@@ -58,4 +62,12 @@
             return retval;
         }
     }
+
+    public static String getLanguageDisplayName(final String language) {
+        if (language.equals(NO_LANGUAGE_CODE)) {
+            return NO_LANGUAGE_DISPLAY_NAME;
+        }
+        final Locale locale = constructLocaleFromString(language);
+        return locale.getDisplayName(Locale.ENGLISH);
+    }
 }
diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java
index 9bb2b38..f72fefb 100644
--- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java
+++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/MoreKeysResources.java
@@ -16,10 +16,8 @@
 
 package com.android.inputmethod.keyboard.tools;
 
-import java.io.Closeable;
 import java.io.File;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.LineNumberReader;
 import java.io.PrintStream;
@@ -28,6 +26,7 @@
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Locale;
+import java.util.TreeMap;
 import java.util.jar.JarFile;
 
 public class MoreKeysResources {
@@ -38,20 +37,13 @@
     private static final String MARK_DEFAULT_TEXTS = "@DEFAULT_TEXTS@";
     private static final String MARK_TEXTS = "@TEXTS@";
     private static final String MARK_LANGUAGES_AND_TEXTS = "@LANGUAGES_AND_TEXTS@";
-    private static final String DEFAULT_LANGUAGE_NAME = "DEFAULT";
     private static final String EMPTY_STRING_VAR = "EMPTY";
 
-    private static final String NO_LANGUAGE_CODE = "zz";
-    private static final String NO_LANGUAGE_DISPLAY_NAME = "Alphabet";
-
     private final JarFile mJar;
-    // Language to string resources map.
-    private final HashMap<String, StringResourceMap> mResourcesMap =
-            new HashMap<String, StringResourceMap>();
-    // Sorted languages list. The language is taken from string resource directories
-    // (values-<language>/) or {@link #DEFAULT_LANGUAGE_NAME} for the default string resource
-    // directory (values/).
-    private final ArrayList<String> mSortedLanguagesList = new ArrayList<String>();
+    // String resources maps sorted by its language. The language is determined from the jar entry
+    // name by calling {@link JarUtils#getLanguegFromEntryName(String)}.
+    private final TreeMap<String, StringResourceMap> mResourcesMap =
+            new TreeMap<String, StringResourceMap>();
     // Default string resources map.
     private final StringResourceMap mDefaultResourceMap;
     // Histogram of string resource names. This is used to sort {@link #mSortedResourceNames}.
@@ -64,22 +56,13 @@
 
     public MoreKeysResources(final JarFile jar) {
         mJar = jar;
-        final ArrayList<String> resources = JarUtils.getNameListing(jar, TEXT_RESOURCE_NAME);
-        for (final String name : resources) {
-            final String dirName = name.substring(0, name.lastIndexOf('/'));
-            final int pos = dirName.lastIndexOf('/');
-            final String parentName = (pos >= 0) ? dirName.substring(pos + 1) : dirName;
-            final String language = getLanguageFromResDir(parentName);
-            final InputStream stream = JarUtils.openResource(name);
-            try {
-                mResourcesMap.put(language, new StringResourceMap(stream));
-            } finally {
-                close(stream);
-            }
+        final ArrayList<String> resourceEntryNames = JarUtils.getEntryNameListing(
+                jar, TEXT_RESOURCE_NAME);
+        for (final String entryName : resourceEntryNames) {
+            final StringResourceMap resMap = new StringResourceMap(entryName);
+            mResourcesMap.put(resMap.mLanguage, resMap);
         }
-        mDefaultResourceMap = mResourcesMap.get(DEFAULT_LANGUAGE_NAME);
-        mSortedLanguagesList.addAll(mResourcesMap.keySet());
-        Collections.sort(mSortedLanguagesList);
+        mDefaultResourceMap = mResourcesMap.get(LocaleUtils.DEFAULT_LANGUAGE_NAME);
 
         // Initialize name histogram and names list.
         final HashMap<String, Integer> nameHistogram = mNameHistogram;
@@ -118,22 +101,8 @@
         mSortedResourceNames = resourceNamesList.toArray(new String[resourceNamesList.size()]);
     }
 
-    private static String getLanguageFromResDir(final String dirName) {
-        final int languagePos = dirName.indexOf('-');
-        if (languagePos < 0) {
-            // Default resource.
-            return DEFAULT_LANGUAGE_NAME;
-        }
-        final String language = dirName.substring(languagePos + 1);
-        final int countryPos = language.indexOf("-r");
-        if (countryPos < 0) {
-            return language;
-        }
-        return language.replace("-r", "_");
-    }
-
     public void writeToJava(final String outDir) {
-        final ArrayList<String> list = JarUtils.getNameListing(mJar, JAVA_TEMPLATE);
+        final ArrayList<String> list = JarUtils.getEntryNameListing(mJar, JAVA_TEMPLATE);
         if (list.isEmpty()) {
             throw new RuntimeException("Can't find java template " + JAVA_TEMPLATE);
         }
@@ -159,8 +128,8 @@
         } catch (IOException e) {
             throw new RuntimeException(e);
         } finally {
-            close(lnr);
-            close(ps);
+            JarUtils.close(lnr);
+            JarUtils.close(ps);
         }
     }
 
@@ -201,10 +170,11 @@
     }
 
     private void dumpTexts(final PrintStream out) {
-        for (final String language : mSortedLanguagesList) {
-            final StringResourceMap resMap = mResourcesMap.get(language);
+        for (final StringResourceMap resMap : mResourcesMap.values()) {
+            final String language = resMap.mLanguage;
             if (resMap == mDefaultResourceMap) continue;
-            out.format("    /* Language %s: %s */\n", language, getLanguageDisplayName(language));
+            out.format("    /* Language %s: %s */\n",
+                    language, LocaleUtils.getLanguageDisplayName(language));
             out.format("    private static final String[] " + getArrayNameForLanguage(language)
                     + " = {\n");
             final int outputArraySize = dumpTextsInternal(out, resMap);
@@ -214,8 +184,8 @@
     }
 
     private void dumpLanguageMap(final PrintStream out) {
-        for (final String language : mSortedLanguagesList) {
-            final StringResourceMap resMap = mResourcesMap.get(language);
+        for (final StringResourceMap resMap : mResourcesMap.values()) {
+            final String language = resMap.mLanguage;
             final Locale locale = LocaleUtils.constructLocaleFromString(language);
             final String languageKeyToDump = locale.getCountry().isEmpty()
                     ? String.format("\"%s\"", language)
@@ -223,18 +193,10 @@
             out.format("        %s, %-15s /* %3d/%3d %s */\n",
                     languageKeyToDump, getArrayNameForLanguage(language) + ",",
                     resMap.getResources().size(), resMap.getOutputArraySize(),
-                    getLanguageDisplayName(language));
+                    LocaleUtils.getLanguageDisplayName(language));
         }
     }
 
-    private static String getLanguageDisplayName(final String language) {
-        final Locale locale = LocaleUtils.constructLocaleFromString(language);
-        if (locale.getLanguage().equals(NO_LANGUAGE_CODE)) {
-            return NO_LANGUAGE_DISPLAY_NAME;
-        }
-        return locale.getDisplayName(Locale.ENGLISH);
-    }
-
     private int dumpTextsInternal(final PrintStream out, final StringResourceMap resMap) {
         final ArrayInitializerFormatter formatter =
                 new ArrayInitializerFormatter(out, 100, "        ", mSortedResourceNames);
@@ -289,13 +251,4 @@
         }
         return sb.toString();
     }
-
-    private static void close(final Closeable stream) {
-        try {
-            if (stream != null) {
-                stream.close();
-            }
-        } catch (IOException e) {
-        }
-    }
 }
diff --git a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java
index 4eff8a2..8cdc17d 100644
--- a/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java
+++ b/tools/make-keyboard-text/src/com/android/inputmethod/keyboard/tools/StringResourceMap.java
@@ -34,6 +34,8 @@
 import javax.xml.parsers.SAXParserFactory;
 
 public class StringResourceMap {
+    // Lanugage name.
+    public final String mLanguage;
     // String resource list.
     private final List<StringResource> mResources;
     // Name to string resource map.
@@ -45,22 +47,28 @@
     // {@link MoreKeysResources#dumpLanguageMap(OutputStream)} via {@link #getOutputArraySize()}.
     private int mOutputArraySize;
 
-    public StringResourceMap(final InputStream is) {
+    public StringResourceMap(final String jarEntryName) {
+        mLanguage = JarUtils.getLanguageFromEntryName(jarEntryName);
         final StringResourceHandler handler = new StringResourceHandler();
         final SAXParserFactory factory = SAXParserFactory.newInstance();
         factory.setNamespaceAware(true);
+        final InputStream stream = JarUtils.openResource(jarEntryName);
         try {
             final SAXParser parser = factory.newSAXParser();
             // In order to get comment tag.
             parser.setProperty("http://xml.org/sax/properties/lexical-handler", handler);
-            parser.parse(is, handler);
+            parser.parse(stream, handler);
         } catch (ParserConfigurationException e) {
+            throw new RuntimeException(e.getMessage(), e);
         } catch (SAXParseException e) {
             throw new RuntimeException(e.getMessage() + " at line " + e.getLineNumber()
-                    + ", column " + e.getColumnNumber());
+                    + ", column " + e.getColumnNumber(), e);
         } catch (SAXException e) {
-            throw new RuntimeException(e.getMessage());
+            throw new RuntimeException(e.getMessage(), e);
         } catch (IOException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        } finally {
+            JarUtils.close(stream);
         }
 
         mResources = Collections.unmodifiableList(handler.mResources);