Merge "Move splash screen to separate file"
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
index f1212f9..2919b9b 100644
--- a/java/res/values-af/strings.xml
+++ b/java/res/values-af/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Geen wagperiode nie"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Verstek"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms."</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Stelsel se verstek"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Stel kontakname voor"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Gebruik name van kontakte vir voorstelle en korreksies"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Dubbelspasie-punt"</string>
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
index d388827..65382de 100644
--- a/java/res/values-am/strings.xml
+++ b/java/res/values-am/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"የዘገየ የለም"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ነባሪ"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ሚሊሰከንድ"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"የስርዓት ነባሪ"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"የዕውቂያ ስም ጠቁም"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"ከዕውቂያዎች ለጥቆማዎች እና ማስተካከያዎች ስሞች ተጠቀም"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"የድርብ-ክፍተት ነጥብ"</string>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index 3f0add8..6f18c94 100644
--- a/java/res/values-ar/strings.xml
+++ b/java/res/values-ar/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"بلا تأخير"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"افتراضي"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> مللي ثانية"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"الإعداد الافتراضي للنظام"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"اقتراح أسماء جهات الاتصال"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"استخدام الأسماء من جهات الاتصال للاقتراحات والتصحيحات"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"نقطة المسافة المزدوجة"</string>
diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml
index 6aa48ef..e5db3f6 100644
--- a/java/res/values-be/strings.xml
+++ b/java/res/values-be/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Няма затрымкі"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Па змаўчанні"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> мс"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Прапан. імёны кантактаў"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Выкарыстоўваць імёны са спісу кантактаў для прапаноў і выпраўл."</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Падвойны iнтэрвал"</string>
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
index 2fb2cd6..21318fd 100644
--- a/java/res/values-bg/strings.xml
+++ b/java/res/values-bg/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без задържане"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"По подразбиране"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> милисек"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Предложения за контакти"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Използване на имена от „Контакти“ за предложения и поправки"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Точка чрез двоен интервал"</string>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
index beb5e56..18cff92 100644
--- a/java/res/values-ca/strings.xml
+++ b/java/res/values-ca/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sense retard"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminat"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Predeterm. del sist."</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Suggereix noms de contactes"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilitza els noms de contactes per fer suggeriments i correccions"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Punt amb doble espai"</string>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index f2a5c21..a053dd5 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez prodlevy"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Výchozí"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Navrhovat jména kontaktů"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Použít jména ze seznamu kontaktů k návrhům a opravám"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Tečka dvojitým mezerníkem"</string>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
index 5838592..88c1d61 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Ingen forsink."</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Foreslå navne på kontakter"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Brug navne fra Kontaktpersoner til forslag og rettelser"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"To mellemrum for punktum"</string>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
index 4e7bbe0..ca66b77 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Keine Verzögerung"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Systemstandardeinstellung"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Kontakte vorschlagen"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Namen aus \"Kontakte\" als Vorschläge und Korrekturmöglichkeiten anzeigen"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Punkt plus Leerzeichen"</string>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index 700e1fc..28630bf 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Χωρίς καθυστέρ."</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Προεπιλογή"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>χλστ. δ."</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Προεπιλογή συστήμ."</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Πρόταση ονομάτων επαφών"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Χρησιμοποιήστε ονόματα από τις Επαφές για προτάσεις και διορθ."</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Τελεία με διπλό πάτημα πλήκτρ.διαστ."</string>
diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
index 4bc6d9c..df29be3 100644
--- a/java/res/values-en-rGB/strings.xml
+++ b/java/res/values-en-rGB/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"No delay"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"System default"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Suggest Contact names"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Use names from Contacts for suggestions and corrections"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Double-space full stop"</string>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index ee429fc..f3ca575 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sin demora"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminada"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nombres de contacto"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Usar nombres de los contactos para sugerencias y correcciones"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Punto y doble espacio"</string>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
index 0bdb06e..117ac95 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sin retraso"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predeterminado"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Predeterminado"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir contactos"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizar nombres de contactos para sugerencias y correcciones"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Punto y espacio"</string>
diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml
index 5e92d1c..8fb0c46 100644
--- a/java/res/values-et/strings.xml
+++ b/java/res/values-et/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Viivituseta"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Vaikeseade"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Soovita kontaktkirjeid"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Kasuta soovitusteks ja parandusteks nimesid kontaktiloendist"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Punkt tühikuklahviga"</string>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
index 502355e..c2cef70 100644
--- a/java/res/values-fa/strings.xml
+++ b/java/res/values-fa/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"بدون تأخیر"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"پیش‌فرض"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> میلی‌ثانیه"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"پیشنهاد نام‌های مخاطب"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"برای پیشنهاد و تصحیح از نام مخاطبین استفاده شود"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"نقطه با دو فاصله"</string>
diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml
index 563d3ae..3d8a2a6 100644
--- a/java/res/values-fi/strings.xml
+++ b/java/res/values-fi/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Ei viivettä"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Oletus"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Ehdota yhteystietojen nimiä"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Käytä yhteystietojen nimiä ehdotuksissa ja korjauksissa"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Kaksoisvälilyönti = piste"</string>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index 9198a7d..76a7662 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sans délai"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Par défaut"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Proposer noms de contacts"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utiliser des noms de contacts pour les suggestions et corrections"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Point et espace"</string>
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index 3b6a6c3..cbccb6f 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"कोई विलंब नहीं"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"डिफ़ॉल्ट"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> मिलीसेकंड"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"संपर्क नाम सुझाएं"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"सुझाव और सुधार के लिए संपर्क से नामों का उपयोग करें"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"दोहरे स्पेस वाला पीरियड"</string>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index 264192b..b682599 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez odgode"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Zadano"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Predlaži imena kontakata"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Upotreba imena iz Kontakata za prijedloge i ispravke"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Točka s dva razmaka"</string>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
index 167b43b..cba6966 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Nincs késés"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Alapbeállítás"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Javasolt névjegyek"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"A névjegyek használata a javaslatokhoz és javításokhoz"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Dupla szóköz: pont"</string>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
index 7550b9d..530a21c 100644
--- a/java/res/values-in/strings.xml
+++ b/java/res/values-in/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Tanpa penundaan"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> md"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Sarankan nama Kontak"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Menggunakan nama dari Kontak untuk saran dan koreksi"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Titik spasi ganda"</string>
diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml
index ed8bfa6..73873c4 100644
--- a/java/res/values-it/strings.xml
+++ b/java/res/values-it/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Nessun ritardo"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predefinito"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Suggerisci nomi di contatti"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizza nomi di Contatti per suggerimenti e correzioni"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Doppio spazio per punto"</string>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index 6c9ab85..44cbcfc 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"ללא עיכוב"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ברירת מחדל"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> אלפ\' שניה"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"הצע שמות של אנשי קשר"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"השתמש בשמות מרשימת אנשי הקשר עבור הצעות ותיקונים"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"רווח כפול לנקודה"</string>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index e0af4b0..e01c492 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"すぐに消去"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"デフォルト"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ミリ秒"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"連絡先の名前を候補に表示"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"連絡先の名前を使用して候補表示や自動修正を行います"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"ダブルスペースピリオド"</string>
diff --git a/java/res/values-ka/strings.xml b/java/res/values-ka/strings.xml
index 7630cde..bc8bda3 100644
--- a/java/res/values-ka/strings.xml
+++ b/java/res/values-ka/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"არ დაყოვნდეს"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ნაგულისხმევი"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>მწმ"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"კონტაქტის სახელების შეთავაზება"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"კონტაქტებიდან სახელების გამოყენება შეთავაზებებისთვის და კორექციისთვის"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"წერტილი ორმაგი შორისით"</string>
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
index b481899..67cbc3b 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"지연 없음"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"기본값"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"주소록 이름 활용"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"추천 및 수정에 주소록의 이름 사용"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"더블스페이스 마침표"</string>
diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml
index b877ffa..3cf3e3d 100644
--- a/java/res/values-lt/strings.xml
+++ b/java/res/values-lt/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Be delsos"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Numatytasis"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Siūlyti kontaktų vardus"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Siūlant ir taisant naudoti vardus iš „Kontaktų“"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Tšk. ir tarp. pal. dukart"</string>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
index 9ad5fc2..45b9857 100644
--- a/java/res/values-lv/strings.xml
+++ b/java/res/values-lv/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez aizkaves"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Noklusējums"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Ieteikt kontaktp. vārdus"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Izmantot kontaktpersonu vārdus kā ieteikumus un labojumus"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Dubultpiesk. = punkts"</string>
diff --git a/java/res/values-mn/strings.xml b/java/res/values-mn/strings.xml
index eb2ba85..a75146f 100644
--- a/java/res/values-mn/strings.xml
+++ b/java/res/values-mn/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Хүлээхгүй"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Үндсэн"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>мс"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Харилцагчдын нэрс санал болгох"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Санал болгох, залруулахда Харилцагчдын нэрсээс ашиглах"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Давхар зайтай цэг"</string>
diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml
index bb001ef..fec3cea 100644
--- a/java/res/values-ms/strings.xml
+++ b/java/res/values-ms/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Tiada lengah"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Lalai"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Lalai sistem"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Cadangkan nama Kenalan"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Menggunakan nama daripada Kenalan untuk cadangan dan pembetulan"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Titik ruang berganda"</string>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
index fc0c01e..9544108 100644
--- a/java/res/values-nb/strings.xml
+++ b/java/res/values-nb/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"U/ forsinkelse"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Systemstandard"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Foreslå kontaktnavn"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Bruk navn fra Kontakter til forslag og korrigeringer"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Punktum ved doble mellomrom"</string>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
index 64d64b5..08b14d4 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Geen vertraging"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standaard"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Systeemstandaard"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Contactnamen suggereren"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Namen uit Contacten gebruiken voor suggesties en correcties"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Dubbeltik is punt, spatie"</string>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
index 0a8f568..6f2f2c4 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez opóźnienia"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Wartość domyślna"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Proponuj osoby z kontaktów"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"W propozycjach i poprawkach użyj nazwisk z kontaktów"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Szybka kropka ze spacją"</string>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index afd01ea..3c51154 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sem atraso"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predefinido"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Predef. do sistema"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nomes de Contactos"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizar nomes dos Contactos para sugestões e correções"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Ponto de espaço duplo"</string>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index 907eee8..7bc225d 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Sem atraso"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Padrão"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Padrão do sistema"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Sugerir nomes de contato"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Usar nomes dos Contatos para sugestões e correções"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Duplo espaço p/ ponto"</string>
diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml
index f777c52..9eee1bb 100644
--- a/java/res/values-rm/strings.xml
+++ b/java/res/values-rm/strings.xml
@@ -63,6 +63,8 @@
     <skip />
     <!-- no translation found for abbreviation_unit_milliseconds (8700286094028323363) -->
     <skip />
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <!-- no translation found for use_contacts_dict (4435317977804180815) -->
     <skip />
     <!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index 0c81a62..b251ea5 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Fără întârziere"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Prestabilit"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> msec."</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Sugeraţi nume din Agendă"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Utilizaţi numele din Agendă pentru sugestii şi corecţii"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Inserează punct spațiu"</string>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index b00fa65..86be0a7 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без задержки"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"По умолчанию"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> мс"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Подсказывать имена"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Подсказывать исправления на основе имен из списка контактов"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Ставить точки автоматически"</string>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
index a52a5b9..de1efb4 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Bez oneskorenia"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Predvolená"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Navrhnúť mená kontaktov"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Používať mená z Kontaktov na návrhy a opravy"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Bodka s medzerou"</string>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index c09e2e0..f2bfc31 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Brez zakasnitve"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Privzeto"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Privzeto v sistemu"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Predlagaj imena stikov"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Uporaba imen iz stikov za predloge in popravke"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Dva presl. za vnos pike"</string>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index c44671a..d5c9d30 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без одлагања"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Подразумевано"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Предложи имена контаката"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Користи имена из Контаката за предлоге и исправке"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Тачка и размак"</string>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
index 1b0bd01..539623b 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Fördröj inte"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Standard"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> millisek."</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Standardinställning"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Föreslå kontaktnamn"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Använd namn från Kontakter för förslag och korrigeringar"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Dubbelt blanksteg = punkt"</string>
diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml
index 116ce16..50ae4dc 100644
--- a/java/res/values-sw/strings.xml
+++ b/java/res/values-sw/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Hakuna kuchelewa"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Chaguo-msingi"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"Milisekunde <xliff:g id="MILLISECONDS">%s</xliff:g>"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Chaguo-msingi la mfumo"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Pendekeza majini ya Anwani"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Tumia majina kutoka kwa Anwani kwa mapendekezo na marekebisho"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Kitone baada ya nafasi mbili"</string>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
index 0501936..2aa5c49 100644
--- a/java/res/values-th/strings.xml
+++ b/java/res/values-th/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"ไม่มีการหน่วงเวลา"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"ค่าเริ่มต้น"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> มิลลิวิ"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"แนะนำชื่อผู้ติดต่อ"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"ใช้ชื่อจากรายชื่อติดต่อสำหรับคำแนะนำและการแก้ไข"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"แตะ Space สองครั้งแทรกจุด"</string>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
index 6437345..96f4d9d 100644
--- a/java/res/values-tl/strings.xml
+++ b/java/res/values-tl/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Walang antala"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Default"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Mungkahi pangalan Contact"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Gamitin pangalan mula Mga Contact sa mga mungkahi\'t pagwawasto"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Double-space period"</string>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index e85372e..1f5e0ba 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Gecikme yok"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Varsayılan"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> ms"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Kişi Adları öner"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Öneri ve düzeltmeler için Kişiler\'deki adları kullan"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Çift boşlukla nokta ekleme"</string>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
index 47f2132..a24eab7 100644
--- a/java/res/values-uk/strings.xml
+++ b/java/res/values-uk/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Без затримки"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"За умовчанням"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> мс"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"За умовчанням"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Пропон. імена контактів"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Використ. імена зі списку контактів для пропозицій і виправлень"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Крапка подвійним пробілом"</string>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
index c4bfaa4..3926fe3 100644
--- a/java/res/values-vi/strings.xml
+++ b/java/res/values-vi/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Không có tgian trễ"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Mặc định"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> mili giây"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"Đề xuất tên liên hệ"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Sử dụng tên từ Danh bạ cho các đề xuất và chỉnh sửa"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Dấu cách đôi"</string>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index a5bbab2..3a33343 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"无延迟"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"默认"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>毫秒"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"联系人姓名建议"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"根据通讯录中的姓名提供建议和更正"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"双击空格插入句号"</string>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index a0a017a..7720610 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -43,6 +43,8 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"不延遲"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"預設"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> 毫秒"</string>
+    <!-- no translation found for settings_system_default (6268225104743331821) -->
+    <skip />
     <string name="use_contacts_dict" msgid="4435317977804180815">"建議聯絡人名稱"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"根據「聯絡人」名稱提供建議與修正"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"輕按兩下空格鍵即插入句號"</string>
diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml
index 0629c6c..21cf1db 100644
--- a/java/res/values-zu/strings.xml
+++ b/java/res/values-zu/strings.xml
@@ -43,6 +43,7 @@
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"Cha ukulibazisa"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"Okuzenzakalelayo"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g>ms"</string>
+    <string name="settings_system_default" msgid="6268225104743331821">"Okuzenzakalelayo kwesistimu"</string>
     <string name="use_contacts_dict" msgid="4435317977804180815">"Sikisela amagama Othintana nabo"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"Amagama abasebenzisi kusuka Kothintana nabo bokusikisela nokulungisa"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"Isikhathi se-Double-space"</string>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index cdc2c3a..f24b433 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -79,7 +79,7 @@
 
     <!-- Units abbreviation for the duration (milliseconds) [CHAR LIMIT=10] -->
     <string name="abbreviation_unit_milliseconds"><xliff:g id="milliseconds">%s</xliff:g>ms</string>
-    <!-- The text that represents the current settings value is the system default [CHAR LIMIT=20] -->
+    <!-- The text that represents the current settings value is the system default [CHAR LIMIT=25] -->
     <string name="settings_system_default">System default</string>
 
     <!-- Option name for enabling or disabling the use of names of people in Contacts for suggestion and correction [CHAR LIMIT=25] -->
diff --git a/java/res/xml-sw600dp/keys_dvorak_123.xml b/java/res/xml-sw600dp/keys_dvorak_123.xml
index 635ea04..851c14b 100644
--- a/java/res/xml-sw600dp/keys_dvorak_123.xml
+++ b/java/res/xml-sw600dp/keys_dvorak_123.xml
@@ -21,20 +21,40 @@
 <merge
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
-    <Key
-        latin:keyLabel="\'"
-        latin:keyHintLabel="&quot;"
-        latin:moreKeys="!"
-        latin:keyStyle="hasShiftedLetterHintStyle" />
-    <Key
-        latin:keyLabel=","
-        latin:keyHintLabel="&lt;"
-        latin:moreKeys="\?"
-        latin:keyStyle="hasShiftedLetterHintStyle" />
-    <Key
-        latin:keyLabel="."
-        latin:keyHintLabel="&gt;"
-        latin:keyLabelFlags="hasPopupHint|preserveCase"
-        latin:moreKeys="!text/more_keys_for_punctuation"
-        latin:keyStyle="hasShiftedLetterHintStyle" />
+    <switch>
+        <case
+            latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+        >
+            <Key
+                latin:keyLabel="&quot;"
+                latin:keyHintLabel="1"
+                latin:additionalMoreKeys="1" />
+            <Key
+                latin:keyLabel="&lt;"
+                latin:keyHintLabel="2"
+                latin:additionalMoreKeys="2" />
+            <Key
+                latin:keyLabel="&gt;"
+                latin:keyHintLabel="3"
+                latin:additionalMoreKeys="3" />
+        </case>
+        <default>
+            <Key
+                latin:keyLabel="\'"
+                latin:keyHintLabel="1"
+                latin:additionalMoreKeys="1"
+                latin:moreKeys="!,&quot;" />
+            <Key
+                latin:keyLabel=","
+                latin:keyHintLabel="2"
+                latin:additionalMoreKeys="2"
+                latin:moreKeys="\?,&lt;" />
+            <Key
+                latin:keyLabel="."
+                latin:keyHintLabel="3"
+                latin:additionalMoreKeys="3"
+                latin:keyLabelFlags="hasPopupHint|preserveCase"
+                latin:moreKeys="!text/more_keys_for_punctuation,%,&gt;" />
+        </default>
+    </switch>
 </merge>
diff --git a/java/res/xml-sw600dp/rowkeys_arabic1.xml b/java/res/xml-sw600dp/rowkeys_arabic1.xml
index 6a0e257..3c0acf1 100644
--- a/java/res/xml-sw600dp/rowkeys_arabic1.xml
+++ b/java/res/xml-sw600dp/rowkeys_arabic1.xml
@@ -21,57 +21,87 @@
 <merge
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
-    <!-- U+0636: "ض" ARABIC LETTER DAD -->
+    <!-- U+0636: "ض" ARABIC LETTER DAD
+         U+0661: "١" ARABIC-INDIC DIGIT ONE -->
     <Key
         latin:keyLabel="&#x0636;"
+        latin:keyHintLabel="1"
+        latin:additionalMoreKeys="1,&#x0661;"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+0635: "ص" ARABIC LETTER SAD -->
+    <!-- U+0635: "ص" ARABIC LETTER SAD
+         U+0662: "٢" ARABIC-INDIC DIGIT TWO -->
     <Key
         latin:keyLabel="&#x0635;"
+        latin:keyHintLabel="2"
+        latin:additionalMoreKeys="2,&#x0662;"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+062B: "ث" ARABIC LETTER THEH -->
+    <!-- U+062B: "ث" ARABIC LETTER THEH
+         U+0663: "٣" ARABIC-INDIC DIGIT THREE -->
     <Key
         latin:keyLabel="&#x062B;"
+        latin:keyHintLabel="3"
+        latin:additionalMoreKeys="3,&#x0663;"
         latin:keyLabelFlags="fontNormal" />
     <!-- U+0642: "ق" ARABIC LETTER QAF
-         U+06A8: "ڨ" ARABIC LETTER QAF WITH THREE DOTS ABOVE -->
+         U+06A8: "ڨ" ARABIC LETTER QAF WITH THREE DOTS ABOVE
+         U+0664: "٤" ARABIC-INDIC DIGIT FOUR -->
     <!-- TODO: DroidSansArabic lacks the glyph of U+06A8 ARABIC LETTER QAF WITH THREE DOTS ABOVE -->
     <Key
         latin:keyLabel="&#x0642;"
+        latin:keyHintLabel="4"
+        latin:additionalMoreKeys="4,&#x0664;"
         latin:moreKeys="&#x06A8;"
         latin:keyLabelFlags="fontNormal" />
     <!-- U+0641: "ف" ARABIC LETTER FEH
          U+06A4: "ڤ" ARABIC LETTER VEH
          U+06A2: "ڢ" ARABIC LETTER FEH WITH DOT MOVED BELOW
-         U+06A5: "ڥ" ARABIC LETTER FEH WITH THREE DOTS BELOW -->
+         U+06A5: "ڥ" ARABIC LETTER FEH WITH THREE DOTS BELOW
+         U+0665: "٥" ARABIC-INDIC DIGIT FIVE -->
     <!-- TODO: DroidSansArabic lacks the glyph of U+06A2 ARABIC LETTER FEH WITH DOT MOVED BELOW -->
     <!-- TODO: DroidSansArabic lacks the glyph of U+06A5 ARABIC LETTER FEH WITH THREE DOTS BELOW -->
     <Key
         latin:keyLabel="&#x0641;"
+        latin:keyHintLabel="5"
+        latin:additionalMoreKeys="5,&#x0665;"
         latin:moreKeys="&#x06A4;,&#x06A2;,&#x06A5;"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+063A: "غ" ARABIC LETTER GHAIN -->
+    <!-- U+063A: "غ" ARABIC LETTER GHAIN
+         U+0666: "٦" ARABIC-INDIC DIGIT SIX -->
     <Key
         latin:keyLabel="&#x063A;"
+        latin:keyHintLabel="6"
+        latin:additionalMoreKeys="6,&#x0666;"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+0639: "ع" ARABIC LETTER AIN -->
+    <!-- U+0639: "ع" ARABIC LETTER AIN
+         U+0667: "٧" ARABIC-INDIC DIGIT SEVEN -->
     <Key
         latin:keyLabel="&#x0639;"
+        latin:keyHintLabel="7"
+        latin:additionalMoreKeys="7,&#x0667;"
         latin:keyLabelFlags="fontNormal" />
     <!-- U+0647: "ه" ARABIC LETTER HEH
          U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM
-         U+0647 U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER -->
+         U+0647 U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER
+         U+0668: "٨" ARABIC-INDIC DIGIT EIGHT -->
     <Key
         latin:keyLabel="&#x0647;"
+        latin:keyHintLabel="8"
+        latin:additionalMoreKeys="8,&#x0668;"
         latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+062E: "خ" ARABIC LETTER KHAH -->
+    <!-- U+062E: "خ" ARABIC LETTER KHAH
+         U+0669: "٩" ARABIC-INDIC DIGIT NINE -->
     <Key
         latin:keyLabel="&#x062E;"
+        latin:keyHintLabel="9"
+        latin:additionalMoreKeys="9,&#x0669;"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+062D: "ح" ARABIC LETTER HAH -->
+    <!-- U+062D: "ح" ARABIC LETTER HAH
+         U+0660: "٠" ARABIC-INDIC DIGIT ZERO -->
     <Key
         latin:keyLabel="&#x062D;"
+        latin:keyHintLabel="0"
+        latin:additionalMoreKeys="0,&#x0660;"
         latin:keyLabelFlags="fontNormal" />
     <!-- U+062C: "ج" ARABIC LETTER JEEM
          U+0686: "چ" ARABIC LETTER TCHEH -->
diff --git a/java/res/xml-sw600dp/rowkeys_farsi1.xml b/java/res/xml-sw600dp/rowkeys_farsi1.xml
index 7b31240..6dd9a65 100644
--- a/java/res/xml-sw600dp/rowkeys_farsi1.xml
+++ b/java/res/xml-sw600dp/rowkeys_farsi1.xml
@@ -21,50 +21,80 @@
 <merge
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
-    <!-- U+0636: "ض" ARABIC LETTER DAD -->
+    <!-- U+0636: "ض" ARABIC LETTER DAD
+         U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE -->
     <Key
         latin:keyLabel="&#x0636;"
+        latin:keyHintLabel="&#x06F1;"
+        latin:additionalMoreKeys="&#x06F1;,1"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+0635: "ص" ARABIC LETTER SAD -->
+    <!-- U+0635: "ص" ARABIC LETTER SAD
+         U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO -->
     <Key
         latin:keyLabel="&#x0635;"
+        latin:keyHintLabel="&#x06F2;"
+        latin:additionalMoreKeys="&#x06F2;,2"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+062B: "ث" ARABIC LETTER THEH -->
+    <!-- U+062B: "ث" ARABIC LETTER THEH
+         U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE -->
     <Key
         latin:keyLabel="&#x062B;"
+        latin:keyHintLabel="&#x06F3;"
+        latin:additionalMoreKeys="&#x06F3;,3"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+0642: "ق" ARABIC LETTER QAF -->
+    <!-- U+0642: "ق" ARABIC LETTER QAF
+         U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR -->
     <Key
         latin:keyLabel="&#x0642;"
+        latin:keyHintLabel="&#x06F4;"
+        latin:additionalMoreKeys="&#x06F4;,4"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+0641: "ف" ARABIC LETTER FEH -->
+    <!-- U+0641: "ف" ARABIC LETTER FEH
+         U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE -->
     <Key
         latin:keyLabel="&#x0641;"
+        latin:keyHintLabel="&#x06F5;"
+        latin:additionalMoreKeys="&#x06F5;,5"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+063A: "غ" ARABIC LETTER GHAIN -->
+    <!-- U+063A: "غ" ARABIC LETTER GHAIN
+         U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX -->
     <Key
         latin:keyLabel="&#x063A;"
+        latin:keyHintLabel="&#x06F6;"
+        latin:additionalMoreKeys="&#x06F6;,6"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+0639: "ع" ARABIC LETTER AIN -->
+    <!-- U+0639: "ع" ARABIC LETTER AIN
+         U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN -->
     <Key
         latin:keyLabel="&#x0639;"
+        latin:keyHintLabel="&#x06F7;"
+        latin:additionalMoreKeys="&#x06F7;,7"
         latin:keyLabelFlags="fontNormal" />
     <!-- U+0647: "ه" ARABIC LETTER HEH
          U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM
          U+0647/U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER
          U+0647/U+0654: ARABIC LETTER HEH + ARABIC HAMZA ABOVE
-         U+0629: "ة" ARABIC LETTER TEH MARBUTA -->
+         U+0629: "ة" ARABIC LETTER TEH MARBUTA
+         U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT -->
     <Key
         latin:keyLabel="&#x0647;"
         latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;,&#x0647;&#x0654;,&#x0629;,%"
+        latin:keyHintLabel="&#x06F8;"
+        latin:additionalMoreKeys="&#x06F8;,8"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+062E: "خ" ARABIC LETTER KHAH -->
+    <!-- U+062E: "خ" ARABIC LETTER KHAH
+         U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE -->
     <Key
         latin:keyLabel="&#x062E;"
+        latin:keyHintLabel="&#x06F9;"
+        latin:additionalMoreKeys="&#x06F9;,9"
         latin:keyLabelFlags="fontNormal" />
-    <!-- U+062D: "ح" ARABIC LETTER HAH -->
+    <!-- U+062D: "ح" ARABIC LETTER HAH
+         U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO -->
     <Key
         latin:keyLabel="&#x062D;"
+        latin:keyHintLabel="&#x06F0;"
+        latin:additionalMoreKeys="&#x06F0;,0"
         latin:keyLabelFlags="fontNormal" />
     <!-- U+062C: "ج" ARABIC LETTER JEEM -->
     <Key
diff --git a/java/res/xml-sw600dp/rows_azerty.xml b/java/res/xml-sw600dp/rows_azerty.xml
index 824ee38..5a5a7d1 100644
--- a/java/res/xml-sw600dp/rows_azerty.xml
+++ b/java/res/xml-sw600dp/rows_azerty.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="9.0%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_azerty1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_azerty1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_bulgarian.xml b/java/res/xml-sw600dp/rows_bulgarian.xml
index 7253236..2635620 100644
--- a/java/res/xml-sw600dp/rows_bulgarian.xml
+++ b/java/res/xml-sw600dp/rows_bulgarian.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="8.182%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_bulgarian1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_bulgarian1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_bulgarian_bds.xml b/java/res/xml-sw600dp/rows_bulgarian_bds.xml
index db6220e..9439a63 100644
--- a/java/res/xml-sw600dp/rows_bulgarian_bds.xml
+++ b/java/res/xml-sw600dp/rows_bulgarian_bds.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="8.182%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_bulgarian_bds1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_bulgarian_bds1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_colemak.xml b/java/res/xml-sw600dp/rows_colemak.xml
index f7e903b..98a24e4 100644
--- a/java/res/xml-sw600dp/rows_colemak.xml
+++ b/java/res/xml-sw600dp/rows_colemak.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="9.0%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_colemak1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_colemak1" />
         <include
             latin:keyboardLayout="@xml/key_colemak_colon" />
         <Key
diff --git a/java/res/xml-sw600dp/rows_dvorak.xml b/java/res/xml-sw600dp/rows_dvorak.xml
index 2fa8eb2..8859267 100644
--- a/java/res/xml-sw600dp/rows_dvorak.xml
+++ b/java/res/xml-sw600dp/rows_dvorak.xml
@@ -27,10 +27,7 @@
         latin:keyWidth="9.0%p"
     >
         <include
-            latin:keyboardLayout="@xml/keys_dvorak_123" />
-        <include
-            latin:keyboardLayout="@xml/rowkeys_dvorak1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_dvorak1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_east_slavic.xml b/java/res/xml-sw600dp/rows_east_slavic.xml
index 3096255..b4160d6 100644
--- a/java/res/xml-sw600dp/rows_east_slavic.xml
+++ b/java/res/xml-sw600dp/rows_east_slavic.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="8.182%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_east_slavic1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_east_slavic1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_georgian.xml b/java/res/xml-sw600dp/rows_georgian.xml
index 61d3eb0..b0e9e35 100644
--- a/java/res/xml-sw600dp/rows_georgian.xml
+++ b/java/res/xml-sw600dp/rows_georgian.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="9.0%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_georgian1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_georgian1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_greek.xml b/java/res/xml-sw600dp/rows_greek.xml
index 6a10228..de214c6 100644
--- a/java/res/xml-sw600dp/rows_greek.xml
+++ b/java/res/xml-sw600dp/rows_greek.xml
@@ -29,8 +29,7 @@
         <include
             latin:keyboardLayout="@xml/key_greek_semicolon" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_greek1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_greek1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_hebrew.xml b/java/res/xml-sw600dp/rows_hebrew.xml
index f9e6f51..9945dee 100644
--- a/java/res/xml-sw600dp/rows_hebrew.xml
+++ b/java/res/xml-sw600dp/rows_hebrew.xml
@@ -27,10 +27,6 @@
         latin:keyWidth="9.0%p"
     >
         <include
-            latin:keyboardLayout="@xml/key_apostrophe" />
-        <include
-            latin:keyboardLayout="@xml/key_dash" />
-        <include
             latin:keyboardLayout="@xml/rowkeys_hebrew1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
diff --git a/java/res/xml-sw600dp/rows_hindi.xml b/java/res/xml-sw600dp/rows_hindi.xml
index 9678465..2a9a419 100644
--- a/java/res/xml-sw600dp/rows_hindi.xml
+++ b/java/res/xml-sw600dp/rows_hindi.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="8.182%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_hindi1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_hindi1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_mongolian.xml b/java/res/xml-sw600dp/rows_mongolian.xml
index cfd8c8c..dc0c1fe 100644
--- a/java/res/xml-sw600dp/rows_mongolian.xml
+++ b/java/res/xml-sw600dp/rows_mongolian.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="8.182%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_mongolian1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_mongolian1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_nordic.xml b/java/res/xml-sw600dp/rows_nordic.xml
index 4314403..299bf89 100644
--- a/java/res/xml-sw600dp/rows_nordic.xml
+++ b/java/res/xml-sw600dp/rows_nordic.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="8.182%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_nordic1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_nordic1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_qwerty.xml b/java/res/xml-sw600dp/rows_qwerty.xml
index bac02fd..722f9d1 100644
--- a/java/res/xml-sw600dp/rows_qwerty.xml
+++ b/java/res/xml-sw600dp/rows_qwerty.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="9.0%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_qwerty1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_qwerty1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_qwertz.xml b/java/res/xml-sw600dp/rows_qwertz.xml
index 98ddd08..f2f832c 100644
--- a/java/res/xml-sw600dp/rows_qwertz.xml
+++ b/java/res/xml-sw600dp/rows_qwertz.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="9.0%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_qwertz1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_qwertz1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_south_slavic.xml b/java/res/xml-sw600dp/rows_south_slavic.xml
index e53a2ee..6ef6643 100644
--- a/java/res/xml-sw600dp/rows_south_slavic.xml
+++ b/java/res/xml-sw600dp/rows_south_slavic.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="8.182%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_south_slavic1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_south_slavic1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw600dp/rows_spanish.xml b/java/res/xml-sw600dp/rows_spanish.xml
index b48ee01..bca9bba 100644
--- a/java/res/xml-sw600dp/rows_spanish.xml
+++ b/java/res/xml-sw600dp/rows_spanish.xml
@@ -27,8 +27,7 @@
         latin:keyWidth="9.0%p"
     >
         <include
-            latin:keyboardLayout="@xml/rowkeys_qwerty1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_qwerty1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw768dp/rows_azerty.xml b/java/res/xml-sw768dp/rows_azerty.xml
index dcc403b..cf4bc92 100644
--- a/java/res/xml-sw768dp/rows_azerty.xml
+++ b/java/res/xml-sw768dp/rows_azerty.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_azerty1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_azerty1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw768dp/rows_bulgarian.xml b/java/res/xml-sw768dp/rows_bulgarian.xml
index 6453414..bdc1262 100644
--- a/java/res/xml-sw768dp/rows_bulgarian.xml
+++ b/java/res/xml-sw768dp/rows_bulgarian.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_bulgarian1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_bulgarian1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw768dp/rows_bulgarian_bds.xml b/java/res/xml-sw768dp/rows_bulgarian_bds.xml
index 8acb4d2..58c4611 100644
--- a/java/res/xml-sw768dp/rows_bulgarian_bds.xml
+++ b/java/res/xml-sw768dp/rows_bulgarian_bds.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_bulgarian_bds1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_bulgarian_bds1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw768dp/rows_colemak.xml b/java/res/xml-sw768dp/rows_colemak.xml
index db9b0c2..073f812 100644
--- a/java/res/xml-sw768dp/rows_colemak.xml
+++ b/java/res/xml-sw768dp/rows_colemak.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_colemak1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_colemak1" />
         <include
             latin:keyboardLayout="@xml/key_colemak_colon" />
         <Key
diff --git a/java/res/xml-sw768dp/rows_dvorak.xml b/java/res/xml-sw768dp/rows_dvorak.xml
index 9416478..60d5dd6 100644
--- a/java/res/xml-sw768dp/rows_dvorak.xml
+++ b/java/res/xml-sw768dp/rows_dvorak.xml
@@ -31,10 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/keys_dvorak_123" />
-        <include
-            latin:keyboardLayout="@xml/rowkeys_dvorak1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_dvorak1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw768dp/rows_east_slavic.xml b/java/res/xml-sw768dp/rows_east_slavic.xml
index a4287f1..420307d 100644
--- a/java/res/xml-sw768dp/rows_east_slavic.xml
+++ b/java/res/xml-sw768dp/rows_east_slavic.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_east_slavic1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_east_slavic1" />
         <Key
             latin:keyLabel="!text/keylabel_for_east_slavic_row1_12" />
         <Key
diff --git a/java/res/xml-sw768dp/rows_georgian.xml b/java/res/xml-sw768dp/rows_georgian.xml
index 74f1a07..3f8bd45 100644
--- a/java/res/xml-sw768dp/rows_georgian.xml
+++ b/java/res/xml-sw768dp/rows_georgian.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_georgian1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_georgian1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight"/>
diff --git a/java/res/xml-sw768dp/rows_greek.xml b/java/res/xml-sw768dp/rows_greek.xml
index aebe129..9e1e00b 100644
--- a/java/res/xml-sw768dp/rows_greek.xml
+++ b/java/res/xml-sw768dp/rows_greek.xml
@@ -33,8 +33,7 @@
         <include
             latin:keyboardLayout="@xml/key_greek_semicolon" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_greek1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_greek1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight"/>
diff --git a/java/res/xml-sw768dp/rows_hebrew.xml b/java/res/xml-sw768dp/rows_hebrew.xml
index e588b83..a5f6dfe 100644
--- a/java/res/xml-sw768dp/rows_hebrew.xml
+++ b/java/res/xml-sw768dp/rows_hebrew.xml
@@ -31,10 +31,6 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/key_apostrophe" />
-        <include
-            latin:keyboardLayout="@xml/key_dash" />
-        <include
             latin:keyboardLayout="@xml/rowkeys_hebrew1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
diff --git a/java/res/xml-sw768dp/rows_hindi.xml b/java/res/xml-sw768dp/rows_hindi.xml
index 510772b..6baf09e 100644
--- a/java/res/xml-sw768dp/rows_hindi.xml
+++ b/java/res/xml-sw768dp/rows_hindi.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_hindi1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_hindi1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw768dp/rows_mongolian.xml b/java/res/xml-sw768dp/rows_mongolian.xml
index 9afd4e2..5f37f87 100644
--- a/java/res/xml-sw768dp/rows_mongolian.xml
+++ b/java/res/xml-sw768dp/rows_mongolian.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_mongolian1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_mongolian1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw768dp/rows_nordic.xml b/java/res/xml-sw768dp/rows_nordic.xml
index 06591a6..13d9399 100644
--- a/java/res/xml-sw768dp/rows_nordic.xml
+++ b/java/res/xml-sw768dp/rows_nordic.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_nordic1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_nordic1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw768dp/rows_qwerty.xml b/java/res/xml-sw768dp/rows_qwerty.xml
index a1deabd..8af18ed 100644
--- a/java/res/xml-sw768dp/rows_qwerty.xml
+++ b/java/res/xml-sw768dp/rows_qwerty.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_qwerty1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_qwerty1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight"/>
diff --git a/java/res/xml-sw768dp/rows_qwertz.xml b/java/res/xml-sw768dp/rows_qwertz.xml
index 801dd38..0dd206d 100644
--- a/java/res/xml-sw768dp/rows_qwertz.xml
+++ b/java/res/xml-sw768dp/rows_qwertz.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_qwertz1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_qwertz1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight"/>
diff --git a/java/res/xml-sw768dp/rows_south_slavic.xml b/java/res/xml-sw768dp/rows_south_slavic.xml
index b556853..6b44c4e 100644
--- a/java/res/xml-sw768dp/rows_south_slavic.xml
+++ b/java/res/xml-sw768dp/rows_south_slavic.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_south_slavic1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_south_slavic1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml-sw768dp/rows_spanish.xml b/java/res/xml-sw768dp/rows_spanish.xml
index 8b80332..4520c10 100644
--- a/java/res/xml-sw768dp/rows_spanish.xml
+++ b/java/res/xml-sw768dp/rows_spanish.xml
@@ -31,8 +31,7 @@
             latin:keyLabelFlags="alignLeft"
             latin:keyWidth="7.969%p" />
         <include
-            latin:keyboardLayout="@xml/rowkeys_qwerty1"
-            latin:keyLabelFlags="disableAdditionalMoreKeys|disableKeyHintLabel" />
+            latin:keyboardLayout="@xml/rowkeys_qwerty1" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyWidth="fillRight"/>
diff --git a/java/res/xml/keys_dvorak_123.xml b/java/res/xml/keys_dvorak_123.xml
index 60e6b6f..7124c89 100644
--- a/java/res/xml/keys_dvorak_123.xml
+++ b/java/res/xml/keys_dvorak_123.xml
@@ -51,7 +51,7 @@
                 latin:keyLabel="\'"
                 latin:keyHintLabel="1"
                 latin:additionalMoreKeys="1"
-                latin:moreKeys="!" />
+                latin:moreKeys="!,&quot;" />
         </default>
     </switch>
     <switch>
@@ -72,13 +72,13 @@
                 latin:keyLabel=","
                 latin:keyHintLabel="2"
                 latin:additionalMoreKeys="2"
-                latin:moreKeys="\?" />
+                latin:moreKeys="\?,&lt;" />
             <Key
                 latin:keyLabel="."
                 latin:keyHintLabel="3"
                 latin:additionalMoreKeys="3"
                 latin:keyLabelFlags="hasPopupHint|preserveCase"
-                latin:moreKeys="!text/more_keys_for_punctuation,%" />
+                latin:moreKeys="!text/more_keys_for_punctuation,%,&gt;" />
         </default>
     </switch>
 </merge>
diff --git a/java/res/xml/rowkeys_dvorak1.xml b/java/res/xml/rowkeys_dvorak1.xml
index 7e0eb6e..033308a 100644
--- a/java/res/xml/rowkeys_dvorak1.xml
+++ b/java/res/xml/rowkeys_dvorak1.xml
@@ -21,6 +21,8 @@
 <merge
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
+    <include
+        latin:keyboardLayout="@xml/keys_dvorak_123" />
     <Key
         latin:keyLabel="p"
         latin:keyHintLabel="4"
diff --git a/java/res/xml/rowkeys_thai1.xml b/java/res/xml/rowkeys_thai1.xml
index 950d2a4..cd53665 100644
--- a/java/res/xml/rowkeys_thai1.xml
+++ b/java/res/xml/rowkeys_thai1.xml
@@ -81,17 +81,33 @@
             <Key
                 latin:keyLabel="&#x0E45;"
                 latin:keyLabelFlags="fontNormal" />
+            <!-- U+0E51: "๑" THAI DIGIT ONE -->
             <Key
+                latin:keyHintLabel="1"
+                latin:additionalMoreKeys="1"
+                latin:moreKeys="&#x0E51;"
                 latin:keyLabel="/" />
+            <!-- U+0E52: "๒" THAI DIGIT TWO -->
             <Key
+                latin:keyHintLabel="2"
+                latin:additionalMoreKeys="2"
+                latin:moreKeys="&#x0E52;"
                 latin:keyLabel="_" />
-            <!-- U+0E20: "ภ" THAI CHARACTER PHO SAMPHAO -->
+            <!-- U+0E20: "ภ" THAI CHARACTER PHO SAMPHAO
+                 U+0E53: "๓" THAI DIGIT THREE -->
             <Key
                 latin:keyLabel="&#x0E20;"
+                latin:keyHintLabel="3"
+                latin:additionalMoreKeys="3"
+                latin:moreKeys="&#x0E53;"
                 latin:keyLabelFlags="fontNormal" />
-            <!-- U+0E16: "ถ" THAI CHARACTER THO THUNG -->
+            <!-- U+0E16: "ถ" THAI CHARACTER THO THUNG
+                 U+0E54: "๔" THAI DIGIT FOUR -->
             <Key
                 latin:keyLabel="&#x0E16;"
+                latin:keyHintLabel="4"
+                latin:additionalMoreKeys="4"
+                latin:moreKeys="&#x0E54;"
                 latin:keyLabelFlags="fontNormal" />
             <!-- U+0020: " " SPACE
                  U+0E38: " ุ" THAI CHARACTER SARA U -->
@@ -109,25 +125,45 @@
                 latin:keyLabel="&#x20;&#x0E36;"
                 latin:code="0x0E36"
                 latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
-            <!-- U+0E04: "ค" THAI CHARACTER KHO KHWAI -->
+            <!-- U+0E04: "ค" THAI CHARACTER KHO KHWAI
+                 U+0E55: "๕" THAI DIGIT FIVE -->
             <Key
                 latin:keyLabel="&#x0E04;"
+                latin:keyHintLabel="5"
+                latin:additionalMoreKeys="5"
+                latin:moreKeys="&#x0E55;"
                 latin:keyLabelFlags="fontNormal" />
-            <!-- U+0E15: "ต" THAI CHARACTER TO TAO -->
+            <!-- U+0E15: "ต" THAI CHARACTER TO TAO
+                 U+0E56: "๖" THAI DIGIT SIX -->
             <Key
                 latin:keyLabel="&#x0E15;"
+                latin:keyHintLabel="6"
+                latin:additionalMoreKeys="6"
+                latin:moreKeys="&#x0E56;"
                 latin:keyLabelFlags="fontNormal" />
-            <!-- U+0E08: "จ" THAI CHARACTER CHO CHAN -->
+            <!-- U+0E08: "จ" THAI CHARACTER CHO CHAN
+                 U+0E57: "๗" THAI DIGIT SEVEN -->
             <Key
                 latin:keyLabel="&#x0E08;"
+                latin:keyHintLabel="7"
+                latin:additionalMoreKeys="7"
+                latin:moreKeys="&#x0E57;"
                 latin:keyLabelFlags="fontNormal" />
-            <!-- U+0E02: "ข" THAI CHARACTER KHO KHAI -->
+            <!-- U+0E02: "ข" THAI CHARACTER KHO KHAI
+                 U+0E58: "๘" THAI DIGIT EIGHT -->
             <Key
                 latin:keyLabel="&#x0E02;"
+                latin:keyHintLabel="8"
+                latin:additionalMoreKeys="8"
+                latin:moreKeys="&#x0E58;"
                 latin:keyLabelFlags="fontNormal" />
-            <!-- U+0E0A: "ช" THAI CHARACTER CHO CHANG -->
+            <!-- U+0E0A: "ช" THAI CHARACTER CHO CHANG
+                 U+0E59: "๙" THAI DIGIT NINE -->
             <Key
                 latin:keyLabel="&#x0E0A;"
+                latin:keyHintLabel="9"
+                latin:additionalMoreKeys="9"
+                latin:moreKeys="&#x0E59;"
                 latin:keyLabelFlags="fontNormal" />
         </default>
     </switch>
diff --git a/java/res/xml/rowkeys_thai2.xml b/java/res/xml/rowkeys_thai2.xml
index f602994..4bcbbbf 100644
--- a/java/res/xml/rowkeys_thai2.xml
+++ b/java/res/xml/rowkeys_thai2.xml
@@ -79,9 +79,13 @@
                 latin:keyLabel="," />
         </case>
         <default>
-            <!-- U+0E46: "ๆ" THAI CHARACTER MAIYAMOK -->
+            <!-- U+0E46: "ๆ" THAI CHARACTER MAIYAMOK
+                 U+0E50: "๐" THAI DIGIT ZERO -->
             <Key
                 latin:keyLabel="&#x0E46;"
+                latin:keyHintLabel="0"
+                latin:additionalMoreKeys="0"
+                latin:moreKeys="&#x0E50;"
                 latin:keyLabelFlags="fontNormal" />
             <!-- U+0E44: "ไ" THAI CHARACTER SARA AI MAIMALAI -->
             <Key
diff --git a/java/res/xml/rows_dvorak.xml b/java/res/xml/rows_dvorak.xml
index 8e3d071..13d7021 100644
--- a/java/res/xml/rows_dvorak.xml
+++ b/java/res/xml/rows_dvorak.xml
@@ -27,8 +27,6 @@
         latin:keyWidth="10%p"
     >
         <include
-            latin:keyboardLayout="@xml/keys_dvorak_123" />
-        <include
             latin:keyboardLayout="@xml/rowkeys_dvorak1" />
         </Row>
     <Row
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
index 0576f66..77f3234 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
@@ -35,8 +35,8 @@
 import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardView;
-import com.android.inputmethod.latin.CollectionUtils;
-import com.android.inputmethod.latin.CoordinateUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.CoordinateUtils;
 
 /**
  * Exposes a virtual view sub-tree for {@link KeyboardView} and generates
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
index ee52de1..8929dc7 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityUtils.java
@@ -33,8 +33,8 @@
 import android.view.inputmethod.EditorInfo;
 
 import com.android.inputmethod.compat.SettingsSecureCompatUtils;
-import com.android.inputmethod.latin.InputTypeUtils;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.InputTypeUtils;
 
 public final class AccessibilityUtils {
     private static final String TAG = AccessibilityUtils.class.getSimpleName();
diff --git a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
index 05d8269..41f5b9a 100644
--- a/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
+++ b/java/src/com/android/inputmethod/accessibility/KeyCodeDescriptionMapper.java
@@ -25,9 +25,9 @@
 import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardId;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.HashMap;
 
diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
index 141e08a..e195a54 100644
--- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
+++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java
@@ -23,10 +23,10 @@
 import android.text.TextUtils;
 import android.text.style.SuggestionSpan;
 
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.SuggestionSpanPickedNotificationReceiver;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
diff --git a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
index bf22305..be9f879 100644
--- a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
+++ b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
@@ -28,6 +28,8 @@
 
 import com.android.inputmethod.compat.DownloadManagerCompatUtils;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.LogUtils;
+import com.android.inputmethod.latin.utils.Utils;
 
 import java.util.LinkedList;
 import java.util.Queue;
@@ -98,7 +100,7 @@
         final boolean mForceStartNow;
         public StartDownloadAction(final String clientId,
                 final WordListMetadata wordList, final boolean forceStartNow) {
-            Utils.l("New download action for client ", clientId, " : ", wordList);
+            LogUtils.l("New download action for client ", clientId, " : ", wordList);
             mClientId = clientId;
             mWordList = wordList;
             mForceStartNow = forceStartNow;
@@ -110,7 +112,7 @@
                 Log.e(TAG, "UpdateAction with a null parameter!");
                 return;
             }
-            Utils.l("Downloading word list");
+            LogUtils.l("Downloading word list");
             final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
             final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db,
                     mWordList.mId, mWordList.mVersion);
@@ -132,7 +134,7 @@
                         + " for an upgrade action. Fall back to download.");
             }
             // Download it.
-            Utils.l("Upgrade word list, downloading", mWordList.mRemoteFilename);
+            LogUtils.l("Upgrade word list, downloading", mWordList.mRemoteFilename);
 
             // TODO: if DownloadManager is disabled or not installed, download by ourselves
             if (null == manager) return;
@@ -142,7 +144,7 @@
             // DownloadManager also stupidly cuts the extension to replace with its own that it
             // gets from the content-type. We need to circumvent this.
             final String disambiguator = "#" + System.currentTimeMillis()
-                    + com.android.inputmethod.latin.Utils.getVersionName(context) + ".dict";
+                    + Utils.getVersionName(context) + ".dict";
             final Uri uri = Uri.parse(mWordList.mRemoteFilename + disambiguator);
             final Request request = new Request(uri);
 
@@ -178,7 +180,7 @@
 
             final long downloadId = UpdateHandler.registerDownloadRequest(manager, request, db,
                     mWordList.mId, mWordList.mVersion);
-            Utils.l("Starting download of", uri, "with id", downloadId);
+            LogUtils.l("Starting download of", uri, "with id", downloadId);
             PrivateLog.log("Starting download of " + uri + ", id : " + downloadId);
         }
     }
@@ -195,7 +197,8 @@
 
         public InstallAfterDownloadAction(final String clientId,
                 final ContentValues wordListValues) {
-            Utils.l("New InstallAfterDownloadAction for client ", clientId, " : ", wordListValues);
+            LogUtils.l("New InstallAfterDownloadAction for client ", clientId, " : ",
+                    wordListValues);
             mClientId = clientId;
             mWordListValues = wordListValues;
         }
@@ -213,7 +216,7 @@
                         + " for an InstallAfterDownload action. Bailing out.");
                 return;
             }
-            Utils.l("Setting word list as installed");
+            LogUtils.l("Setting word list as installed");
             final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
             MetadataDbHelper.markEntryAsFinishedDownloadingAndInstalled(db, mWordListValues);
         }
@@ -229,7 +232,7 @@
         final WordListMetadata mWordList;
 
         public EnableAction(final String clientId, final WordListMetadata wordList) {
-            Utils.l("New EnableAction for client ", clientId, " : ", wordList);
+            LogUtils.l("New EnableAction for client ", clientId, " : ", wordList);
             mClientId = clientId;
             mWordList = wordList;
         }
@@ -240,7 +243,7 @@
                 Log.e(TAG, "EnableAction with a null parameter!");
                 return;
             }
-            Utils.l("Enabling word list");
+            LogUtils.l("Enabling word list");
             final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
             final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db,
                     mWordList.mId, mWordList.mVersion);
@@ -264,7 +267,7 @@
         // The word list to disable. May not be null.
         final WordListMetadata mWordList;
         public DisableAction(final String clientId, final WordListMetadata wordlist) {
-            Utils.l("New Disable action for client ", clientId, " : ", wordlist);
+            LogUtils.l("New Disable action for client ", clientId, " : ", wordlist);
             mClientId = clientId;
             mWordList = wordlist;
         }
@@ -275,7 +278,7 @@
                 Log.e(TAG, "DisableAction with a null word list!");
                 return;
             }
-            Utils.l("Disabling word list : " + mWordList);
+            LogUtils.l("Disabling word list : " + mWordList);
             final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
             final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db,
                     mWordList.mId, mWordList.mVersion);
@@ -311,7 +314,7 @@
         // The word list to make available. May not be null.
         final WordListMetadata mWordList;
         public MakeAvailableAction(final String clientId, final WordListMetadata wordlist) {
-            Utils.l("New MakeAvailable action", clientId, " : ", wordlist);
+            LogUtils.l("New MakeAvailable action", clientId, " : ", wordlist);
             mClientId = clientId;
             mWordList = wordlist;
         }
@@ -328,7 +331,7 @@
                 Log.e(TAG, "Unexpected state of the word list '" + mWordList.mId + "' "
                         + " for a makeavailable action. Marking as available anyway.");
             }
-            Utils.l("Making word list available : " + mWordList);
+            LogUtils.l("Making word list available : " + mWordList);
             // If mLocalFilename is null, then it's a remote file that hasn't been downloaded
             // yet, so we set the local filename to the empty string.
             final ContentValues values = MetadataDbHelper.makeContentValues(0,
@@ -360,7 +363,7 @@
         // The word list to mark pre-installed. May not be null.
         final WordListMetadata mWordList;
         public MarkPreInstalledAction(final String clientId, final WordListMetadata wordlist) {
-            Utils.l("New MarkPreInstalled action", clientId, " : ", wordlist);
+            LogUtils.l("New MarkPreInstalled action", clientId, " : ", wordlist);
             mClientId = clientId;
             mWordList = wordlist;
         }
@@ -377,7 +380,7 @@
                 Log.e(TAG, "Unexpected state of the word list '" + mWordList.mId + "' "
                         + " for a markpreinstalled action. Marking as preinstalled anyway.");
             }
-            Utils.l("Marking word list preinstalled : " + mWordList);
+            LogUtils.l("Marking word list preinstalled : " + mWordList);
             // This word list is pre-installed : we don't have its file. We should reset
             // the local file name to the empty string so that we don't try to open it
             // accidentally. The remote filename may be set by the application if it so wishes.
@@ -401,7 +404,7 @@
         private final String mClientId;
         final WordListMetadata mWordList;
         public UpdateDataAction(final String clientId, final WordListMetadata wordlist) {
-            Utils.l("New UpdateData action for client ", clientId, " : ", wordlist);
+            LogUtils.l("New UpdateData action for client ", clientId, " : ", wordlist);
             mClientId = clientId;
             mWordList = wordlist;
         }
@@ -419,7 +422,7 @@
                 Log.e(TAG, "Trying to update data about a non-existing word list. Bailing out.");
                 return;
             }
-            Utils.l("Updating data about a word list : " + mWordList);
+            LogUtils.l("Updating data about a word list : " + mWordList);
             final ContentValues values = MetadataDbHelper.makeContentValues(
                     oldValues.getAsInteger(MetadataDbHelper.PENDINGID_COLUMN),
                     oldValues.getAsInteger(MetadataDbHelper.TYPE_COLUMN),
@@ -453,7 +456,7 @@
         final boolean mHasNewerVersion;
         public ForgetAction(final String clientId, final WordListMetadata wordlist,
                 final boolean hasNewerVersion) {
-            Utils.l("New TryRemove action for client ", clientId, " : ", wordlist);
+            LogUtils.l("New TryRemove action for client ", clientId, " : ", wordlist);
             mClientId = clientId;
             mWordList = wordlist;
             mHasNewerVersion = hasNewerVersion;
@@ -465,7 +468,7 @@
                 Log.e(TAG, "TryRemoveAction with a null word list!");
                 return;
             }
-            Utils.l("Trying to remove word list : " + mWordList);
+            LogUtils.l("Trying to remove word list : " + mWordList);
             final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
             final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db,
                     mWordList.mId, mWordList.mVersion);
@@ -525,7 +528,7 @@
         // The word list to delete. May not be null.
         final WordListMetadata mWordList;
         public StartDeleteAction(final String clientId, final WordListMetadata wordlist) {
-            Utils.l("New StartDelete action for client ", clientId, " : ", wordlist);
+            LogUtils.l("New StartDelete action for client ", clientId, " : ", wordlist);
             mClientId = clientId;
             mWordList = wordlist;
         }
@@ -536,7 +539,7 @@
                 Log.e(TAG, "StartDeleteAction with a null word list!");
                 return;
             }
-            Utils.l("Trying to delete word list : " + mWordList);
+            LogUtils.l("Trying to delete word list : " + mWordList);
             final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
             final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db,
                     mWordList.mId, mWordList.mVersion);
@@ -564,7 +567,7 @@
         // The word list to delete. May not be null.
         final WordListMetadata mWordList;
         public FinishDeleteAction(final String clientId, final WordListMetadata wordlist) {
-            Utils.l("New FinishDelete action for client", clientId, " : ", wordlist);
+            LogUtils.l("New FinishDelete action for client", clientId, " : ", wordlist);
             mClientId = clientId;
             mWordList = wordlist;
         }
@@ -575,7 +578,7 @@
                 Log.e(TAG, "FinishDeleteAction with a null word list!");
                 return;
             }
-            Utils.l("Trying to delete word list : " + mWordList);
+            LogUtils.l("Trying to delete word list : " + mWordList);
             final SQLiteDatabase db = MetadataDbHelper.getDb(context, mClientId);
             final ContentValues values = MetadataDbHelper.getContentValuesByWordListId(db,
                     mWordList.mId, mWordList.mVersion);
@@ -632,7 +635,7 @@
      * @param reporter a Reporter to send errors to.
      */
     public void execute(final Context context, final ProblemReporter reporter) {
-        Utils.l("Executing a batch of actions");
+        LogUtils.l("Executing a batch of actions");
         Queue<Action> remainingActions = mActions;
         while (!remainingActions.isEmpty()) {
             final Action a = remainingActions.poll();
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryListInterfaceState.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryListInterfaceState.java
index 5ad5900..f1a2a83 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DictionaryListInterfaceState.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryListInterfaceState.java
@@ -18,7 +18,7 @@
 
 import android.view.View;
 
-import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.ArrayList;
 import java.util.HashMap;
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java
index 4fbe162..4aa4d4b 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryProvider.java
@@ -31,6 +31,7 @@
 import android.util.Log;
 
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.LogUtils;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -219,7 +220,7 @@
     @Override
     public Cursor query(final Uri uri, final String[] projection, final String selection,
             final String[] selectionArgs, final String sortOrder) {
-        Utils.l("Uri =", uri);
+        LogUtils.l("Uri =", uri);
         PrivateLog.log("Query : " + uri);
         final String clientId = getClientId(uri);
         final int match = matchUri(uri);
@@ -227,7 +228,7 @@
             case DICTIONARY_V1_WHOLE_LIST:
             case DICTIONARY_V2_WHOLE_LIST:
                 final Cursor c = MetadataDbHelper.queryDictionaries(getContext(), clientId);
-                Utils.l("List of dictionaries with count", c.getCount());
+                LogUtils.l("List of dictionaries with count", c.getCount());
                 PrivateLog.log("Returned a list of " + c.getCount() + " items");
                 return c;
             case DICTIONARY_V2_DICT_INFO:
diff --git a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
index dac1213..c6cadb8 100644
--- a/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
+++ b/java/src/com/android/inputmethod/dictionarypack/MetadataDbHelper.java
@@ -25,6 +25,7 @@
 import android.util.Log;
 
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.LogUtils;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -772,12 +773,12 @@
         if (TextUtils.isEmpty(valuesClientId) || null == valuesMetadataUri
                 || null == valuesMetadataAdditionalId) {
             // We need all these columns to be filled in
-            Utils.l("Missing parameter for updateClientInfo");
+            LogUtils.l("Missing parameter for updateClientInfo");
             return;
         }
         if (!clientId.equals(valuesClientId)) {
             // Mismatch! The client violates the protocol.
-            Utils.l("Received an updateClientInfo request for ", clientId, " but the values "
+            LogUtils.l("Received an updateClientInfo request for ", clientId, " but the values "
                     + "contain a different ID : ", valuesClientId);
             return;
         }
@@ -847,7 +848,7 @@
             final ContentValues r) {
         switch (r.getAsInteger(TYPE_COLUMN)) {
             case TYPE_BULK:
-                Utils.l("Ended processing a wordlist");
+                LogUtils.l("Ended processing a wordlist");
                 // Updating a bulk word list is a three-step operation:
                 // - Add the new entry to the table
                 // - Remove the old entry from the table
@@ -869,7 +870,7 @@
                         // the phone is suddenly cut during an update.
                         final int filenameIndex = c.getColumnIndex(LOCAL_FILENAME_COLUMN);
                         do {
-                            Utils.l("Setting for removal", c.getString(filenameIndex));
+                            LogUtils.l("Setting for removal", c.getString(filenameIndex));
                             filenames.add(c.getString(filenameIndex));
                         } while (c.moveToNext());
                     }
diff --git a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
index 3f917f1..936d00d 100644
--- a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
+++ b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
@@ -38,6 +38,8 @@
 import com.android.inputmethod.compat.ConnectivityManagerCompatUtils;
 import com.android.inputmethod.compat.DownloadManagerCompatUtils;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.LogUtils;
+import com.android.inputmethod.latin.utils.Utils;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -183,8 +185,8 @@
                 final String clientId = cursor.getString(0);
                 final String metadataUri =
                         MetadataDbHelper.getMetadataUriAsString(context, clientId);
-                PrivateLog.log("Update for clientId " + Utils.s(clientId));
-                Utils.l("Update for clientId", clientId, " which uses URI ", metadataUri);
+                PrivateLog.log("Update for clientId " + LogUtils.s(clientId));
+                LogUtils.l("Update for clientId", clientId, " which uses URI ", metadataUri);
                 uris.add(metadataUri);
             } while (cursor.moveToNext());
         } finally {
@@ -211,14 +213,14 @@
      */
     private static void updateClientsWithMetadataUri(final Context context,
             final boolean updateNow, final String metadataUri) {
-        PrivateLog.log("Update for metadata URI " + Utils.s(metadataUri));
+        PrivateLog.log("Update for metadata URI " + LogUtils.s(metadataUri));
         // Adding a disambiguator to circumvent a bug in older versions of DownloadManager.
         // DownloadManager also stupidly cuts the extension to replace with its own that it
         // gets from the content-type. We need to circumvent this.
         final String disambiguator = "#" + System.currentTimeMillis()
-                + com.android.inputmethod.latin.Utils.getVersionName(context) + ".json";
+                + Utils.getVersionName(context) + ".json";
         final Request metadataRequest = new Request(Uri.parse(metadataUri + disambiguator));
-        Utils.l("Request =", metadataRequest);
+        LogUtils.l("Request =", metadataRequest);
 
         final Resources res = context.getResources();
         // By default, download over roaming is allowed and all network types are allowed too.
@@ -254,7 +256,7 @@
         final long downloadId;
         synchronized (sSharedIdProtector) {
             downloadId = manager.enqueue(metadataRequest);
-            Utils.l("Metadata download requested with id", downloadId);
+            LogUtils.l("Metadata download requested with id", downloadId);
             // If there is already a download in progress, it's been there for a while and
             // there is probably something wrong with download manager. It's best to just
             // overwrite the id and request it again. If the old one happens to finish
@@ -326,11 +328,11 @@
      */
     public static long registerDownloadRequest(final DownloadManager manager, final Request request,
             final SQLiteDatabase db, final String id, final int version) {
-        Utils.l("RegisterDownloadRequest for word list id : ", id, ", version ", version);
+        LogUtils.l("RegisterDownloadRequest for word list id : ", id, ", version ", version);
         final long downloadId;
         synchronized (sSharedIdProtector) {
             downloadId = manager.enqueue(request);
-            Utils.l("Download requested with id", downloadId);
+            LogUtils.l("Download requested with id", downloadId);
             MetadataDbHelper.markEntryAsDownloading(db, id, version, downloadId);
         }
         return downloadId;
@@ -416,7 +418,7 @@
         // Get and check the ID of the file that was downloaded
         final long fileId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, NOT_AN_ID);
         PrivateLog.log("Download finished with id " + fileId);
-        Utils.l("DownloadFinished with id", fileId);
+        LogUtils.l("DownloadFinished with id", fileId);
         if (NOT_AN_ID == fileId) return; // Spurious wake-up: ignore
 
         final DownloadManager manager =
@@ -426,7 +428,7 @@
         final ArrayList<DownloadRecord> recordList =
                 getDownloadRecordsForCompletedDownloadInfo(context, downloadInfo);
         if (null == recordList) return; // It was someone else's download.
-        Utils.l("Received result for download ", fileId);
+        LogUtils.l("Received result for download ", fileId);
 
         // TODO: handle gracefully a null pointer here. This is practically impossible because
         // we come here only when DownloadManager explicitly called us when it ended a
@@ -503,7 +505,7 @@
     private static void publishUpdateCycleCompletedEvent(final Context context) {
         // Even if this is not successful, we have to publish the new state.
         PrivateLog.log("Publishing update cycle completed event");
-        Utils.l("Publishing update cycle completed event");
+        LogUtils.l("Publishing update cycle completed event");
         for (UpdateEventListener listener : linkedCopyOfList(sUpdateEventListeners)) {
             listener.updateCycleCompleted();
         }
@@ -517,12 +519,12 @@
             // {@link handleWordList(Context,InputStream,ContentValues)}.
             // Handle the downloaded file according to its type
             if (downloadRecord.isMetadata()) {
-                Utils.l("Data D/L'd is metadata for", downloadRecord.mClientId);
+                LogUtils.l("Data D/L'd is metadata for", downloadRecord.mClientId);
                 // #handleMetadata() closes its InputStream argument
                 handleMetadata(context, new ParcelFileDescriptor.AutoCloseInputStream(
                         manager.openDownloadedFile(fileId)), downloadRecord.mClientId);
             } else {
-                Utils.l("Data D/L'd is a word list");
+                LogUtils.l("Data D/L'd is a word list");
                 final int wordListStatus = downloadRecord.mAttributes.getAsInteger(
                         MetadataDbHelper.STATUS_COLUMN);
                 if (MetadataDbHelper.STATUS_DOWNLOADING == wordListStatus) {
@@ -582,7 +584,7 @@
      */
     private static void handleMetadata(final Context context, final InputStream stream,
             final String clientId) throws IOException, BadFormatException {
-        Utils.l("Entering handleMetadata");
+        LogUtils.l("Entering handleMetadata");
         final List<WordListMetadata> newMetadata;
         final InputStreamReader reader = new InputStreamReader(stream);
         try {
@@ -592,7 +594,7 @@
             reader.close();
         }
 
-        Utils.l("Downloaded metadata :", newMetadata);
+        LogUtils.l("Downloaded metadata :", newMetadata);
         PrivateLog.log("Downloaded metadata\n" + newMetadata);
 
         final ActionBatch actions = computeUpgradeTo(context, clientId, newMetadata);
@@ -617,7 +619,7 @@
         // DownloadManager does not have the ability to put the file directly where we want
         // it, so we had it download to a temporary place. Now we move it. It will be deleted
         // automatically by DownloadManager.
-        Utils.l("Downloaded a new word list :", downloadRecord.mAttributes.getAsString(
+        LogUtils.l("Downloaded a new word list :", downloadRecord.mAttributes.getAsString(
                 MetadataDbHelper.DESCRIPTION_COLUMN), "for", downloadRecord.mClientId);
         PrivateLog.log("Downloaded a new word list with description : "
                 + downloadRecord.mAttributes.getAsString(MetadataDbHelper.DESCRIPTION_COLUMN)
@@ -676,9 +678,9 @@
      */
     private static void copyFile(final InputStream in, final OutputStream out)
             throws IOException {
-        Utils.l("Copying files");
+        LogUtils.l("Copying files");
         if (!(in instanceof FileInputStream) || !(out instanceof FileOutputStream)) {
-            Utils.l("Not the right types");
+            LogUtils.l("Not the right types");
             copyFileFallback(in, out);
         } else {
             try {
@@ -687,7 +689,7 @@
                 sourceChannel.transferTo(0, Integer.MAX_VALUE, destinationChannel);
             } catch (IOException e) {
                 // Can't work with channels, or something went wrong. Copy by hand.
-                Utils.l("Won't work");
+                LogUtils.l("Won't work");
                 copyFileFallback(in, out);
             }
         }
@@ -702,7 +704,7 @@
      */
     private static void copyFileFallback(final InputStream in, final OutputStream out)
             throws IOException {
-        Utils.l("Falling back to slow copy");
+        LogUtils.l("Falling back to slow copy");
         final byte[] buffer = new byte[FILE_COPY_BUFFER_SIZE];
         for (int readBytes = in.read(buffer); readBytes >= 0; readBytes = in.read(buffer))
             out.write(buffer, 0, readBytes);
@@ -717,10 +719,10 @@
      */
     private static String getTempFileName(final Context context, final String locale)
             throws IOException {
-        Utils.l("Entering openTempFileOutput");
+        LogUtils.l("Entering openTempFileOutput");
         final File dir = context.getFilesDir();
         final File f = File.createTempFile(locale + "___", DICT_FILE_SUFFIX, dir);
-        Utils.l("File name is", f.getName());
+        LogUtils.l("File name is", f.getName());
         return f.getName();
     }
 
@@ -741,7 +743,7 @@
             final String clientId, List<WordListMetadata> from, List<WordListMetadata> to) {
         final ActionBatch actions = new ActionBatch();
         // Upgrade existing word lists
-        Utils.l("Comparing dictionaries");
+        LogUtils.l("Comparing dictionaries");
         final Set<String> wordListIds = new TreeSet<String>();
         // TODO: Can these be null?
         if (null == from) from = new ArrayList<WordListMetadata>();
@@ -756,7 +758,7 @@
             final WordListMetadata newInfo = null == metadataInfo
                     || metadataInfo.mFormatVersion > MAXIMUM_SUPPORTED_FORMAT_VERSION
                             ? null : metadataInfo;
-            Utils.l("Considering updating ", id, "currentInfo =", currentInfo);
+            LogUtils.l("Considering updating ", id, "currentInfo =", currentInfo);
 
             if (null == currentInfo && null == newInfo) {
                 // This may happen if a new word list appeared that we can't handle.
diff --git a/java/src/com/android/inputmethod/event/EventInterpreter.java b/java/src/com/android/inputmethod/event/EventInterpreter.java
index 6efe899..726b920 100644
--- a/java/src/com/android/inputmethod/event/EventInterpreter.java
+++ b/java/src/com/android/inputmethod/event/EventInterpreter.java
@@ -19,9 +19,9 @@
 import android.util.SparseArray;
 import android.view.KeyEvent;
 
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.LatinIME;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.ArrayList;
 
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 4ef8653..09f1145 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -41,7 +41,7 @@
 import com.android.inputmethod.keyboard.internal.MoreKeySpec;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.StringUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index e87ecbc..fefac96 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -21,8 +21,8 @@
 import com.android.inputmethod.keyboard.internal.KeyVisualAttributes;
 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
 import com.android.inputmethod.keyboard.internal.KeyboardParams;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 /**
  * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 4c5dd25..d00521c 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -25,8 +25,8 @@
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.compat.EditorInfoCompatUtils;
-import com.android.inputmethod.latin.InputTypeUtils;
 import com.android.inputmethod.latin.SubtypeLocale;
+import com.android.inputmethod.latin.utils.InputTypeUtils;
 
 import java.util.Arrays;
 import java.util.Locale;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index a074b63..c4f5eb0 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -42,15 +42,15 @@
 import com.android.inputmethod.keyboard.internal.KeyboardParams;
 import com.android.inputmethod.keyboard.internal.KeysCache;
 import com.android.inputmethod.latin.AdditionalSubtype;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.InputAttributes;
-import com.android.inputmethod.latin.InputTypeUtils;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.ResourceUtils;
 import com.android.inputmethod.latin.SubtypeLocale;
 import com.android.inputmethod.latin.SubtypeSwitcher;
-import com.android.inputmethod.latin.XmlParseUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.InputTypeUtils;
+import com.android.inputmethod.latin.utils.ResourceUtils;
+import com.android.inputmethod.latin.utils.XmlParseUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 7941fcb..4cee4cf 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -32,11 +32,11 @@
 
 import com.android.inputmethod.keyboard.internal.KeyDrawParams;
 import com.android.inputmethod.keyboard.internal.KeyVisualAttributes;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.define.ProductionFlag;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 import com.android.inputmethod.research.ResearchLogger;
 
 import java.util.HashSet;
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 7f33502..8a926d6 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -58,21 +58,21 @@
 import com.android.inputmethod.keyboard.internal.SlidingKeyInputPreview;
 import com.android.inputmethod.keyboard.internal.TouchScreenRegulator;
 import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.CoordinateUtils;
 import com.android.inputmethod.latin.DebugSettings;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.ResourceUtils;
 import com.android.inputmethod.latin.Settings;
-import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
-import com.android.inputmethod.latin.StringUtils;
 import com.android.inputmethod.latin.SubtypeLocale;
 import com.android.inputmethod.latin.SuggestedWords;
-import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils;
 import com.android.inputmethod.latin.define.ProductionFlag;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.CoordinateUtils;
+import com.android.inputmethod.latin.utils.ResourceUtils;
+import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper;
+import com.android.inputmethod.latin.utils.StringUtils;
+import com.android.inputmethod.latin.utils.Utils.UsabilityStudyLogUtils;
 import com.android.inputmethod.research.ResearchLogger;
 
 import java.util.Locale;
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index ae08a59..51f5446 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -28,7 +28,7 @@
 import com.android.inputmethod.keyboard.internal.KeyboardParams;
 import com.android.inputmethod.keyboard.internal.MoreKeySpec;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.StringUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
 
 public final class MoreKeysKeyboard extends Keyboard {
     private final int mDefaultKeyCoordX;
@@ -279,8 +279,14 @@
             mParentKey = parentKey;
 
             final int width, height;
+            // {@link KeyPreviewDrawParams#mPreviewVisibleWidth} should have been set at
+            // {@link MainKeyboardView#showKeyPreview(PointerTracker}, though there may be
+            // some chances that the value is zero. <code>width == 0</code> will cause
+            // zero-division error at
+            // {@link MoreKeysKeyboardParams#setParameters(int,int,int,int,int,int,boolean,int)}.
             final boolean singleMoreKeyWithPreview = parentKeyboardView.isKeyPreviewPopupEnabled()
-                    && !parentKey.noKeyPreview() && parentKey.mMoreKeys.length == 1;
+                    && !parentKey.noKeyPreview() && parentKey.mMoreKeys.length == 1
+                    && keyPreviewDrawParams.mPreviewVisibleWidth > 0;
             if (singleMoreKeyWithPreview) {
                 // Use pre-computed width and height if this more keys keyboard has only one key to
                 // mitigate visual flicker between key preview and more keys keyboard.
@@ -291,22 +297,10 @@
                 // adjusted with their bottom paddings deducted.
                 width = keyPreviewDrawParams.mPreviewVisibleWidth;
                 height = keyPreviewDrawParams.mPreviewVisibleHeight + mParams.mVerticalGap;
-                // TODO: Remove this check.
-                if (width == 0) {
-                    throw new IllegalArgumentException(
-                            "Zero width key detected: " + parentKey + " in " + parentKeyboard.mId);
-                }
             } else {
                 width = getMaxKeyWidth(parentKeyboardView, parentKey, mParams.mDefaultKeyWidth,
                         context.getResources());
                 height = parentKeyboard.mMostCommonKeyHeight;
-                // TODO: Remove this check.
-                if (width == 0) {
-                    throw new IllegalArgumentException(
-                            "Zero width calculated: " + parentKey
-                            + " moreKeys=" + java.util.Arrays.toString(parentKey.mMoreKeys)
-                            + " in " + parentKeyboard.mId);
-                }
             }
             final int dividerWidth;
             if (parentKey.needsDividersInMoreKeys()) {
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index a82fb79..897ad1d 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -23,8 +23,8 @@
 import android.view.View;
 
 import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.CoordinateUtils;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.CoordinateUtils;
 
 /**
  * A view that renders a virtual {@link MoreKeysKeyboard}. It handles rendering of keys and
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 958aaf5..7b14259 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -27,13 +27,13 @@
 import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints;
 import com.android.inputmethod.keyboard.internal.GestureStrokeWithPreviewPoints.GestureStrokePreviewParams;
 import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.CoordinateUtils;
 import com.android.inputmethod.latin.InputPointers;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.define.ProductionFlag;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.CoordinateUtils;
 import com.android.inputmethod.research.ResearchLogger;
 
 import java.util.ArrayList;
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 0e86b05..9b0a33c 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -22,7 +22,7 @@
 
 import com.android.inputmethod.keyboard.internal.TouchPositionCorrection;
 import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.JniUtils;
+import com.android.inputmethod.latin.utils.JniUtils;
 
 import java.util.Arrays;
 
diff --git a/java/src/com/android/inputmethod/keyboard/TypefaceUtils.java b/java/src/com/android/inputmethod/keyboard/TypefaceUtils.java
index 6a54e11..c3b9520 100644
--- a/java/src/com/android/inputmethod/keyboard/TypefaceUtils.java
+++ b/java/src/com/android/inputmethod/keyboard/TypefaceUtils.java
@@ -21,7 +21,7 @@
 import android.graphics.Typeface;
 import android.util.SparseArray;
 
-import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 public final class TypefaceUtils {
     private TypefaceUtils() {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java
index ab810a5..9bfddba 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureFloatingPreviewText.java
@@ -26,9 +26,9 @@
 import android.view.View;
 
 import com.android.inputmethod.keyboard.PointerTracker;
-import com.android.inputmethod.latin.CoordinateUtils;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SuggestedWords;
+import com.android.inputmethod.latin.utils.CoordinateUtils;
 
 /**
  * The class for single gesture preview text. The class for multiple gesture preview text will be
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
index 70363e6..f29ade8 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStroke.java
@@ -21,8 +21,8 @@
 
 import com.android.inputmethod.latin.InputPointers;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.ResizableIntArray;
-import com.android.inputmethod.latin.ResourceUtils;
+import com.android.inputmethod.latin.utils.ResizableIntArray;
+import com.android.inputmethod.latin.utils.ResourceUtils;
 
 public class GestureStroke {
     private static final String TAG = GestureStroke.class.getSimpleName();
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
index 8deadbf..ecc67dd 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeWithPreviewPoints.java
@@ -19,7 +19,7 @@
 import android.content.res.TypedArray;
 
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.ResizableIntArray;
+import com.android.inputmethod.latin.utils.ResizableIntArray;
 
 public final class GestureStrokeWithPreviewPoints extends GestureStroke {
     public static final int PREVIEW_CAPACITY = 256;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTrail.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTrail.java
index fb69e22..aca6679 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureTrail.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTrail.java
@@ -26,7 +26,7 @@
 
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.ResizableIntArray;
+import com.android.inputmethod.latin.utils.ResizableIntArray;
 
 /*
  * @attr ref R.styleable#MainKeyboardView_gestureTrailFadeoutStartDelay
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java
index 1e4c43e..dff5177 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java
@@ -30,8 +30,8 @@
 
 import com.android.inputmethod.keyboard.PointerTracker;
 import com.android.inputmethod.keyboard.internal.GestureTrail.Params;
-import com.android.inputmethod.latin.CollectionUtils;
-import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper;
 
 /**
  * Draw gesture trail preview graphics during gesture.
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java
index 5dcd842..1716fa0 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyDrawParams.java
@@ -18,7 +18,7 @@
 
 import android.graphics.Typeface;
 
-import com.android.inputmethod.latin.ResourceUtils;
+import com.android.inputmethod.latin.utils.ResourceUtils;
 
 public final class KeyDrawParams {
     public Typeface mTypeface;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
index ba449ee..22f5b3d 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
@@ -21,10 +21,10 @@
 
 import android.text.TextUtils;
 
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.LatinImeLogger;
-import com.android.inputmethod.latin.StringUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java
index a048ad0..6aab3e7 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStylesSet.java
@@ -20,9 +20,9 @@
 import android.util.Log;
 import android.util.SparseArray;
 
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.XmlParseUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.XmlParseUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java b/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java
index 6ddd2a6..7a2622c 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyVisualAttributes.java
@@ -21,7 +21,7 @@
 import android.util.SparseIntArray;
 
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.ResourceUtils;
+import com.android.inputmethod.latin.utils.ResourceUtils;
 
 public final class KeyVisualAttributes {
     public final Typeface mTypeface;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index be178f5..26bbd7d 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -29,12 +29,12 @@
 import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardId;
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.ResourceUtils;
-import com.android.inputmethod.latin.StringUtils;
 import com.android.inputmethod.latin.SubtypeLocale;
-import com.android.inputmethod.latin.XmlParseUtils;
+import com.android.inputmethod.latin.utils.LocaleUtils.RunInLocale;
+import com.android.inputmethod.latin.utils.ResourceUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
+import com.android.inputmethod.latin.utils.XmlParseUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
index a9e04bc..d65aae2 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
@@ -16,8 +16,8 @@
 
 package com.android.inputmethod.keyboard.internal;
 
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.HashMap;
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
index 4ac2549..4e3f761 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
@@ -22,8 +22,8 @@
 import android.util.Log;
 import android.util.SparseIntArray;
 
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.HashMap;
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
index 84319eb..a57b83a 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
@@ -20,8 +20,8 @@
 
 import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.keyboard.KeyboardId;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.ArrayList;
 import java.util.TreeSet;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java
index 855f655..5fe84a7 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardRow.java
@@ -23,7 +23,7 @@
 import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.ResourceUtils;
+import com.android.inputmethod.latin.utils.ResourceUtils;
 
 import org.xmlpull.v1.XmlPullParser;
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index e1cee42..370d0cb 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -20,7 +20,7 @@
 import android.util.Log;
 
 import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.RecapitalizeStatus;
+import com.android.inputmethod.latin.utils.RecapitalizeStatus;
 
 /**
  * Keyboard state machine.
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index 7ec1c94..467c15f 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -20,7 +20,7 @@
 import android.content.res.Resources;
 
 import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.HashMap;
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeysCache.java b/java/src/com/android/inputmethod/keyboard/internal/KeysCache.java
index db154a3..7c2e3e1 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeysCache.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeysCache.java
@@ -17,7 +17,7 @@
 package com.android.inputmethod.keyboard.internal;
 
 import com.android.inputmethod.keyboard.Key;
-import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.HashMap;
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java
index b38d79f..110936f 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java
@@ -19,7 +19,7 @@
 import android.text.TextUtils;
 
 import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.StringUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
 
 import java.util.Locale;
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
index 31ef3cd..3dbb7b7 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
@@ -18,7 +18,7 @@
 
 import android.util.Log;
 
-import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.ArrayList;
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
index 2376110..3388c57 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
@@ -24,8 +24,8 @@
 import android.util.AttributeSet;
 import android.widget.RelativeLayout;
 
-import com.android.inputmethod.latin.CollectionUtils;
-import com.android.inputmethod.latin.CoordinateUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.CoordinateUtils;
 
 import java.util.ArrayList;
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java b/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java
index 33dbbaf..5c9d367 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/SlidingKeyInputPreview.java
@@ -23,8 +23,8 @@
 import android.view.View;
 
 import com.android.inputmethod.keyboard.PointerTracker;
-import com.android.inputmethod.latin.CoordinateUtils;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.CoordinateUtils;
 
 /**
  * Draw rubber band preview graphics during sliding key input.
diff --git a/java/src/com/android/inputmethod/keyboard/internal/TouchScreenRegulator.java b/java/src/com/android/inputmethod/keyboard/internal/TouchScreenRegulator.java
index d6b1cc6..fddd985 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/TouchScreenRegulator.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/TouchScreenRegulator.java
@@ -23,8 +23,8 @@
 import com.android.inputmethod.keyboard.MainKeyboardView;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.ResourceUtils;
 import com.android.inputmethod.latin.define.ProductionFlag;
+import com.android.inputmethod.latin.utils.ResourceUtils;
 import com.android.inputmethod.research.ResearchLogger;
 
 public final class TouchScreenRegulator {
diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java
index 85b14d8..0bddeb5 100644
--- a/java/src/com/android/inputmethod/latin/AdditionalSubtype.java
+++ b/java/src/com/android/inputmethod/latin/AdditionalSubtype.java
@@ -25,6 +25,9 @@
 import android.text.TextUtils;
 import android.view.inputmethod.InputMethodSubtype;
 
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
+
 import java.util.ArrayList;
 
 public final class AdditionalSubtype {
diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
index ff5e339..8128e3a 100644
--- a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
+++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
@@ -44,6 +44,9 @@
 import android.widget.SpinnerAdapter;
 import android.widget.Toast;
 
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.IntentUtils;
+
 import java.util.ArrayList;
 import java.util.TreeSet;
 
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index aad129d..05b1a2e 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -21,6 +21,10 @@
 
 import com.android.inputmethod.keyboard.ProximityInfo;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.utils.AdditionalFeaturesSettingUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.JniUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
index c038db8..321e806 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
@@ -28,7 +28,10 @@
 import android.util.Log;
 
 import com.android.inputmethod.dictionarypack.DictionaryPackConstants;
-import com.android.inputmethod.latin.DictionaryInfoUtils.DictionaryInfo;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.DictionaryInfoUtils;
+import com.android.inputmethod.latin.utils.DictionaryInfoUtils.DictionaryInfo;
+import com.android.inputmethod.latin.utils.MetadataFileUriGetter;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 272f36e..d0af59d 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -16,10 +16,6 @@
 
 package com.android.inputmethod.latin;
 
-import com.android.inputmethod.latin.define.ProductionFlag;
-import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
-import com.android.inputmethod.latin.makedict.FormatSpec;
-
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
@@ -27,6 +23,13 @@
 import android.content.res.AssetFileDescriptor;
 import android.util.Log;
 
+import com.android.inputmethod.latin.define.ProductionFlag;
+import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
+import com.android.inputmethod.latin.makedict.FormatSpec;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.DictionaryInfoUtils;
+import com.android.inputmethod.latin.utils.LocaleUtils;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
@@ -39,7 +42,7 @@
 /**
  * Helper class to get the address of a mmap'able dictionary file.
  */
-final class BinaryDictionaryGetter {
+final public class BinaryDictionaryGetter {
 
     /**
      * Used for Log actions from this class
diff --git a/java/src/com/android/inputmethod/latin/ByteArrayWrapper.java b/java/src/com/android/inputmethod/latin/ByteArrayWrapper.java
new file mode 100644
index 0000000..15f70c5
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/ByteArrayWrapper.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface;
+
+/**
+ * This class provides an implementation for the FusionDictionary buffer interface that is backed
+ * by a simpled byte array. It allows to create a binary dictionary in memory.
+ */
+public final class ByteArrayWrapper implements FusionDictionaryBufferInterface {
+    private byte[] mBuffer;
+    private int mPosition;
+
+    public ByteArrayWrapper(final byte[] buffer) {
+        mBuffer = buffer;
+        mPosition = 0;
+    }
+
+    @Override
+    public int readUnsignedByte() {
+        return mBuffer[mPosition++] & 0xFF;
+    }
+
+    @Override
+    public int readUnsignedShort() {
+        final int retval = readUnsignedByte();
+        return (retval << 8) + readUnsignedByte();
+    }
+
+    @Override
+    public int readUnsignedInt24() {
+        final int retval = readUnsignedShort();
+        return (retval << 8) + readUnsignedByte();
+    }
+
+    @Override
+    public int readInt() {
+        final int retval = readUnsignedShort();
+        return (retval << 16) + readUnsignedShort();
+    }
+
+    @Override
+    public int position() {
+        return mPosition;
+    }
+
+    @Override
+    public void position(int position) {
+        mPosition = position;
+    }
+
+    @Override
+    public void put(final byte b) {
+        mBuffer[mPosition++] = b;
+    }
+
+    @Override
+    public int limit() {
+        return mBuffer.length - 1;
+    }
+
+    @Override
+    public int capacity() {
+        return mBuffer.length;
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index b9db9a0..110be9d 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -30,6 +30,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.inputmethod.latin.utils.StringUtils;
+
 import java.util.List;
 import java.util.Locale;
 
diff --git a/java/src/com/android/inputmethod/latin/DebugSettings.java b/java/src/com/android/inputmethod/latin/DebugSettings.java
index 5969a63..d1cb39c 100644
--- a/java/src/com/android/inputmethod/latin/DebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/DebugSettings.java
@@ -29,6 +29,7 @@
 import android.util.Log;
 
 import com.android.inputmethod.keyboard.KeyboardSwitcher;
+import com.android.inputmethod.latin.utils.Utils;
 import com.android.inputmethod.research.ResearchLogger;
 
 public final class DebugSettings extends PreferenceFragment
diff --git a/java/src/com/android/inputmethod/latin/DicTraverseSession.java b/java/src/com/android/inputmethod/latin/DicTraverseSession.java
index 534e211..45b2813 100644
--- a/java/src/com/android/inputmethod/latin/DicTraverseSession.java
+++ b/java/src/com/android/inputmethod/latin/DicTraverseSession.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.latin.utils.JniUtils;
+
 import java.util.Locale;
 
 public final class DicTraverseSession {
diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
index ed2b442..d05bb1e 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
@@ -16,10 +16,11 @@
 
 package com.android.inputmethod.latin;
 
+import android.util.Log;
+
 import com.android.inputmethod.keyboard.ProximityInfo;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-
-import android.util.Log;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.ArrayList;
 import java.util.Collection;
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index 4514ec2..5b98613 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -22,6 +22,8 @@
 import android.util.Log;
 
 import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.DictionaryInfoUtils;
 
 import java.io.File;
 import java.util.ArrayList;
diff --git a/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java b/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java
index 5609612..2dcfdb0 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryPackInstallBroadcastReceiver.java
@@ -17,6 +17,7 @@
 package com.android.inputmethod.latin;
 
 import com.android.inputmethod.dictionarypack.DictionaryPackConstants;
+import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 887d657..f357e2a 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -28,6 +28,7 @@
 import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
 import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
 import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.io.File;
 import java.io.FileOutputStream;
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index 0dabdb8..a67c919 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -22,7 +22,8 @@
 
 import com.android.inputmethod.keyboard.ProximityInfo;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.UserHistoryForgettingCurveUtils.ForgettingCurveParams;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils.ForgettingCurveParams;
 
 import java.util.ArrayList;
 import java.util.LinkedList;
diff --git a/java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java b/java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java
index 9f91639..18f4920 100644
--- a/java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java
+++ b/java/src/com/android/inputmethod/latin/ExternalDictionaryGetterForDebug.java
@@ -23,6 +23,9 @@
 import android.os.Environment;
 
 import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.DictionaryInfoUtils;
+import com.android.inputmethod.latin.utils.LocaleUtils;
 
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
diff --git a/java/src/com/android/inputmethod/latin/InputAttributes.java b/java/src/com/android/inputmethod/latin/InputAttributes.java
index 1f673e9..21b103e 100644
--- a/java/src/com/android/inputmethod/latin/InputAttributes.java
+++ b/java/src/com/android/inputmethod/latin/InputAttributes.java
@@ -20,6 +20,9 @@
 import android.util.Log;
 import android.view.inputmethod.EditorInfo;
 
+import com.android.inputmethod.latin.utils.InputTypeUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
+
 /**
  * Class to hold attributes of the input field.
  */
diff --git a/java/src/com/android/inputmethod/latin/InputPointers.java b/java/src/com/android/inputmethod/latin/InputPointers.java
index 81c8330..e96a46e 100644
--- a/java/src/com/android/inputmethod/latin/InputPointers.java
+++ b/java/src/com/android/inputmethod/latin/InputPointers.java
@@ -17,6 +17,7 @@
 package com.android.inputmethod.latin;
 
 import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.utils.ResizableIntArray;
 
 import android.util.Log;
 
diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java
index 826dc11..cdeadc7 100644
--- a/java/src/com/android/inputmethod/latin/LastComposedWord.java
+++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.latin.utils.StringUtils;
+
 import android.text.TextUtils;
 
 /**
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 73ec578..0efe0eb 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -43,7 +43,7 @@
 import android.os.SystemClock;
 import android.preference.PreferenceManager;
 import android.text.InputType;
-import android.text.SpannableString;
+import android.text.Spanned;
 import android.text.TextUtils;
 import android.text.style.SuggestionSpan;
 import android.util.Log;
@@ -76,9 +76,20 @@
 import com.android.inputmethod.keyboard.MainKeyboardView;
 import com.android.inputmethod.latin.RichInputConnection.Range;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.Utils.Stats;
 import com.android.inputmethod.latin.define.ProductionFlag;
 import com.android.inputmethod.latin.suggestions.SuggestionStripView;
+import com.android.inputmethod.latin.utils.CapsModeUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.CompletionInfoUtils;
+import com.android.inputmethod.latin.utils.InputTypeUtils;
+import com.android.inputmethod.latin.utils.IntentUtils;
+import com.android.inputmethod.latin.utils.JniUtils;
+import com.android.inputmethod.latin.utils.PositionalInfoForUserDictPendingAddition;
+import com.android.inputmethod.latin.utils.RecapitalizeStatus;
+import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper;
+import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask;
+import com.android.inputmethod.latin.utils.Utils;
+import com.android.inputmethod.latin.utils.Utils.Stats;
 import com.android.inputmethod.research.ResearchLogger;
 
 import java.io.FileDescriptor;
@@ -201,6 +212,7 @@
         private static final int MSG_UPDATE_SUGGESTION_STRIP = 2;
         private static final int MSG_SHOW_GESTURE_PREVIEW_AND_SUGGESTION_STRIP = 3;
         private static final int MSG_RESUME_SUGGESTIONS = 4;
+        private static final int MSG_REOPEN_DICTIONARIES = 5;
 
         private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1;
 
@@ -241,6 +253,13 @@
             case MSG_RESUME_SUGGESTIONS:
                 latinIme.restartSuggestionsOnWordTouchedByCursor();
                 break;
+            case MSG_REOPEN_DICTIONARIES:
+                latinIme.initSuggest();
+                // In theory we could call latinIme.updateSuggestionStrip() right away, but
+                // in the practice, the dictionary is not finished opening yet so we wouldn't
+                // get any suggestions. Wait one frame.
+                postUpdateSuggestionStrip();
+                break;
             }
         }
 
@@ -248,6 +267,10 @@
             sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP), mDelayUpdateSuggestions);
         }
 
+        public void postReopenDictionaries() {
+            sendMessage(obtainMessage(MSG_REOPEN_DICTIONARIES));
+        }
+
         public void postResumeSuggestions() {
             removeMessages(MSG_RESUME_SUGGESTIONS);
             sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS), mDelayUpdateSuggestions);
@@ -261,6 +284,10 @@
             return hasMessages(MSG_UPDATE_SUGGESTION_STRIP);
         }
 
+        public boolean hasPendingReopenDictionaries() {
+            return hasMessages(MSG_REOPEN_DICTIONARIES);
+        }
+
         public void postUpdateShiftState() {
             removeMessages(MSG_UPDATE_SHIFT_STATE);
             sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState);
@@ -413,6 +440,12 @@
         }
     }
 
+    // Loading the native library eagerly to avoid unexpected UnsatisfiedLinkError at the initial
+    // JNI call as much as possible.
+    static {
+        JniUtils.loadNativeLibrary();
+    }
+
     public LatinIME() {
         super();
         mSettings = Settings.getInstance();
@@ -474,8 +507,17 @@
                 new InputAttributes(getCurrentInputEditorInfo(), isFullscreenMode());
         mSettings.loadSettings(locale, inputAttributes);
         AudioAndHapticFeedbackManager.getInstance().onSettingsChanged(mSettings.getCurrent());
-        // May need to reset the contacts dictionary depending on the user settings.
-        resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
+        // To load the keyboard we need to load all the settings once, but resetting the
+        // contacts dictionary should be deferred until after the new layout has been displayed
+        // to improve responsivity. In the language switching process, we post a reopenDictionaries
+        // message, then come here to read the settings for the new language before we change
+        // the layout; at this time, we need to skip resetting the contacts dictionary. It will
+        // be done later inside {@see #initSuggest()} when the reopenDictionaries message is
+        // processed.
+        if (!mHandler.hasPendingReopenDictionaries()) {
+            // May need to reset the contacts dictionary depending on the user settings.
+            resetContactsDictionary(null == mSuggest ? null : mSuggest.getContactsDictionary());
+        }
     }
 
     // Note that this method is called from a non-UI thread.
@@ -2470,13 +2512,15 @@
         if (null == range) return; // Happens if we don't have an input connection at all
         // If for some strange reason (editor bug or so) we measure the text before the cursor as
         // longer than what the entire text is supposed to be, the safe thing to do is bail out.
-        if (range.mCharsBefore > mLastSelectionStart) return;
+        final int numberOfCharsInWordBeforeCursor = range.getNumberOfCharsInWordBeforeCursor();
+        if (numberOfCharsInWordBeforeCursor > mLastSelectionStart) return;
         final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
-        final String typedWord = range.mWord.toString();
-        if (range.mWord instanceof SpannableString) {
-            final SpannableString spannableString = (SpannableString)range.mWord;
+        final CharSequence word = range.mWord;
+        final String typedWord = word.toString();
+        if (word instanceof Spanned) {
+            final Spanned spanned = (Spanned)word;
             int i = 0;
-            for (Object object : spannableString.getSpans(0, spannableString.length(),
+            for (Object object : spanned.getSpans(0, spanned.length(),
                     SuggestionSpan.class)) {
                 SuggestionSpan span = (SuggestionSpan)object;
                 for (String s : span.getSuggestions()) {
@@ -2490,9 +2534,10 @@
             }
         }
         mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard());
-        mWordComposer.setCursorPositionWithinWord(range.mCharsBefore);
-        mConnection.setComposingRegion(mLastSelectionStart - range.mCharsBefore,
-                mLastSelectionEnd + range.mCharsAfter);
+        mWordComposer.setCursorPositionWithinWord(numberOfCharsInWordBeforeCursor);
+        mConnection.setComposingRegion(
+                mLastSelectionStart - numberOfCharsInWordBeforeCursor,
+                mLastSelectionEnd + range.getNumberOfCharsInWordAfterCursor());
         final SuggestedWords suggestedWords;
         if (suggestions.isEmpty()) {
             // We come here if there weren't any suggestion spans on this word. We will try to
@@ -2619,18 +2664,17 @@
     // Outside LatinIME, only used by the {@link InputTestsBase} test suite.
     @UsedForTesting
     void loadKeyboard() {
-        // TODO: Why are we calling {@link #loadSettings()} and {@link #initSuggest()} in a
-        // different order than in {@link #onStartInputView}?
-        initSuggest();
+        // Since we are switching languages, the most urgent thing is to let the keyboard graphics
+        // update. LoadKeyboard does that, but we need to wait for buffer flip for it to be on
+        // the screen. Anything we do right now will delay this, so wait until the next frame
+        // before we do the rest, like reopening dictionaries and updating suggestions. So we
+        // post a message.
+        mHandler.postReopenDictionaries();
         loadSettings();
         if (mKeyboardSwitcher.getMainKeyboardView() != null) {
             // Reload keyboard because the current language has been changed.
             mKeyboardSwitcher.loadKeyboard(getCurrentInputEditorInfo(), mSettings.getCurrent());
         }
-        // Since we just changed languages, we should re-evaluate suggestions with whatever word
-        // we are currently composing. If we are not composing anything, we may want to display
-        // predictions or punctuation signs (which is done by the updateSuggestionStrip anyway).
-        mHandler.postUpdateSuggestionStrip();
     }
 
     // Callback called by PointerTracker through the KeyboardActionListener. This is called when a
diff --git a/java/src/com/android/inputmethod/latin/NativeSuggestOptions.java b/java/src/com/android/inputmethod/latin/NativeSuggestOptions.java
index 2915513..07ccd75 100644
--- a/java/src/com/android/inputmethod/latin/NativeSuggestOptions.java
+++ b/java/src/com/android/inputmethod/latin/NativeSuggestOptions.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.latin.utils.AdditionalFeaturesSettingUtils;
+
 public class NativeSuggestOptions {
     // Need to update suggest_options.h when you add, remove or reorder options.
     private static final int IS_GESTURE = 0;
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 980215d..d431ad6 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -17,7 +17,6 @@
 package com.android.inputmethod.latin;
 
 import android.inputmethodservice.InputMethodService;
-import android.text.SpannableString;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -28,6 +27,9 @@
 import android.view.inputmethod.InputConnection;
 
 import com.android.inputmethod.latin.define.ProductionFlag;
+import com.android.inputmethod.latin.utils.CapsModeUtils;
+import com.android.inputmethod.latin.utils.LogUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
 import com.android.inputmethod.research.ResearchLogger;
 
 import java.util.Locale;
@@ -105,7 +107,7 @@
                     + "\nActual text = " + reference.length() + " " + reference;
             ((LatinIME)mParent).debugDumpStateAndCrashWithException(context);
         } else {
-            Log.e(TAG, Utils.getStackTrace(2));
+            Log.e(TAG, LogUtils.getStackTrace(2));
             Log.e(TAG, "Exp <> Actual : " + mCurrentCursorPosition + " <> " + et.selectionStart);
         }
     }
@@ -154,7 +156,7 @@
         if (mNestLevel != 1) {
             // TODO: exception instead
             Log.e(TAG, "Batch edit level incorrect : " + mNestLevel);
-            Log.e(TAG, Utils.getStackTrace(4));
+            Log.e(TAG, LogUtils.getStackTrace(4));
         }
     }
 
@@ -441,25 +443,33 @@
      * Represents a range of text, relative to the current cursor position.
      */
     public static final class Range {
-        /** Characters before selection start */
-        public final int mCharsBefore;
+        private final CharSequence mTextAtCursor;
+        private final int mWordAtCursorStartIndex;
+        private final int mWordAtCursorEndIndex;
+        private final int mCursorIndex;
 
-        /**
-         * Characters after selection start, including one trailing word
-         * separator.
-         */
-        public final int mCharsAfter;
-
-        /** The actual characters that make up a word */
         public final CharSequence mWord;
 
-        public Range(int charsBefore, int charsAfter, CharSequence word) {
-            if (charsBefore < 0 || charsAfter < 0) {
+        public int getNumberOfCharsInWordBeforeCursor() {
+            return mCursorIndex - mWordAtCursorStartIndex;
+        }
+
+        public int getNumberOfCharsInWordAfterCursor() {
+            return mWordAtCursorEndIndex - mCursorIndex;
+        }
+
+        public Range(final CharSequence textAtCursor, final int wordAtCursorStartIndex,
+                final int wordAtCursorEndIndex, final int cursorIndex) {
+            if (wordAtCursorStartIndex < 0 || cursorIndex < wordAtCursorStartIndex
+                    || cursorIndex > wordAtCursorEndIndex
+                    || wordAtCursorEndIndex > textAtCursor.length()) {
                 throw new IndexOutOfBoundsException();
             }
-            this.mCharsBefore = charsBefore;
-            this.mCharsAfter = charsAfter;
-            this.mWord = word;
+            mTextAtCursor = textAtCursor;
+            mWordAtCursorStartIndex = wordAtCursorStartIndex;
+            mWordAtCursorEndIndex = wordAtCursorEndIndex;
+            mCursorIndex = cursorIndex;
+            mWord = mTextAtCursor.subSequence(mWordAtCursorStartIndex, mWordAtCursorEndIndex);
         }
     }
 
@@ -571,10 +581,8 @@
             }
         }
 
-        final SpannableString word = new SpannableString(TextUtils.concat(
-                before.subSequence(startIndexInBefore, before.length()),
-                after.subSequence(0, endIndexInAfter)));
-        return new Range(before.length() - startIndexInBefore, endIndexInAfter, word);
+        return new Range(TextUtils.concat(before, after), startIndexInBefore,
+                before.length() + endIndexInAfter, before.length());
     }
 
     public boolean isCursorTouchingWord(final SettingsValues settingsValues) {
diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
index 86f7563..5b1a2dd 100644
--- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
+++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
@@ -28,6 +28,7 @@
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.Collections;
 import java.util.HashMap;
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index a6149c6..084d330 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -23,7 +23,9 @@
 import android.preference.PreferenceManager;
 import android.util.Log;
 
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
+import com.android.inputmethod.latin.utils.LocaleUtils;
+import com.android.inputmethod.latin.utils.LocaleUtils.RunInLocale;
+import com.android.inputmethod.latin.utils.ResourceUtils;
 
 import java.util.HashMap;
 import java.util.Locale;
diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java
index 8017ce1..46fa191 100644
--- a/java/src/com/android/inputmethod/latin/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java
@@ -35,16 +35,19 @@
 import android.util.Log;
 import android.view.inputmethod.InputMethodSubtype;
 
-import java.util.TreeSet;
-
 import com.android.inputmethod.dictionarypack.DictionarySettingsActivity;
 import com.android.inputmethod.latin.define.ProductionFlag;
 import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager;
 import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
 import com.android.inputmethod.latin.userdictionary.UserDictionarySettings;
+import com.android.inputmethod.latin.utils.AdditionalFeaturesSettingUtils;
+import com.android.inputmethod.latin.utils.FeedbackUtils;
+import com.android.inputmethod.latin.utils.Utils;
 import com.android.inputmethod.research.ResearchLogger;
 import com.android.inputmethodcommon.InputMethodSettingsFragment;
 
+import java.util.TreeSet;
+
 public final class SettingsFragment extends InputMethodSettingsFragment
         implements SharedPreferences.OnSharedPreferenceChangeListener {
     private static final String TAG = SettingsFragment.class.getSimpleName();
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 0910244..8eadf73 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -24,6 +24,10 @@
 
 import com.android.inputmethod.keyboard.internal.KeySpecParser;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.utils.AdditionalFeaturesSettingUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.InputTypeUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
diff --git a/java/src/com/android/inputmethod/latin/SubtypeLocale.java b/java/src/com/android/inputmethod/latin/SubtypeLocale.java
index 4d88ecc..3f94aca 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeLocale.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeLocale.java
@@ -25,7 +25,11 @@
 import android.util.Log;
 import android.view.inputmethod.InputMethodSubtype;
 
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.LocaleUtils;
+import com.android.inputmethod.latin.utils.LocaleUtils.RunInLocale;
+import com.android.inputmethod.latin.utils.LogUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
 
 import java.util.HashMap;
 import java.util.Locale;
@@ -238,7 +242,7 @@
                             + " nameResId=" + subtype.getNameResId()
                             + " locale=" + subtype.getLocale()
                             + " extra=" + subtype.getExtraValue()
-                            + "\n" + Utils.getStackTrace());
+                            + "\n" + LogUtils.getStackTrace());
                     return "";
                 }
             }
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index e783e6d..8b31f4e 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -22,6 +22,9 @@
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.keyboard.ProximityInfo;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.utils.BoundedTreeSet;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Comparator;
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 7a16595..5b47dda 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -19,6 +19,9 @@
 import android.text.TextUtils;
 import android.view.inputmethod.CompletionInfo;
 
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index 90f9297..ba84c1a 100644
--- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
@@ -28,6 +28,7 @@
 import android.text.TextUtils;
 
 import com.android.inputmethod.compat.UserDictionaryCompatUtils;
+import com.android.inputmethod.latin.utils.LocaleUtils;
 
 import java.util.Arrays;
 import java.util.Locale;
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
index 5280283..ca2d884 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
@@ -24,10 +24,13 @@
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.keyboard.ProximityInfo;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.UserHistoryDictIOUtils.BigramDictionaryInterface;
-import com.android.inputmethod.latin.UserHistoryDictIOUtils.OnAddWordListener;
-import com.android.inputmethod.latin.UserHistoryForgettingCurveUtils.ForgettingCurveParams;
 import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils;
+import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.BigramDictionaryInterface;
+import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.OnAddWordListener;
+import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils;
+import com.android.inputmethod.latin.utils.UserHistoryForgettingCurveUtils.ForgettingCurveParams;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -261,7 +264,7 @@
             inStream = new FileInputStream(file);
             inStream.read(buffer);
             UserHistoryDictIOUtils.readDictionaryBinary(
-                    new UserHistoryDictIOUtils.ByteArrayWrapper(buffer), listener);
+                    new ByteArrayWrapper(buffer), listener);
         } catch (FileNotFoundException e) {
             // This is an expected condition: we don't have a user history dictionary for this
             // language yet. It will be created sometime later.
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java
index 316f096..28941c4 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java
+++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionaryBigramList.java
@@ -19,6 +19,7 @@
 import android.util.Log;
 
 import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.HashMap;
 import java.util.Set;
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
index 13fa9d9..978c064 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
@@ -35,10 +35,10 @@
 
 import com.android.inputmethod.compat.TextViewCompatUtils;
 import com.android.inputmethod.compat.ViewCompatUtils;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SettingsActivity;
-import com.android.inputmethod.latin.StaticInnerHandlerWrapper;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper;
 
 import java.util.ArrayList;
 
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 13fcaf4..692e739 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -25,17 +25,17 @@
 
 import com.android.inputmethod.keyboard.KeyboardLayoutSet;
 import com.android.inputmethod.latin.BinaryDictionary;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.ContactsBinaryDictionary;
 import com.android.inputmethod.latin.Dictionary;
 import com.android.inputmethod.latin.DictionaryCollection;
 import com.android.inputmethod.latin.DictionaryFactory;
-import com.android.inputmethod.latin.LocaleUtils;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.StringUtils;
 import com.android.inputmethod.latin.SynchronouslyLoadedContactsBinaryDictionary;
 import com.android.inputmethod.latin.SynchronouslyLoadedUserBinaryDictionary;
 import com.android.inputmethod.latin.UserBinaryDictionary;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.LocaleUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java
index 9a1114f..ddda52d 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java
@@ -23,7 +23,7 @@
 import android.view.textservice.SuggestionsInfo;
 import android.view.textservice.TextInfo;
 
-import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.ArrayList;
 
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index 16e9fb7..6719e98 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -30,11 +30,11 @@
 import com.android.inputmethod.compat.SuggestionsInfoCompatUtils;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.Dictionary;
-import com.android.inputmethod.latin.LocaleUtils;
-import com.android.inputmethod.latin.StringUtils;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.WordComposer;
 import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService.SuggestionsGatherer;
+import com.android.inputmethod.latin.utils.LocaleUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Locale;
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
index a20e09e..ac8f687 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/DictionaryPool.java
@@ -19,10 +19,10 @@
 import android.util.Log;
 
 import com.android.inputmethod.keyboard.ProximityInfo;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.Dictionary;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.WordComposer;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.ArrayList;
 import java.util.Locale;
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java
index 5ce9d8e..da58126 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java
@@ -21,7 +21,7 @@
 import android.preference.PreferenceScreen;
 
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.Utils;
+import com.android.inputmethod.latin.utils.Utils;
 
 /**
  * Preference screen.
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index 322ae5b..2218b3b 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -31,7 +31,7 @@
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.Utils;
+import com.android.inputmethod.latin.utils.Utils;
 
 public final class MoreSuggestions extends Keyboard {
     public static final int SUGGESTION_CODE_BASE = 1024;
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index f434a12..b6caf9b 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -49,9 +49,9 @@
 import com.android.inputmethod.latin.AutoCorrection;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.ResourceUtils;
 import com.android.inputmethod.latin.SuggestedWords;
-import com.android.inputmethod.latin.Utils;
+import com.android.inputmethod.latin.utils.ResourceUtils;
+import com.android.inputmethod.latin.utils.Utils;
 
 import java.util.ArrayList;
 
@@ -449,8 +449,10 @@
             final TextView wordView = mWordViews.get(positionInStrip);
             wordView.setEnabled(true);
             wordView.setTextColor(mColorAutoCorrect);
-            final String punctuation = suggestedWords.getWord(positionInStrip);
-            wordView.setText(punctuation);
+            // {@link TextView#getTag()} is used to get the index in suggestedWords at
+            // {@link SuggestionStripView#onClick(View)}.
+            wordView.setTag(positionInStrip);
+            wordView.setText(suggestedWords.getWord(positionInStrip));
             wordView.setTextScaleX(1.0f);
             wordView.setCompoundDrawables(null, null, null, null);
             stripView.addView(wordView);
@@ -468,6 +470,8 @@
         final int wordWidth = (int)(width * mCenterSuggestionWeight);
         final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint());
         final float wordScaleX = wordView.getTextScaleX();
+        // {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word
+        // will be extracted at {@link #getAddToDictionaryWord()}.
         wordView.setTag(word);
         wordView.setText(text);
         wordView.setTextScaleX(wordScaleX);
@@ -497,8 +501,10 @@
         hintView.setOnClickListener(listener);
     }
 
-    public CharSequence getAddToDictionaryWord() {
-        return (CharSequence)mWordToSaveView.getTag();
+    public String getAddToDictionaryWord() {
+        // String tag is set at
+        // {@link #layoutAddToDictionaryHint(String,ViewGroup,int,CharSequence,OnClickListener}.
+        return (String)mWordToSaveView.getTag();
     }
 
     public boolean isAddToDictionaryShowing(final View v) {
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index b2b9427..fcebdd4 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -34,7 +34,6 @@
 import com.android.inputmethod.keyboard.MainKeyboardView;
 import com.android.inputmethod.keyboard.MoreKeysPanel;
 import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
@@ -42,6 +41,7 @@
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.define.ProductionFlag;
 import com.android.inputmethod.latin.suggestions.MoreSuggestions.MoreSuggestionsListener;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 import com.android.inputmethod.research.ResearchLogger;
 
 import java.util.ArrayList;
@@ -306,12 +306,15 @@
     @Override
     public void onClick(final View view) {
         if (mLayoutHelper.isAddToDictionaryShowing(view)) {
-            mListener.addWordToUserDictionary(mLayoutHelper.getAddToDictionaryWord().toString());
+            mListener.addWordToUserDictionary(mLayoutHelper.getAddToDictionaryWord());
             clear();
             return;
         }
 
         final Object tag = view.getTag();
+        // Integer tag is set at
+        // {@link SuggestionStripLayoutHelper#setupWordViewsTextAndColor(SuggestedWords,int)} and
+        // {@link SuggestionStripLayoutHelper#layoutPunctuationSuggestions(SuggestedWords,ViewGroup}
         if (!(tag instanceof Integer)) {
             return;
         }
diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java
index 89ec746..dad7296 100644
--- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java
+++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordContents.java
@@ -16,10 +16,6 @@
 
 package com.android.inputmethod.latin.userdictionary;
 
-import com.android.inputmethod.compat.UserDictionaryCompatUtils;
-import com.android.inputmethod.latin.LocaleUtils;
-import com.android.inputmethod.latin.R;
-
 import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -30,6 +26,10 @@
 import android.view.View;
 import android.widget.EditText;
 
+import com.android.inputmethod.compat.UserDictionaryCompatUtils;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.LocaleUtils;
+
 import java.util.ArrayList;
 import java.util.Locale;
 import java.util.TreeSet;
diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java
index 6e64882..e7cf0d3 100644
--- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java
+++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryList.java
@@ -16,9 +16,6 @@
 
 package com.android.inputmethod.latin.userdictionary;
 
-import com.android.inputmethod.latin.LocaleUtils;
-import com.android.inputmethod.latin.R;
-
 import android.app.Activity;
 import android.content.Intent;
 import android.database.Cursor;
@@ -29,6 +26,9 @@
 import android.provider.UserDictionary;
 import android.text.TextUtils;
 
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.LocaleUtils;
+
 import java.util.Locale;
 import java.util.TreeSet;
 
diff --git a/java/src/com/android/inputmethod/latin/AdditionalFeaturesSettingUtils.java b/java/src/com/android/inputmethod/latin/utils/AdditionalFeaturesSettingUtils.java
similarity index 94%
rename from java/src/com/android/inputmethod/latin/AdditionalFeaturesSettingUtils.java
rename to java/src/com/android/inputmethod/latin/utils/AdditionalFeaturesSettingUtils.java
index 0fdaea5..18dfb3d 100644
--- a/java/src/com/android/inputmethod/latin/AdditionalFeaturesSettingUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/AdditionalFeaturesSettingUtils.java
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
-
-import com.android.inputmethodcommon.InputMethodSettingsFragment;
+package com.android.inputmethod.latin.utils;
 
 import android.content.Context;
 import android.content.SharedPreferences;
 
+import com.android.inputmethod.latin.Settings;
+import com.android.inputmethodcommon.InputMethodSettingsFragment;
+
 /**
  * Utility class for managing additional features settings.
  */
diff --git a/java/src/com/android/inputmethod/latin/BoundedTreeSet.java b/java/src/com/android/inputmethod/latin/utils/BoundedTreeSet.java
similarity index 96%
rename from java/src/com/android/inputmethod/latin/BoundedTreeSet.java
rename to java/src/com/android/inputmethod/latin/utils/BoundedTreeSet.java
index 489a74e..ae1fd3f 100644
--- a/java/src/com/android/inputmethod/latin/BoundedTreeSet.java
+++ b/java/src/com/android/inputmethod/latin/utils/BoundedTreeSet.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 
diff --git a/java/src/com/android/inputmethod/latin/CapsModeUtils.java b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
similarity index 98%
rename from java/src/com/android/inputmethod/latin/CapsModeUtils.java
rename to java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
index 4b8d1ac..2f91c57 100644
--- a/java/src/com/android/inputmethod/latin/CapsModeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
@@ -14,11 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.text.InputType;
 import android.text.TextUtils;
 
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.WordComposer;
+
 import java.util.Locale;
 
 public final class CapsModeUtils {
diff --git a/java/src/com/android/inputmethod/latin/CollectionUtils.java b/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java
similarity index 98%
rename from java/src/com/android/inputmethod/latin/CollectionUtils.java
rename to java/src/com/android/inputmethod/latin/utils/CollectionUtils.java
index a8623cc..98f0d8b 100644
--- a/java/src/com/android/inputmethod/latin/CollectionUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CollectionUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.util.SparseArray;
 
diff --git a/java/src/com/android/inputmethod/latin/CompletionInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/CompletionInfoUtils.java
similarity index 96%
rename from java/src/com/android/inputmethod/latin/CompletionInfoUtils.java
rename to java/src/com/android/inputmethod/latin/utils/CompletionInfoUtils.java
index 792a446..5ccf0e0 100644
--- a/java/src/com/android/inputmethod/latin/CompletionInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CompletionInfoUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.text.TextUtils;
 import android.view.inputmethod.CompletionInfo;
diff --git a/java/src/com/android/inputmethod/latin/CoordinateUtils.java b/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java
similarity index 96%
rename from java/src/com/android/inputmethod/latin/CoordinateUtils.java
rename to java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java
index af270e1..72f2cd2 100644
--- a/java/src/com/android/inputmethod/latin/CoordinateUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CoordinateUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 public final class CoordinateUtils {
     private static final int INDEX_X = 0;
diff --git a/java/src/com/android/inputmethod/latin/utils/CsvUtils.java b/java/src/com/android/inputmethod/latin/utils/CsvUtils.java
index 999c2f0..159ebb1 100644
--- a/java/src/com/android/inputmethod/latin/utils/CsvUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CsvUtils.java
@@ -17,7 +17,6 @@
 package com.android.inputmethod.latin.utils;
 
 import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.latin.CollectionUtils;
 
 import java.util.ArrayList;
 
diff --git a/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
similarity index 98%
rename from java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java
rename to java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
index 9d47849..b3d37d7 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.content.ContentValues;
 import android.content.Context;
@@ -23,6 +23,9 @@
 import android.text.format.DateUtils;
 import android.util.Log;
 
+import com.android.inputmethod.latin.AssetFileAddress;
+import com.android.inputmethod.latin.BinaryDictionaryGetter;
+import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
 import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
 import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
@@ -38,9 +41,7 @@
  */
 public class DictionaryInfoUtils {
     private static final String TAG = DictionaryInfoUtils.class.getSimpleName();
-    // This class must be located in the same package as LatinIME.java.
-    private static final String RESOURCE_PACKAGE_NAME =
-            DictionaryInfoUtils.class.getPackage().getName();
+    private static final String RESOURCE_PACKAGE_NAME = R.class.getPackage().getName();
     private static final String DEFAULT_MAIN_DICT = "main";
     private static final String MAIN_DICT_PREFIX = "main_";
     // 6 digits - unicode is limited to 21 bits
diff --git a/java/src/com/android/inputmethod/latin/FeedbackUtils.java b/java/src/com/android/inputmethod/latin/utils/FeedbackUtils.java
similarity index 95%
rename from java/src/com/android/inputmethod/latin/FeedbackUtils.java
rename to java/src/com/android/inputmethod/latin/utils/FeedbackUtils.java
index 0582763..ec7eaf4 100644
--- a/java/src/com/android/inputmethod/latin/FeedbackUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/FeedbackUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.content.Context;
 import android.content.Intent;
diff --git a/java/src/com/android/inputmethod/latin/InputTypeUtils.java b/java/src/com/android/inputmethod/latin/utils/InputTypeUtils.java
similarity index 98%
rename from java/src/com/android/inputmethod/latin/InputTypeUtils.java
rename to java/src/com/android/inputmethod/latin/utils/InputTypeUtils.java
index 46194f6..19cd340 100644
--- a/java/src/com/android/inputmethod/latin/InputTypeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/InputTypeUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.text.InputType;
 import android.view.inputmethod.EditorInfo;
diff --git a/java/src/com/android/inputmethod/latin/IntentUtils.java b/java/src/com/android/inputmethod/latin/utils/IntentUtils.java
similarity index 97%
rename from java/src/com/android/inputmethod/latin/IntentUtils.java
rename to java/src/com/android/inputmethod/latin/utils/IntentUtils.java
index d175af5..ea01681 100644
--- a/java/src/com/android/inputmethod/latin/IntentUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/IntentUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.content.Intent;
 import android.text.TextUtils;
diff --git a/java/src/com/android/inputmethod/latin/JniUtils.java b/java/src/com/android/inputmethod/latin/utils/JniUtils.java
similarity index 96%
rename from java/src/com/android/inputmethod/latin/JniUtils.java
rename to java/src/com/android/inputmethod/latin/utils/JniUtils.java
index 8aedee5..e7fdafa 100644
--- a/java/src/com/android/inputmethod/latin/JniUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/JniUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.util.Log;
 
diff --git a/java/src/com/android/inputmethod/latin/LocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/LocaleUtils.java
similarity index 99%
rename from java/src/com/android/inputmethod/latin/LocaleUtils.java
rename to java/src/com/android/inputmethod/latin/utils/LocaleUtils.java
index a1e4050..58d062b 100644
--- a/java/src/com/android/inputmethod/latin/LocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/LocaleUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -166,6 +166,7 @@
 
     static final Object sLockForRunInLocale = new Object();
 
+    // TODO: Make this an external class
     public abstract static class RunInLocale<T> {
         protected abstract T job(Resources res);
 
diff --git a/java/src/com/android/inputmethod/dictionarypack/Utils.java b/java/src/com/android/inputmethod/latin/utils/LogUtils.java
similarity index 76%
rename from java/src/com/android/inputmethod/dictionarypack/Utils.java
rename to java/src/com/android/inputmethod/latin/utils/LogUtils.java
index c4a42db..a0d2e04 100644
--- a/java/src/com/android/inputmethod/dictionarypack/Utils.java
+++ b/java/src/com/android/inputmethod/latin/utils/LogUtils.java
@@ -14,16 +14,18 @@
  * the License.
  */
 
-package com.android.inputmethod.dictionarypack;
+package com.android.inputmethod.latin.utils;
 
 import android.util.Log;
 
+import com.android.inputmethod.latin.LatinImeLogger;
+
 /**
- * A class for various utility methods, especially debugging.
+ * A class for logging and debugging utility methods.
  */
-public final class Utils {
-    private final static String TAG = Utils.class.getSimpleName() + ":DEBUG --";
-    private final static boolean DEBUG = DictionaryProvider.DEBUG;
+public final class LogUtils {
+    private final static String TAG = LogUtils.class.getSimpleName();
+    private final static boolean sDBG = LatinImeLogger.sDBG;
 
     /**
      * Calls .toString() on its non-null argument or returns "null"
@@ -39,13 +41,22 @@
      * @return a readable, carriage-return-separated string for the current stack trace.
      */
     public static String getStackTrace() {
+        return getStackTrace(Integer.MAX_VALUE - 1);
+    }
+
+    /**
+     * Get the string representation of the current stack trace, for debugging purposes.
+     * @param limit the maximum number of stack frames to be returned.
+     * @return a readable, carriage-return-separated string for the current stack trace.
+     */
+    public static String getStackTrace(final int limit) {
         final StringBuilder sb = new StringBuilder();
         try {
             throw new RuntimeException();
-        } catch (RuntimeException e) {
-            StackTraceElement[] frames = e.getStackTrace();
+        } catch (final RuntimeException e) {
+            final StackTraceElement[] frames = e.getStackTrace();
             // Start at 1 because the first frame is here and we don't care about it
-            for (int j = 1; j < frames.length; ++j) {
+            for (int j = 1; j < frames.length && j < limit + 1; ++j) {
                 sb.append(frames[j].toString() + "\n");
             }
         }
@@ -75,7 +86,7 @@
      * @param args the stuff to send to the log
      */
     public static void l(final Object... args) {
-        if (!DEBUG) return;
+        if (!sDBG) return;
         final StringBuilder sb = new StringBuilder();
         for (final Object o : args) {
             sb.append(s(o).toString());
@@ -92,7 +103,7 @@
      * @param args the stuff to send to the log
      */
     public static void r(final Object... args) {
-        if (!DEBUG) return;
+        if (!sDBG) return;
         final StringBuilder sb = new StringBuilder("\u001B[31m");
         for (final Object o : args) {
             sb.append(s(o).toString());
diff --git a/java/src/com/android/inputmethod/latin/MetadataFileUriGetter.java b/java/src/com/android/inputmethod/latin/utils/MetadataFileUriGetter.java
similarity index 92%
rename from java/src/com/android/inputmethod/latin/MetadataFileUriGetter.java
rename to java/src/com/android/inputmethod/latin/utils/MetadataFileUriGetter.java
index a98ecc7..9ad319d 100644
--- a/java/src/com/android/inputmethod/latin/MetadataFileUriGetter.java
+++ b/java/src/com/android/inputmethod/latin/utils/MetadataFileUriGetter.java
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
+
+import com.android.inputmethod.latin.R;
 
 import android.content.Context;
 
diff --git a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java b/java/src/com/android/inputmethod/latin/utils/PositionalInfoForUserDictPendingAddition.java
similarity index 97%
rename from java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java
rename to java/src/com/android/inputmethod/latin/utils/PositionalInfoForUserDictPendingAddition.java
index a880000..1fc7ecc 100644
--- a/java/src/com/android/inputmethod/latin/PositionalInfoForUserDictPendingAddition.java
+++ b/java/src/com/android/inputmethod/latin/utils/PositionalInfoForUserDictPendingAddition.java
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.view.inputmethod.EditorInfo;
 
+import com.android.inputmethod.latin.RichInputConnection;
+
 import java.util.Locale;
 
 /**
diff --git a/java/src/com/android/inputmethod/latin/RecapitalizeStatus.java b/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java
similarity index 98%
rename from java/src/com/android/inputmethod/latin/RecapitalizeStatus.java
rename to java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java
index b9d7dcf..0f5cd80 100644
--- a/java/src/com/android/inputmethod/latin/RecapitalizeStatus.java
+++ b/java/src/com/android/inputmethod/latin/utils/RecapitalizeStatus.java
@@ -14,9 +14,7 @@
  * the License.
  */
 
-package com.android.inputmethod.latin;
-
-import com.android.inputmethod.latin.StringUtils;
+package com.android.inputmethod.latin.utils;
 
 import java.util.Locale;
 
diff --git a/java/src/com/android/inputmethod/latin/ResizableIntArray.java b/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java
similarity index 98%
rename from java/src/com/android/inputmethod/latin/ResizableIntArray.java
rename to java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java
index 691f060..4c7739a 100644
--- a/java/src/com/android/inputmethod/latin/ResizableIntArray.java
+++ b/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import java.util.Arrays;
 
diff --git a/java/src/com/android/inputmethod/latin/ResourceUtils.java b/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java
similarity index 99%
rename from java/src/com/android/inputmethod/latin/ResourceUtils.java
rename to java/src/com/android/inputmethod/latin/utils/ResourceUtils.java
index 0eb8b4f..ffec575 100644
--- a/java/src/com/android/inputmethod/latin/ResourceUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ResourceUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.content.res.Resources;
 import android.content.res.TypedArray;
diff --git a/java/src/com/android/inputmethod/latin/StaticInnerHandlerWrapper.java b/java/src/com/android/inputmethod/latin/utils/StaticInnerHandlerWrapper.java
similarity index 96%
rename from java/src/com/android/inputmethod/latin/StaticInnerHandlerWrapper.java
rename to java/src/com/android/inputmethod/latin/utils/StaticInnerHandlerWrapper.java
index e50af4d..44e5d17 100644
--- a/java/src/com/android/inputmethod/latin/StaticInnerHandlerWrapper.java
+++ b/java/src/com/android/inputmethod/latin/utils/StaticInnerHandlerWrapper.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.os.Handler;
 import android.os.Looper;
diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
similarity index 99%
rename from java/src/com/android/inputmethod/latin/StringUtils.java
rename to java/src/com/android/inputmethod/latin/utils/StringUtils.java
index c2fd4fb..7406d85 100644
--- a/java/src/com/android/inputmethod/latin/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.text.TextUtils;
 
+import com.android.inputmethod.latin.Constants;
+
 import java.util.ArrayList;
 import java.util.Locale;
 
diff --git a/java/src/com/android/inputmethod/latin/TargetPackageInfoGetterTask.java b/java/src/com/android/inputmethod/latin/utils/TargetPackageInfoGetterTask.java
similarity index 97%
rename from java/src/com/android/inputmethod/latin/TargetPackageInfoGetterTask.java
rename to java/src/com/android/inputmethod/latin/utils/TargetPackageInfoGetterTask.java
index 947b0c5..afbe2ec 100644
--- a/java/src/com/android/inputmethod/latin/TargetPackageInfoGetterTask.java
+++ b/java/src/com/android/inputmethod/latin/utils/TargetPackageInfoGetterTask.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.content.Context;
 import android.content.pm.PackageInfo;
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java
similarity index 82%
rename from java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java
rename to java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java
index 1093155..32eb0b2 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryDictIOUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtils.java
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.util.Log;
 
 import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.UserHistoryDictionaryBigramList;
 import com.android.inputmethod.latin.makedict.BinaryDictIOUtils;
 import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
 import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface;
@@ -53,64 +54,6 @@
         public int getFrequency(final String word1, final String word2);
     }
 
-    public static final class ByteArrayWrapper implements FusionDictionaryBufferInterface {
-        private byte[] mBuffer;
-        private int mPosition;
-
-        public ByteArrayWrapper(final byte[] buffer) {
-            mBuffer = buffer;
-            mPosition = 0;
-        }
-
-        @Override
-        public int readUnsignedByte() {
-            return mBuffer[mPosition++] & 0xFF;
-        }
-
-        @Override
-        public int readUnsignedShort() {
-            final int retval = readUnsignedByte();
-            return (retval << 8) + readUnsignedByte();
-        }
-
-        @Override
-        public int readUnsignedInt24() {
-            final int retval = readUnsignedShort();
-            return (retval << 8) + readUnsignedByte();
-        }
-
-        @Override
-        public int readInt() {
-            final int retval = readUnsignedShort();
-            return (retval << 16) + readUnsignedShort();
-        }
-
-        @Override
-        public int position() {
-            return mPosition;
-        }
-
-        @Override
-        public void position(int position) {
-            mPosition = position;
-        }
-
-        @Override
-        public void put(final byte b) {
-            mBuffer[mPosition++] = b;
-        }
-
-        @Override
-        public int limit() {
-            return mBuffer.length - 1;
-        }
-
-        @Override
-        public int capacity() {
-            return mBuffer.length;
-        }
-    }
-
     /**
      * Writes dictionary to file.
      */
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
similarity index 99%
rename from java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java
rename to java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
index 9053d70..9f842f9 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.text.format.DateUtils;
 import android.util.Log;
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/utils/Utils.java
similarity index 95%
rename from java/src/com/android/inputmethod/latin/Utils.java
rename to java/src/com/android/inputmethod/latin/utils/Utils.java
index 949720f..390d306 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/utils/Utils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.app.Activity;
 import android.content.ComponentName;
@@ -35,7 +35,12 @@
 import android.util.Log;
 
 import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.LatinIME;
+import com.android.inputmethod.latin.LatinImeLogger;
+import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.WordComposer;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -50,6 +55,7 @@
 import java.util.Date;
 import java.util.Locale;
 
+// TODO: Come up with a more descriptive class name
 public final class Utils {
     private static final String TAG = Utils.class.getSimpleName();
 
@@ -71,15 +77,17 @@
         }
     }
 
-    /* package */ static final class RingCharBuffer {
+    // TODO: Make this an external class
+    public /* for test */ static final class RingCharBuffer {
+        public /* for test */ static final int BUFSIZE = 20;
+        public /* for test */ int mLength = 0;
+
         private static RingCharBuffer sRingCharBuffer = new RingCharBuffer();
         private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC';
         private static final int INVALID_COORDINATE = -2;
-        /* package */ static final int BUFSIZE = 20;
         private InputMethodService mContext;
         private boolean mEnabled = false;
         private int mEnd = 0;
-        /* package */ int mLength = 0;
         private char[] mCharBuf = new char[BUFSIZE];
         private int[] mXBuf = new int[BUFSIZE];
         private int[] mYBuf = new int[BUFSIZE];
@@ -184,25 +192,7 @@
         }
     }
 
-    // Get the current stack trace
-    public static String getStackTrace(final int limit) {
-        final StringBuilder sb = new StringBuilder();
-        try {
-            throw new RuntimeException();
-        } catch (final RuntimeException e) {
-            final StackTraceElement[] frames = e.getStackTrace();
-            // Start at 1 because the first frame is here and we don't care about it
-            for (int j = 1; j < frames.length && j < limit + 1; ++j) {
-                sb.append(frames[j].toString() + "\n");
-            }
-        }
-        return sb.toString();
-    }
-
-    public static String getStackTrace() {
-        return getStackTrace(Integer.MAX_VALUE - 1);
-    }
-
+    // TODO: Make this an external class
     public static final class UsabilityStudyLogUtils {
         // TODO: remove code duplication with ResearchLog class
         private static final String USABILITY_TAG = UsabilityStudyLogUtils.class.getSimpleName();
@@ -416,6 +406,7 @@
         }
     }
 
+    // TODO: Make this an external class
     public static final class Stats {
         public static void onNonSeparator(final char code, final int x, final int y) {
             RingCharBuffer.getInstance().push(code, x, y);
@@ -495,6 +486,10 @@
         return 0;
     }
 
+    /**
+     * A utility method to get the application's PackageInfo.versionName
+     * @return the application's PackageInfo.versionName
+     */
     public static String getVersionName(final Context context) {
         try {
             if (context == null) {
diff --git a/java/src/com/android/inputmethod/latin/XmlParseUtils.java b/java/src/com/android/inputmethod/latin/utils/XmlParseUtils.java
similarity index 98%
rename from java/src/com/android/inputmethod/latin/XmlParseUtils.java
rename to java/src/com/android/inputmethod/latin/utils/XmlParseUtils.java
index 48e5ed3..bdad166 100644
--- a/java/src/com/android/inputmethod/latin/XmlParseUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/XmlParseUtils.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.content.res.TypedArray;
 
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index 46d2314..f073308 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -54,7 +54,6 @@
 import com.android.inputmethod.keyboard.MainKeyboardView;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.Dictionary;
-import com.android.inputmethod.latin.InputTypeUtils;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.RichInputConnection;
@@ -62,6 +61,7 @@
 import com.android.inputmethod.latin.Suggest;
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.define.ProductionFlag;
+import com.android.inputmethod.latin.utils.InputTypeUtils;
 import com.android.inputmethod.research.MotionEventReader.ReplayData;
 import com.android.inputmethod.research.ui.SplashScreen;
 
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index fb60139..d5df6b6 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -53,10 +53,10 @@
         dic_nodes_cache.cpp) \
     $(addprefix suggest/core/dictionary/, \
         bigram_dictionary.cpp \
-        binary_dictionary_bigrams_reading_utils.cpp \
         binary_dictionary_format_utils.cpp \
         binary_dictionary_header.cpp \
         binary_dictionary_header_reading_utils.cpp \
+        binary_dictionary_terminal_attributes_reading_utils.cpp \
         bloom_filter.cpp \
         byte_array_utils.cpp \
         dictionary.cpp \
diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h
index 2529994..c700b01 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node.h
@@ -28,13 +28,13 @@
 #if DEBUG_DICT
 #define LOGI_SHOW_ADD_COST_PROP \
         do { char charBuf[50]; \
-        INTS_TO_CHARS(getOutputWordBuf(), getDepth(), charBuf); \
+        INTS_TO_CHARS(getOutputWordBuf(), getNodeCodePointCount(), charBuf); \
         AKLOGI("%20s, \"%c\", size = %03d, total = %03d, index(0) = %02d, dist = %.4f, %s,,", \
                 __FUNCTION__, getNodeCodePoint(), inputSize, getTotalInputIndex(), \
                 getInputIndex(0), getNormalizedCompoundDistance(), charBuf); } while (0)
 #define DUMP_WORD_AND_SCORE(header) \
         do { char charBuf[50]; char prevWordCharBuf[50]; \
-        INTS_TO_CHARS(getOutputWordBuf(), getDepth(), charBuf); \
+        INTS_TO_CHARS(getOutputWordBuf(), getNodeCodePointCount(), charBuf); \
         INTS_TO_CHARS(mDicNodeState.mDicNodeStatePrevWord.mPrevWord, \
                 mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(), prevWordCharBuf); \
         AKLOGI("#%8s, %5f, %5f, %5f, %5f, %s, %s, %d,,", header, \
@@ -51,6 +51,11 @@
 
 // This struct is purely a bucket to return values. No instances of this struct should be kept.
 struct DicNode_InputStateG {
+    DicNode_InputStateG()
+            : mNeedsToUpdateInputStateG(false), mPointerId(0), mInputIndex(0),
+              mPrevCodePoint(0), mTerminalDiffCost(0.0f), mRawLength(0.0f),
+              mDoubleLetterLevel(NOT_A_DOUBLE_LETTER) {}
+
     bool mNeedsToUpdateInputStateG;
     int mPointerId;
     int16_t mInputIndex;
@@ -157,7 +162,7 @@
             const bool isTerminal, const bool hasMultipleChars, const bool hasChildren,
             const uint16_t additionalSubwordLength, const int *additionalSubword) {
         mIsUsed = true;
-        uint16_t newDepth = static_cast<uint16_t>(dicNode->getDepth() + 1);
+        uint16_t newDepth = static_cast<uint16_t>(dicNode->getNodeCodePointCount() + 1);
         mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion;
         const uint16_t newLeavingDepth = static_cast<uint16_t>(
                 dicNode->mDicNodeProperties.getLeavingDepth() + additionalSubwordLength);
@@ -180,7 +185,7 @@
     }
 
     bool isRoot() const {
-        return getDepth() == 0;
+        return getNodeCodePointCount() == 0;
     }
 
     bool hasChildren() const {
@@ -188,12 +193,12 @@
     }
 
     bool isLeavingNode() const {
-        ASSERT(getDepth() <= getLeavingDepth());
-        return getDepth() == getLeavingDepth();
+        ASSERT(getNodeCodePointCount() <= getLeavingDepth());
+        return getNodeCodePointCount() == getLeavingDepth();
     }
 
     AK_FORCE_INLINE bool isFirstLetter() const {
-        return getDepth() == 1;
+        return getNodeCodePointCount() == 1;
     }
 
     bool isCached() const {
@@ -206,7 +211,7 @@
 
     // Used to expand the node in DicNodeUtils
     int getNodeTypedCodePoint() const {
-        return mDicNodeState.mDicNodeStateOutput.getCodePointAt(getDepth());
+        return mDicNodeState.mDicNodeStateOutput.getCodePointAt(getNodeCodePointCount());
     }
 
     bool isImpossibleBigramWord() const {
@@ -215,7 +220,7 @@
         }
         const int prevWordLen = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength()
                 - mDicNodeState.mDicNodeStatePrevWord.getPrevWordStart() - 1;
-        const int currentWordLen = getDepth();
+        const int currentWordLen = getNodeCodePointCount();
         return (prevWordLen == 1 && currentWordLen == 1);
     }
 
@@ -263,13 +268,13 @@
 
     AK_FORCE_INLINE bool isTerminalWordNode() const {
         const bool isTerminalNodes = mDicNodeProperties.isTerminal();
-        const int currentNodeDepth = getDepth();
+        const int currentNodeDepth = getNodeCodePointCount();
         const int terminalNodeDepth = mDicNodeProperties.getLeavingDepth();
         return isTerminalNodes && currentNodeDepth > 0 && currentNodeDepth == terminalNodeDepth;
     }
 
     bool shouldBeFilterdBySafetyNetForBigram() const {
-        const uint16_t currentDepth = getDepth();
+        const uint16_t currentDepth = getNodeCodePointCount();
         const int prevWordLen = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength()
                 - mDicNodeState.mDicNodeStatePrevWord.getPrevWordStart() - 1;
         return !(currentDepth > 0 && (currentDepth != 1 || prevWordLen != 1));
@@ -281,7 +286,7 @@
 
     bool isTotalInputSizeExceedingLimit() const {
         const int prevWordsLen = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength();
-        const int currentWordDepth = getDepth();
+        const int currentWordDepth = getNodeCodePointCount();
         // TODO: 3 can be 2? Needs to be investigated.
         // TODO: Have a const variable for 3 (or 2)
         return prevWordsLen + currentWordDepth > MAX_WORD_LENGTH - 3;
@@ -316,7 +321,7 @@
 
     void outputResult(int *dest) const {
         const uint16_t prevWordLength = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength();
-        const uint16_t currentDepth = getDepth();
+        const uint16_t currentDepth = getNodeCodePointCount();
         DicNodeUtils::appendTwoWords(mDicNodeState.mDicNodeStatePrevWord.mPrevWord,
                    prevWordLength, getOutputWordBuf(), currentDepth, dest);
         DUMP_WORD_AND_SCORE("OUTPUT");
@@ -475,13 +480,13 @@
         return mDicNodeProperties.getAttributesPos();
     }
 
-    inline uint16_t getDepth() const {
+    inline uint16_t getNodeCodePointCount() const {
         return mDicNodeProperties.getDepth();
     }
 
-    // "Length" includes spaces.
-    inline uint16_t getTotalLength() const {
-        return getDepth() + mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength();
+    // Returns code point count including spaces
+    inline uint16_t getTotalNodeCodePointCount() const {
+        return getNodeCodePointCount() + mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength();
     }
 
     AK_FORCE_INLINE void dump(const char *tag) const {
@@ -516,8 +521,8 @@
         } else if (diff < -MIN_DIFF) {
             return false;
         }
-        const int depth = getDepth();
-        const int depthDiff = right->getDepth() - depth;
+        const int depth = getNodeCodePointCount();
+        const int depthDiff = right->getNodeCodePointCount() - depth;
         if (depthDiff != 0) {
             return depthDiff > 0;
         }
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_iterator.h b/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_iterator.h
index 0856840..f2b48e9 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_iterator.h
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_iterator.h
@@ -18,8 +18,8 @@
 #define LATINIME_BINARY_DICTIONARY_BIGRAMS_ITERATOR_H
 
 #include "defines.h"
-#include "suggest/core/dictionary/binary_dictionary_bigrams_reading_utils.h"
 #include "suggest/core/dictionary/binary_dictionary_info.h"
+#include "suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h"
 
 namespace latinime {
 
@@ -35,15 +35,17 @@
     }
 
     AK_FORCE_INLINE void next() {
-        mBigramFlags = BinaryDictionaryBigramsReadingUtils::getFlagsAndForwardPointer(
+        mBigramFlags = BinaryDictionaryTerminalAttributesReadingUtils::getFlagsAndForwardPointer(
                 mBinaryDictionaryInfo, &mPos);
-        mBigramPos = BinaryDictionaryBigramsReadingUtils::getBigramAddressAndForwardPointer(
-                mBinaryDictionaryInfo, mBigramFlags, &mPos);
-        mHasNext = BinaryDictionaryBigramsReadingUtils::hasNext(mBigramFlags);
+        mBigramPos =
+                BinaryDictionaryTerminalAttributesReadingUtils::getBigramAddressAndForwardPointer(
+                        mBinaryDictionaryInfo, mBigramFlags, &mPos);
+        mHasNext = BinaryDictionaryTerminalAttributesReadingUtils::hasNext(mBigramFlags);
     }
 
     AK_FORCE_INLINE int getProbability() const {
-        return BinaryDictionaryBigramsReadingUtils::getBigramProbability(mBigramFlags);
+        return BinaryDictionaryTerminalAttributesReadingUtils::getProbabilityFromFlags(
+                mBigramFlags);
     }
 
     AK_FORCE_INLINE int getBigramPos() const {
@@ -59,7 +61,7 @@
 
     const BinaryDictionaryInfo *const mBinaryDictionaryInfo;
     int mPos;
-    BinaryDictionaryBigramsReadingUtils::BigramFlags mBigramFlags;
+    BinaryDictionaryTerminalAttributesReadingUtils::BigramFlags mBigramFlags;
     int mBigramPos;
     bool mHasNext;
 };
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_reading_utils.cpp b/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_reading_utils.cpp
deleted file mode 100644
index 78a54b1..0000000
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_reading_utils.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2013 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.
- */
-
-#include "suggest/core/dictionary/binary_dictionary_bigrams_reading_utils.h"
-
-#include "suggest/core/dictionary/binary_dictionary_info.h"
-#include "suggest/core/dictionary/byte_array_utils.h"
-
-namespace latinime {
-
-const BinaryDictionaryBigramsReadingUtils::BigramFlags
-        BinaryDictionaryBigramsReadingUtils::MASK_ATTRIBUTE_ADDRESS_TYPE = 0x30;
-const BinaryDictionaryBigramsReadingUtils::BigramFlags
-        BinaryDictionaryBigramsReadingUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE = 0x10;
-const BinaryDictionaryBigramsReadingUtils::BigramFlags
-        BinaryDictionaryBigramsReadingUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES = 0x20;
-const BinaryDictionaryBigramsReadingUtils::BigramFlags
-        BinaryDictionaryBigramsReadingUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES = 0x30;
-const BinaryDictionaryBigramsReadingUtils::BigramFlags
-        BinaryDictionaryBigramsReadingUtils::FLAG_ATTRIBUTE_OFFSET_NEGATIVE = 0x40;
-// Flag for presence of more attributes
-const BinaryDictionaryBigramsReadingUtils::BigramFlags
-        BinaryDictionaryBigramsReadingUtils::FLAG_ATTRIBUTE_HAS_NEXT = 0x80;
-// Mask for attribute probability, stored on 4 bits inside the flags byte.
-const BinaryDictionaryBigramsReadingUtils::BigramFlags
-        BinaryDictionaryBigramsReadingUtils::MASK_ATTRIBUTE_PROBABILITY = 0x0F;
-const int BinaryDictionaryBigramsReadingUtils::ATTRIBUTE_ADDRESS_SHIFT = 4;
-
-/* static */ int BinaryDictionaryBigramsReadingUtils::getBigramAddressAndForwardPointer(
-        const BinaryDictionaryInfo *const binaryDictionaryInfo, const BigramFlags flags,
-        int *const pos) {
-    int offset = 0;
-    const int origin = *pos;
-    switch (MASK_ATTRIBUTE_ADDRESS_TYPE & flags) {
-        case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
-            offset = ByteArrayUtils::readUint8andAdvancePosition(
-                    binaryDictionaryInfo->getDictRoot(), pos);
-            break;
-        case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
-            offset = ByteArrayUtils::readUint16andAdvancePosition(
-                    binaryDictionaryInfo->getDictRoot(), pos);
-            break;
-        case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
-            offset = ByteArrayUtils::readUint24andAdvancePosition(
-                    binaryDictionaryInfo->getDictRoot(), pos);
-            break;
-    }
-    if (isOffsetNegative(flags)) {
-        return origin - offset;
-    } else {
-        return origin + offset;
-    }
-}
-
-} // namespace latinime
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.cpp b/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.cpp
new file mode 100644
index 0000000..0a7509c
--- /dev/null
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include "suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h"
+
+#include "suggest/core/dictionary/binary_dictionary_info.h"
+#include "suggest/core/dictionary/byte_array_utils.h"
+
+namespace latinime {
+
+typedef BinaryDictionaryTerminalAttributesReadingUtils TaUtils;
+
+const TaUtils::TerminalAttributeFlags TaUtils::MASK_ATTRIBUTE_ADDRESS_TYPE = 0x30;
+const TaUtils::TerminalAttributeFlags TaUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE = 0x10;
+const TaUtils::TerminalAttributeFlags TaUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES = 0x20;
+const TaUtils::TerminalAttributeFlags TaUtils::FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES = 0x30;
+const TaUtils::TerminalAttributeFlags TaUtils::FLAG_ATTRIBUTE_OFFSET_NEGATIVE = 0x40;
+// Flag for presence of more attributes
+const TaUtils::TerminalAttributeFlags TaUtils::FLAG_ATTRIBUTE_HAS_NEXT = 0x80;
+// Mask for attribute probability, stored on 4 bits inside the flags byte.
+const TaUtils::TerminalAttributeFlags TaUtils::MASK_ATTRIBUTE_PROBABILITY = 0x0F;
+const int TaUtils::ATTRIBUTE_ADDRESS_SHIFT = 4;
+
+/* static */ int TaUtils::getBigramAddressAndForwardPointer(
+        const BinaryDictionaryInfo *const binaryDictionaryInfo, const TerminalAttributeFlags flags,
+        int *const pos) {
+    int offset = 0;
+    const int origin = *pos;
+    switch (MASK_ATTRIBUTE_ADDRESS_TYPE & flags) {
+        case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
+            offset = ByteArrayUtils::readUint8andAdvancePosition(
+                    binaryDictionaryInfo->getDictRoot(), pos);
+            break;
+        case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
+            offset = ByteArrayUtils::readUint16andAdvancePosition(
+                    binaryDictionaryInfo->getDictRoot(), pos);
+            break;
+        case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
+            offset = ByteArrayUtils::readUint24andAdvancePosition(
+                    binaryDictionaryInfo->getDictRoot(), pos);
+            break;
+    }
+    if (isOffsetNegative(flags)) {
+        return origin - offset;
+    } else {
+        return origin + offset;
+    }
+}
+
+} // namespace latinime
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_reading_utils.h b/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h
similarity index 61%
rename from native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_reading_utils.h
rename to native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h
index e71f2a1..f38fd5a 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_bigrams_reading_utils.h
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef LATINIME_BINARY_DICTIONARY_BIGRAM_READING_UTILS_H
-#define LATINIME_BINARY_DICTIONARY_BIGRAM_READING_UTILS_H
+#ifndef LATINIME_BINARY_DICTIONARY_TERMINAL_ATTRIBUTES_READING_UTILS_H
+#define LATINIME_BINARY_DICTIONARY_TERMINAL_ATTRIBUTES_READING_UTILS_H
 
 #include <stdint.h>
 
@@ -25,10 +25,26 @@
 
 namespace latinime {
 
-class BinaryDictionaryBigramsReadingUtils {
+class BinaryDictionaryTerminalAttributesReadingUtils {
  public:
-    typedef uint8_t BigramFlags;
+    typedef uint8_t TerminalAttributeFlags;
+    typedef TerminalAttributeFlags BigramFlags;
 
+    static AK_FORCE_INLINE TerminalAttributeFlags getFlagsAndForwardPointer(
+            const BinaryDictionaryInfo *const binaryDictionaryInfo, int *const pos) {
+        return ByteArrayUtils::readUint8andAdvancePosition(
+                binaryDictionaryInfo->getDictRoot(), pos);
+    }
+
+    static AK_FORCE_INLINE int getProbabilityFromFlags(const TerminalAttributeFlags flags) {
+        return flags & MASK_ATTRIBUTE_PROBABILITY;
+    }
+
+    static AK_FORCE_INLINE bool hasNext(const TerminalAttributeFlags flags) {
+        return (flags & FLAG_ATTRIBUTE_HAS_NEXT) != 0;
+    }
+
+    // Bigrams reading methods
     static AK_FORCE_INLINE void skipExistingBigrams(
             const BinaryDictionaryInfo *const binaryDictionaryInfo, int *const pos) {
         BigramFlags flags = getFlagsAndForwardPointer(binaryDictionaryInfo, pos);
@@ -39,41 +55,27 @@
         *pos += attributeAddressSize(flags);
     }
 
-    static AK_FORCE_INLINE BigramFlags getFlagsAndForwardPointer(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo, int *const pos) {
-        return ByteArrayUtils::readUint8andAdvancePosition(
-                binaryDictionaryInfo->getDictRoot(), pos);
-    }
+    static int getBigramAddressAndForwardPointer(
+            const BinaryDictionaryInfo *const binaryDictionaryInfo, const BigramFlags flags,
+                    int *const pos);
 
-    static AK_FORCE_INLINE int getBigramProbability(const BigramFlags flags) {
-        return flags & MASK_ATTRIBUTE_PROBABILITY;
-    }
+ private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryDictionaryTerminalAttributesReadingUtils);
 
-    static AK_FORCE_INLINE bool isOffsetNegative(const BigramFlags flags) {
+    static const TerminalAttributeFlags MASK_ATTRIBUTE_ADDRESS_TYPE;
+    static const TerminalAttributeFlags FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE;
+    static const TerminalAttributeFlags FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES;
+    static const TerminalAttributeFlags FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES;
+    static const TerminalAttributeFlags FLAG_ATTRIBUTE_OFFSET_NEGATIVE;
+    static const TerminalAttributeFlags FLAG_ATTRIBUTE_HAS_NEXT;
+    static const TerminalAttributeFlags MASK_ATTRIBUTE_PROBABILITY;
+    static const int ATTRIBUTE_ADDRESS_SHIFT;
+
+    static AK_FORCE_INLINE bool isOffsetNegative(const TerminalAttributeFlags flags) {
         return (flags & FLAG_ATTRIBUTE_OFFSET_NEGATIVE) != 0;
     }
 
-    static AK_FORCE_INLINE bool hasNext(const BigramFlags flags) {
-        return (flags & FLAG_ATTRIBUTE_HAS_NEXT) != 0;
-    }
-
-    static int getBigramAddressAndForwardPointer(
-            const BinaryDictionaryInfo *const binaryDictionaryInfo,
-            const BigramFlags flags, int *const pos);
-
- private:
-    DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryDictionaryBigramsReadingUtils);
-
-    static const BigramFlags MASK_ATTRIBUTE_ADDRESS_TYPE;
-    static const BigramFlags FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE;
-    static const BigramFlags FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES;
-    static const BigramFlags FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES;
-    static const BigramFlags FLAG_ATTRIBUTE_OFFSET_NEGATIVE;
-    static const BigramFlags FLAG_ATTRIBUTE_HAS_NEXT;
-    static const BigramFlags MASK_ATTRIBUTE_PROBABILITY;
-    static const int ATTRIBUTE_ADDRESS_SHIFT;
-
-    static AK_FORCE_INLINE int attributeAddressSize(const BigramFlags flags) {
+    static AK_FORCE_INLINE int attributeAddressSize(const TerminalAttributeFlags flags) {
         return (flags & MASK_ATTRIBUTE_ADDRESS_TYPE) >> ATTRIBUTE_ADDRESS_SHIFT;
         /* Note: this is a value-dependant optimization of what may probably be
            more readably written this way:
@@ -87,4 +89,4 @@
     }
 };
 }
-#endif /* LATINIME_BINARY_DICTIONARY_BIGRAM_READING_UTILS_H */
+#endif /* LATINIME_BINARY_DICTIONARY_TERMINAL_ATTRIBUTES_READING_UTILS_H */
diff --git a/native/jni/src/suggest/core/dictionary/byte_array_utils.h b/native/jni/src/suggest/core/dictionary/byte_array_utils.h
index d3321f6..daa822f 100644
--- a/native/jni/src/suggest/core/dictionary/byte_array_utils.h
+++ b/native/jni/src/suggest/core/dictionary/byte_array_utils.h
@@ -57,6 +57,17 @@
         return value;
     }
 
+    static AK_FORCE_INLINE int readSint24andAdvancePosition(
+            const uint8_t *const buffer, int *const pos) {
+        const uint8_t value = readUint8(buffer, *pos);
+        if (value < 0x80) {
+            return readUint24andAdvancePosition(buffer, pos);
+        } else {
+            (*pos)++;
+            return -(((value & 0x7F) << 16) ^ readUint16andAdvancePosition(buffer, pos));
+        }
+    }
+
     static AK_FORCE_INLINE uint32_t readUint24andAdvancePosition(
             const uint8_t *const buffer, int *const pos) {
         const uint32_t value = readUint24(buffer, *pos);
diff --git a/native/jni/src/suggest/core/layout/proximity_info.cpp b/native/jni/src/suggest/core/layout/proximity_info.cpp
index 05826a5..e64476d 100644
--- a/native/jni/src/suggest/core/layout/proximity_info.cpp
+++ b/native/jni/src/suggest/core/layout/proximity_info.cpp
@@ -215,22 +215,30 @@
     return centerX;
 }
 
-// referencePointY is currently not used because we don't specially handle keys higher than the
-// most common key height. When the referencePointY is NOT_A_COORDINATE, this method should
-// calculate the return value without using the line segment.
+// When the referencePointY is NOT_A_COORDINATE, this method calculates the return value without
+// using the line segment.
 int ProximityInfo::getKeyCenterYOfKeyIdG(
         const int keyId,  const int referencePointY, const bool isGeometric) const {
     // TODO: Remove "isGeometric" and have separate "proximity_info"s for gesture and typing.
     if (keyId < 0) {
         return 0;
     }
+    int centerY;
     if (!hasTouchPositionCorrectionData()) {
-        return mCenterYsG[keyId];
+        centerY = mCenterYsG[keyId];
     } else if (isGeometric) {
-        return static_cast<int>(mSweetSpotCenterYsG[keyId]);
+        centerY = static_cast<int>(mSweetSpotCenterYsG[keyId]);
     } else {
-        return static_cast<int>(mSweetSpotCenterYs[keyId]);
+        centerY = static_cast<int>(mSweetSpotCenterYs[keyId]);
     }
+    if (referencePointY != NOT_A_COORDINATE &&
+            centerY + mKeyHeights[keyId] > KEYBOARD_HEIGHT && centerY < referencePointY) {
+        // When the distance between center point and bottom edge of the keyboard is shorter than
+        // the key height, we assume the key is located at the bottom row of the keyboard.
+        // The center point is extended to the bottom edge for such keys.
+        return referencePointY;
+    }
+    return centerY;
 }
 
 int ProximityInfo::getKeyKeyDistanceG(const int keyId0, const int keyId1) const {
diff --git a/native/jni/src/suggest/core/layout/proximity_info_state.h b/native/jni/src/suggest/core/layout/proximity_info_state.h
index cc6410a..dbcd544 100644
--- a/native/jni/src/suggest/core/layout/proximity_info_state.h
+++ b/native/jni/src/suggest/core/layout/proximity_info_state.h
@@ -90,20 +90,7 @@
         return false;
     }
 
-    // TODO: Promote insertion letter correction if that letter is a proximity of the previous
-    // letter like follows:
-    // // Demotion for a word with excessive character
-    // if (excessiveCount > 0) {
-    //     multiplyRate(WORDS_WITH_EXCESSIVE_CHARACTER_DEMOTION_RATE, &finalFreq);
-    //     if (!lastCharExceeded
-    //             && !proximityInfoState->existsAdjacentProximityChars(excessivePos)) {
-    //         // If an excessive character is not adjacent to the left char or the right char,
-    //         // we will demote this word.
-    //         multiplyRate(WORDS_WITH_EXCESSIVE_CHARACTER_OUT_OF_PROXIMITY_DEMOTION_RATE,
-    //                 &finalFreq);
-    //     }
-    // }
-    inline bool existsAdjacentProximityChars(const int index) const {
+    AK_FORCE_INLINE bool existsAdjacentProximityChars(const int index) const {
         if (index < 0 || index >= mSampledInputSize) return false;
         const int currentCodePoint = getPrimaryCodePointAt(index);
         const int leftIndex = index - 1;
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index a8f16c8..173a612 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -36,6 +36,7 @@
 const int Suggest::MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT = 16;
 const int Suggest::MIN_CONTINUOUS_SUGGESTION_INPUT_SIZE = 2;
 const float Suggest::AUTOCORRECT_CLASSIFICATION_THRESHOLD = 0.33f;
+const int Suggest::FINAL_SCORE_PENALTY_FOR_NOT_BEST_EXACT_MATCHED_WORD = 1;
 
 /**
  * Returns a set of suggestions for the given input touch points. The commitPoint argument indicates
@@ -148,6 +149,8 @@
             &doubleLetterTerminalIndex, &doubleLetterLevel);
 
     int maxScore = S_INT_MIN;
+    int bestExactMatchedNodeTerminalIndex = -1;
+    int bestExactMatchedNodeOutputWordIndex = -1;
     // Output suggestion results here
     for (int terminalIndex = 0; terminalIndex < terminalSize && outputWordIndex < MAX_RESULTS;
             ++terminalIndex) {
@@ -186,7 +189,6 @@
         const int finalScore = SCORING->calculateFinalScore(
                 compoundDistance, traverseSession->getInputSize(),
                 isForceCommitMultiWords || (isValidWord && SCORING->doesAutoCorrectValidWord()));
-
         maxScore = max(maxScore, finalScore);
 
         if (TRAVERSAL->allowPartialCommit()) {
@@ -200,6 +202,25 @@
         if (isValidWord) {
             outputTypes[outputWordIndex] = Dictionary::KIND_CORRECTION | outputTypeFlags;
             frequencies[outputWordIndex] = finalScore;
+            if (isSafeExactMatch) {
+                // Demote exact matches that are not the highest probable node among all exact
+                // matches.
+                const bool isBestTerminal = bestExactMatchedNodeTerminalIndex < 0
+                        || terminals[bestExactMatchedNodeTerminalIndex].getProbability()
+                                < terminalDicNode->getProbability();
+                const int outputWordIndexToBeDemoted = isBestTerminal ?
+                        bestExactMatchedNodeOutputWordIndex : outputWordIndex;
+                if (outputWordIndexToBeDemoted >= 0) {
+                    frequencies[outputWordIndexToBeDemoted] -=
+                            FINAL_SCORE_PENALTY_FOR_NOT_BEST_EXACT_MATCHED_WORD;
+                }
+                if (isBestTerminal) {
+                    // Updates the best exact matched node index.
+                    bestExactMatchedNodeTerminalIndex = terminalIndex;
+                    // Updates the best exact matched output word index.
+                    bestExactMatchedNodeOutputWordIndex = outputWordIndex;
+                }
+            }
             // Populate the outputChars array with the suggested word.
             const int startIndex = outputWordIndex * MAX_WORD_LENGTH;
             terminalDicNode->outputResult(&outputCodePoints[startIndex]);
diff --git a/native/jni/src/suggest/core/suggest.h b/native/jni/src/suggest/core/suggest.h
index 875cbe4..752bde9 100644
--- a/native/jni/src/suggest/core/suggest.h
+++ b/native/jni/src/suggest/core/suggest.h
@@ -82,6 +82,8 @@
 
     // Threshold for autocorrection classifier
     static const float AUTOCORRECT_CLASSIFICATION_THRESHOLD;
+    // Final score penalty to exact match words that are not the most probable exact match.
+    static const int FINAL_SCORE_PENALTY_FOR_NOT_BEST_EXACT_MATCHED_WORD;
 
     const Traversal *const TRAVERSAL;
     const Scoring *const SCORING;
diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
index f879892..2659e4a 100644
--- a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
+++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
@@ -33,6 +33,7 @@
 const float ScoringParams::OMISSION_COST_FIRST_CHAR = 0.582f;
 const float ScoringParams::INSERTION_COST = 0.730f;
 const float ScoringParams::INSERTION_COST_SAME_CHAR = 0.586f;
+const float ScoringParams::INSERTION_COST_PROXIMITY_CHAR = 0.70f;
 const float ScoringParams::INSERTION_COST_FIRST_CHAR = 0.623f;
 const float ScoringParams::TRANSPOSITION_COST = 0.516f;
 const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.319f;
diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.h b/native/jni/src/suggest/policyimpl/typing/scoring_params.h
index 53ac999..c39c417 100644
--- a/native/jni/src/suggest/policyimpl/typing/scoring_params.h
+++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.h
@@ -42,6 +42,7 @@
     static const float OMISSION_COST_FIRST_CHAR;
     static const float INSERTION_COST;
     static const float INSERTION_COST_SAME_CHAR;
+    static const float INSERTION_COST_PROXIMITY_CHAR;
     static const float INSERTION_COST_FIRST_CHAR;
     static const float TRANSPOSITION_COST;
     static const float SPACE_SUBSTITUTION_COST;
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
index e21b318..5ae396e 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
+++ b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
@@ -147,7 +147,7 @@
     AK_FORCE_INLINE bool sameAsTyped(
             const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const {
         return traverseSession->getProximityInfoState(0)->sameAsTyped(
-                dicNode->getOutputWordBuf(), dicNode->getDepth());
+                dicNode->getOutputWordBuf(), dicNode->getNodeCodePointCount());
     }
 
     AK_FORCE_INLINE int getMaxCacheSize() const {
@@ -171,7 +171,7 @@
             return false;
         }
         const int c = dicNode->getOutputWordBuf()[0];
-        const bool shortCappedWord = dicNode->getDepth()
+        const bool shortCappedWord = dicNode->getNodeCodePointCount()
                 < ScoringParams::THRESHOLD_SHORT_WORD_LENGTH && CharUtils::isAsciiUpper(c);
         return !shortCappedWord
                 || probability >= ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY_FOR_CAPPED;
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
index a1c9918..e098f35 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
+++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
@@ -55,7 +55,7 @@
         const bool isZeroCostOmission = parentDicNode->isZeroCostOmission();
         const bool sameCodePoint = dicNode->isSameNodeCodePoint(parentDicNode);
         // If the traversal omitted the first letter then the dicNode should now be on the second.
-        const bool isFirstLetterOmission = dicNode->getDepth() == 2;
+        const bool isFirstLetterOmission = dicNode->getNodeCodePointCount() == 2;
         float cost = 0.0f;
         if (isZeroCostOmission) {
             cost = 0.0f;
@@ -83,7 +83,7 @@
         const bool isProximity = isProximityDicNode(traverseSession, dicNode);
         float cost = isProximity ? (isFirstChar ? ScoringParams::FIRST_PROXIMITY_COST
                 : ScoringParams::PROXIMITY_COST) : 0.0f;
-        if (dicNode->getDepth() == 2) {
+        if (dicNode->getNodeCodePointCount() == 2) {
             // At the second character of the current word, we check if the first char is uppercase
             // and the word is a second or later word of a multiple word suggestion. We demote it
             // if so.
@@ -122,19 +122,25 @@
 
     float getInsertionCost(const DicTraverseSession *const traverseSession,
             const DicNode *const parentDicNode, const DicNode *const dicNode) const {
-        const int16_t parentPointIndex = parentDicNode->getInputIndex(0);
-        const int prevCodePoint =
-                traverseSession->getProximityInfoState(0)->getPrimaryCodePointAt(parentPointIndex);
-
+        const int16_t insertedPointIndex = parentDicNode->getInputIndex(0);
+        const int prevCodePoint = traverseSession->getProximityInfoState(0)->getPrimaryCodePointAt(
+                insertedPointIndex);
         const int currentCodePoint = dicNode->getNodeCodePoint();
         const bool sameCodePoint = prevCodePoint == currentCodePoint;
+        const bool existsAdjacentProximityChars = traverseSession->getProximityInfoState(0)
+                ->existsAdjacentProximityChars(insertedPointIndex);
         const float dist = traverseSession->getProximityInfoState(0)->getPointToKeyLength(
-                parentPointIndex + 1, currentCodePoint);
+                insertedPointIndex + 1, dicNode->getNodeCodePoint());
         const float weightedDistance = dist * ScoringParams::DISTANCE_WEIGHT_LENGTH;
-        const bool singleChar = dicNode->getDepth() == 1;
-        const float cost = (singleChar ? ScoringParams::INSERTION_COST_FIRST_CHAR : 0.0f)
-                + (sameCodePoint ? ScoringParams::INSERTION_COST_SAME_CHAR
-                        : ScoringParams::INSERTION_COST);
+        const bool singleChar = dicNode->getNodeCodePointCount() == 1;
+        float cost = (singleChar ? ScoringParams::INSERTION_COST_FIRST_CHAR : 0.0f);
+        if (sameCodePoint) {
+            cost += ScoringParams::INSERTION_COST_SAME_CHAR;
+        } else if (existsAdjacentProximityChars) {
+            cost += ScoringParams::INSERTION_COST_PROXIMITY_CHAR;
+        } else {
+            cost += ScoringParams::INSERTION_COST;
+        }
         return cost + weightedDistance;
     }
 
@@ -163,6 +169,9 @@
 
     float getTerminalLanguageCost(const DicTraverseSession *const traverseSession,
             const DicNode *const dicNode, const float dicNodeLanguageImprobability) const {
+        // We promote exact matches here to prevent them from being pruned. The final score of
+        // exact match nodes might be demoted later in Suggest::outputSuggestions if there are
+        // multiple exact matches.
         const float languageImprobability = (dicNode->isExactMatch()) ?
                 0.0f : dicNodeLanguageImprobability;
         return languageImprobability * ScoringParams::DISTANCE_WEIGHT_LANGUAGE;
diff --git a/tests/src/com/android/inputmethod/keyboard/SpacebarTextTests.java b/tests/src/com/android/inputmethod/keyboard/SpacebarTextTests.java
index 850af94..057a0c0 100644
--- a/tests/src/com/android/inputmethod/keyboard/SpacebarTextTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/SpacebarTextTests.java
@@ -23,11 +23,11 @@
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.latin.AdditionalSubtype;
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.RichInputMethodManager;
-import com.android.inputmethod.latin.StringUtils;
 import com.android.inputmethod.latin.SubtypeLocale;
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.LocaleUtils.RunInLocale;
+import com.android.inputmethod.latin.utils.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Locale;
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserSplitTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserSplitTests.java
index eea1efc..f04c7e9 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserSplitTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserSplitTests.java
@@ -22,8 +22,8 @@
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 
-import com.android.inputmethod.latin.CollectionUtils;
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.LocaleUtils.RunInLocale;
 
 import java.lang.reflect.Field;
 import java.util.ArrayList;
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
index b55158d..2d9dc5e 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
@@ -26,7 +26,7 @@
 import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
+import com.android.inputmethod.latin.utils.LocaleUtils.RunInLocale;
 
 import java.util.Arrays;
 import java.util.Locale;
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
index 8506e16..db39976 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
@@ -19,7 +19,7 @@
 import android.text.TextUtils;
 
 import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.RecapitalizeStatus;
+import com.android.inputmethod.latin.utils.RecapitalizeStatus;
 
 public class MockKeyboardSwitcher implements KeyboardState.SwitchActions {
     public interface MockConstants {
diff --git a/tests/src/com/android/inputmethod/latin/InputPointersTests.java b/tests/src/com/android/inputmethod/latin/InputPointersTests.java
index 3015829..f0b6acc 100644
--- a/tests/src/com/android/inputmethod/latin/InputPointersTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputPointersTests.java
@@ -19,6 +19,8 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.inputmethod.latin.utils.ResizableIntArray;
+
 import java.util.Arrays;
 
 @SmallTest
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index aec4aac..d1ce104 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -36,6 +36,7 @@
 import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.utils.LocaleUtils;
 
 import java.util.Locale;
 
@@ -242,6 +243,7 @@
         mEditText.mCurrentLocale = LocaleUtils.constructLocaleFromString(locale);
         SubtypeSwitcher.getInstance().forceLocale(mEditText.mCurrentLocale);
         mLatinIME.loadKeyboard();
+        runMessages();
         mKeyboard = mLatinIME.mKeyboardSwitcher.getKeyboard();
         waitForDictionaryToBeLoaded();
     }
diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java
index abfaf30..b64013e 100644
--- a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java
+++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java
@@ -22,7 +22,8 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.inputmethod.InputMethodSubtype;
 
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.LocaleUtils.RunInLocale;
 
 import java.util.ArrayList;
 import java.util.Locale;
diff --git a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
index 9162522..8d0fe01 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
@@ -21,6 +21,8 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.inputmethod.latin.utils.CollectionUtils;
+
 import java.util.ArrayList;
 import java.util.Locale;
 
diff --git a/tests/src/com/android/inputmethod/latin/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/UserHistoryDictionaryTests.java
index 594ba0e..93befd7 100644
--- a/tests/src/com/android/inputmethod/latin/UserHistoryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/UserHistoryDictionaryTests.java
@@ -22,6 +22,8 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
+import com.android.inputmethod.latin.utils.CollectionUtils;
+
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java
index b704d08..cca81a0 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java
@@ -22,13 +22,13 @@
 import android.util.Log;
 import android.util.SparseArray;
 
-import com.android.inputmethod.latin.CollectionUtils;
-import com.android.inputmethod.latin.UserHistoryDictIOUtils;
+import com.android.inputmethod.latin.ByteArrayWrapper;
 import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface;
 import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
 import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
 import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
 import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -106,7 +106,7 @@
             if (bufferType == USE_BYTE_ARRAY) {
                 final byte[] array = new byte[(int)file.length()];
                 inStream.read(array);
-                return new UserHistoryDictIOUtils.ByteArrayWrapper(array);
+                return new ByteArrayWrapper(array);
             } else if (bufferType == USE_BYTE_BUFFER){
                 final ByteBuffer buffer = inStream.getChannel().map(
                         FileChannel.MapMode.READ_ONLY, 0, file.length());
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
index 47885f0..d33142c 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
@@ -21,12 +21,12 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
-import com.android.inputmethod.latin.CollectionUtils;
 import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.ByteBufferWrapper;
 import com.android.inputmethod.latin.makedict.BinaryDictInputOutput.FusionDictionaryBufferInterface;
 import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
 import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
 import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -40,7 +40,7 @@
 import java.util.Random;
 
 @LargeTest
-public class BinaryDictIOUtilsTests  extends AndroidTestCase {
+public class BinaryDictIOUtilsTests extends AndroidTestCase {
     private static final String TAG = BinaryDictIOUtilsTests.class.getSimpleName();
     private static final FormatSpec.FormatOptions FORMAT_OPTIONS =
             new FormatSpec.FormatOptions(3, true);
@@ -53,12 +53,17 @@
         "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
         "\u00FC" /* ü */, "\u00E2" /* â */, "\u00F1" /* ñ */, // accented characters
         "\u4E9C" /* 亜 */, "\u4F0A" /* 伊 */, "\u5B87" /* 宇 */, // kanji
-        "\uD841\uDE28" /* 𠘨 */, "\uD840\uDC0B" /* 𠀋 */, "\uD861\uDeD7" /* 𨛗 */ // surrogate pair
+        "\uD841\uDE28" /* 𠘨 */, "\uD840\uDC0B" /* 𠀋 */, "\uD861\uDED7" /* 𨛗 */ // surrogate pair
     };
 
     public BinaryDictIOUtilsTests() {
+        this(System.currentTimeMillis());
+    }
+
+    public BinaryDictIOUtilsTests(final long seed) {
         super();
-        final Random random = new Random(123456);
+        Log.d(TAG, "Seed for test is " + seed);
+        final Random random = new Random(seed);
         sWords.clear();
         for (int i = 0; i < MAX_UNIGRAMS; ++i) {
             sWords.add(generateWord(random.nextInt()));
diff --git a/tests/src/com/android/inputmethod/latin/CapsModeUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java
similarity index 98%
rename from tests/src/com/android/inputmethod/latin/CapsModeUtilsTests.java
rename to tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java
index 339791d..cf3bdd6 100644
--- a/tests/src/com/android/inputmethod/latin/CapsModeUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/CapsModeUtilsTests.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
diff --git a/tests/src/com/android/inputmethod/latin/ForgettingCurveTests.java b/tests/src/com/android/inputmethod/latin/utils/ForgettingCurveTests.java
similarity index 97%
rename from tests/src/com/android/inputmethod/latin/ForgettingCurveTests.java
rename to tests/src/com/android/inputmethod/latin/utils/ForgettingCurveTests.java
index 3259312..823bd5d 100644
--- a/tests/src/com/android/inputmethod/latin/ForgettingCurveTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/ForgettingCurveTests.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
diff --git a/tests/src/com/android/inputmethod/latin/RecapitalizeStatusTests.java b/tests/src/com/android/inputmethod/latin/utils/RecapitalizeStatusTests.java
similarity index 99%
rename from tests/src/com/android/inputmethod/latin/RecapitalizeStatusTests.java
rename to tests/src/com/android/inputmethod/latin/utils/RecapitalizeStatusTests.java
index 9d7203e..a520412 100644
--- a/tests/src/com/android/inputmethod/latin/RecapitalizeStatusTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/RecapitalizeStatusTests.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
diff --git a/tests/src/com/android/inputmethod/latin/ResizableIntArrayTests.java b/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java
similarity index 99%
rename from tests/src/com/android/inputmethod/latin/ResizableIntArrayTests.java
rename to tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java
index b9fee95..cfff61e 100644
--- a/tests/src/com/android/inputmethod/latin/ResizableIntArrayTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
diff --git a/tests/src/com/android/inputmethod/latin/ResourceUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/ResourceUtilsTests.java
similarity index 98%
rename from tests/src/com/android/inputmethod/latin/ResourceUtilsTests.java
rename to tests/src/com/android/inputmethod/latin/utils/ResourceUtilsTests.java
index c915522..1ae22e3 100644
--- a/tests/src/com/android/inputmethod/latin/ResourceUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/ResourceUtilsTests.java
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.inputmethod.latin.ResourceUtils.DeviceOverridePatternSyntaxError;
+import com.android.inputmethod.latin.utils.ResourceUtils.DeviceOverridePatternSyntaxError;
 
 import java.util.HashMap;
 
diff --git a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java
similarity index 99%
rename from tests/src/com/android/inputmethod/latin/StringUtilsTests.java
rename to tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java
index 4f26098..9ee8e38 100644
--- a/tests/src/com/android/inputmethod/latin/StringUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/StringUtilsTests.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
diff --git a/tests/src/com/android/inputmethod/latin/UserHistoryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java
similarity index 95%
rename from tests/src/com/android/inputmethod/latin/UserHistoryDictIOUtilsTests.java
rename to tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java
index 211d012..0d829c5 100644
--- a/tests/src/com/android/inputmethod/latin/UserHistoryDictIOUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/UserHistoryDictIOUtilsTests.java
@@ -14,18 +14,20 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.latin.utils;
 
 import android.content.Context;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
-import com.android.inputmethod.latin.UserHistoryDictIOUtils.BigramDictionaryInterface;
-import com.android.inputmethod.latin.UserHistoryDictIOUtils.OnAddWordListener;
+import com.android.inputmethod.latin.ByteArrayWrapper;
+import com.android.inputmethod.latin.UserHistoryDictionaryBigramList;
 import com.android.inputmethod.latin.makedict.FormatSpec;
 import com.android.inputmethod.latin.makedict.FusionDictionary;
 import com.android.inputmethod.latin.makedict.FusionDictionary.CharGroup;
+import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.BigramDictionaryInterface;
+import com.android.inputmethod.latin.utils.UserHistoryDictIOUtils.OnAddWordListener;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -152,8 +154,7 @@
             final byte[] buffer = new byte[(int)file.length()];
             inStream.read(buffer);
 
-            UserHistoryDictIOUtils.readDictionaryBinary(
-                    new UserHistoryDictIOUtils.ByteArrayWrapper(buffer), listener);
+            UserHistoryDictIOUtils.readDictionaryBinary(new ByteArrayWrapper(buffer), listener);
         } catch (FileNotFoundException e) {
             Log.e(TAG, "file not found", e);
         } catch (IOException e) {
diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk
index 666887a..9316787 100644
--- a/tools/dicttool/Android.mk
+++ b/tools/dicttool/Android.mk
@@ -16,10 +16,22 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-LATINIME_BASE_SOURCE_DIRECTORY := ../../java/src/com/android/inputmethod
+BUILD_TOP := ../../../../..
+FRAMEWORK_TOP := $(BUILD_TOP)/frameworks/base/core/java
+LATINIME_DIR := $(BUILD_TOP)/packages/inputmethods/LatinIME
+LATINIME_BASE_SOURCE_DIRECTORY := $(LATINIME_DIR)/java/src/com/android/inputmethod
 LATINIME_CORE_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/latin
 LATINIME_ANNOTATIONS_SOURCE_DIRECTORY := $(LATINIME_BASE_SOURCE_DIRECTORY)/annotations
 MAKEDICT_CORE_SOURCE_DIRECTORY := $(LATINIME_CORE_SOURCE_DIRECTORY)/makedict
+DICTTOOL_COMPAT_TESTS_DIRECTORY := compat
+DICTTOOL_ONDEVICE_TESTS_DIRECTORY := \
+        $(LATINIME_DIR)/tests/src/com/android/inputmethod/latin/makedict/
+
+USED_TARGETTED_UTILS := \
+        $(FRAMEWORK_TOP)/android/util/SparseArray.java \
+        $(FRAMEWORK_TOP)/com/android/internal/util/ArrayUtils.java \
+        $(LATINIME_CORE_SOURCE_DIRECTORY)/ByteArrayWrapper.java \
+        $(LATINIME_CORE_SOURCE_DIRECTORY)/utils/CollectionUtils.java
 
 LOCAL_MAIN_SRC_FILES := $(call all-java-files-under, $(MAKEDICT_CORE_SOURCE_DIRECTORY))
 LOCAL_TOOL_SRC_FILES := $(call all-java-files-under, src)
@@ -28,12 +40,13 @@
 LOCAL_SRC_FILES := $(LOCAL_TOOL_SRC_FILES) \
         $(filter-out $(addprefix %/, $(notdir $(LOCAL_TOOL_SRC_FILES))), $(LOCAL_MAIN_SRC_FILES)) \
         $(LOCAL_ANNOTATIONS_SRC_FILES) \
-        $(LATINIME_CORE_SOURCE_DIRECTORY)/Constants.java
+        $(LATINIME_CORE_SOURCE_DIRECTORY)/Constants.java \
+        $(call all-java-files-under, tests) \
+        $(call all-java-files-under, $(DICTTOOL_ONDEVICE_TESTS_DIRECTORY)) \
+        $(call all-java-files-under, $(DICTTOOL_COMPAT_TESTS_DIRECTORY)) \
+        $(USED_TARGETTED_UTILS)
 
-ifeq ($(DICTTOOL_UNITTEST), true)
-    LOCAL_SRC_FILES += $(call all-java-files-under, tests)
-    LOCAL_JAVA_LIBRARIES := junit
-endif
+LOCAL_JAVA_LIBRARIES := junit
 
 LOCAL_JAR_MANIFEST := etc/manifest.txt
 LOCAL_MODULE := dicttool_aosp
diff --git a/tools/dicttool/compat/android/test/AndroidTestCase.java b/tools/dicttool/compat/android/test/AndroidTestCase.java
new file mode 100644
index 0000000..d01b7ad
--- /dev/null
+++ b/tools/dicttool/compat/android/test/AndroidTestCase.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+
+/**
+ * This is a compatibility class that aims at emulating android.test.AndroidTestcase from the
+ * Android library as simply as possible, and only to the extent that is used by the client classes.
+ * Its purpose is to provide compatibility without having to pull the whole Android library.
+ */
+public class AndroidTestCase extends TestCase {
+    public File getCacheDir() {
+        return new File(".");
+    }
+    public AndroidTestCase getContext() {
+        return this;
+    }
+}
diff --git a/tools/dicttool/compat/android/test/MoreAsserts.java b/tools/dicttool/compat/android/test/MoreAsserts.java
new file mode 100644
index 0000000..f56420b
--- /dev/null
+++ b/tools/dicttool/compat/android/test/MoreAsserts.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import junit.framework.Assert;
+
+/**
+ * This is a compatibility class that aims at emulating android.test.MoreAsserts from the
+ * Android library as simply as possible, and only to the extent that is used by the client classes.
+ * Its purpose is to provide compatibility without having to pull the whole Android library.
+ */
+public class MoreAsserts {
+    public static void assertNotEqual(Object unexpected, Object actual) {
+        if (equal(unexpected, actual)) {
+            Assert.fail("expected not to be:<" + unexpected + ">");
+        }
+    }
+    private static boolean equal(Object a, Object b) {
+        return a == b || (a != null && a.equals(b));
+    }
+}
diff --git a/tools/dicttool/compat/android/test/suitebuilder/annotation/LargeTest.java b/tools/dicttool/compat/android/test/suitebuilder/annotation/LargeTest.java
new file mode 100644
index 0000000..ed00f8d
--- /dev/null
+++ b/tools/dicttool/compat/android/test/suitebuilder/annotation/LargeTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.annotation;
+
+/**
+ * This is a compatibility class that aims at emulating the LargeTest annotation from the
+ * Android library as simply as possible, and only to the extent that is used by the client classes.
+ * Its purpose is to provide compatibility without having to pull the whole Android library.
+ */
+public @interface LargeTest {
+}
diff --git a/tools/dicttool/compat/android/util/Log.java b/tools/dicttool/compat/android/util/Log.java
new file mode 100644
index 0000000..d9df3a4
--- /dev/null
+++ b/tools/dicttool/compat/android/util/Log.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+/**
+ * This is a compatibility class that aims at emulating android.util.Log from the
+ * Android library as simply as possible, and only to the extent that is used by the client classes.
+ * Its purpose is to provide compatibility without having to pull the whole Android library.
+ */
+public class Log {
+    public static void d(final String tag, final String message) {
+        System.out.println(tag + " : " + message);
+    }
+    public static void d(final String tag, final String message, final Exception e) {
+        System.out.println(tag + " : " + message + " : " + e);
+    }
+    public static void e(final String tag, final String message) {
+        d(tag, message);
+    }
+    public static void e(final String tag, final String message, final Exception e) {
+        e(tag, message, e);
+    }
+}
diff --git a/tools/dicttool/etc/dicttool_aosp b/tools/dicttool/etc/dicttool_aosp
index a4879a2..cc7111a 100755
--- a/tools/dicttool/etc/dicttool_aosp
+++ b/tools/dicttool/etc/dicttool_aosp
@@ -33,6 +33,7 @@
 prog="${progdir}"/`basename "${prog}"`
 cd "${oldwd}"
 
+classname=com.android.inputmethod.latin.dicttool.Dicttool
 jarfile=dicttool_aosp.jar
 frameworkdir="$progdir"
 if [ ! -r "$frameworkdir/$jarfile" ]
@@ -51,12 +52,21 @@
     exit 1
 fi
 
+lib=junit.jar
+if [ ! -r "$frameworkdir/$lib" ]
+then
+    echo `basename "$prog"`": can't find lib $lib"
+    exit 1
+fi
+
 if [ "$OSTYPE" = "cygwin" ] ; then
     jarpath=`cygpath -w  "$frameworkdir/$jarfile"`
+    libpath=`cygpath -w  "$frameworkdir/$lib"`
     progdir=`cygpath -w  "$progdir"`
 else
     jarpath="$frameworkdir/$jarfile"
+    libpath="$frameworkdir/$lib"
 fi
 
 # might need more memory, e.g. -Xmx128M
-exec java -ea -jar "$jarpath" "$@"
+exec java -ea -classpath "$libpath":"$jarpath" "$classname" "$@"
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CommandList.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CommandList.java
index 0e0095b..0d93c7f 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CommandList.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/CommandList.java
@@ -27,5 +27,6 @@
         Dicttool.addCommand("package", Package.Packager.class);
         Dicttool.addCommand("unpackage", Package.Unpackager.class);
         Dicttool.addCommand("makedict", Makedict.class);
+        Dicttool.addCommand("test", Test.class);
     }
 }
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Crypt.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Crypt.java
index f899023..4612ae4 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Crypt.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Crypt.java
@@ -40,10 +40,12 @@
         public Encrypter() {
         }
 
+        @Override
         public String getHelp() {
             return COMMAND + " <src_filename> <dst_filename>: Encrypts a file";
         }
 
+        @Override
         public void run() {
             throw new UnsupportedOperationException();
         }
@@ -55,10 +57,12 @@
         public Decrypter() {
         }
 
+        @Override
         public String getHelp() {
             return COMMAND + " <src_filename> <dst_filename>: Decrypts a file";
         }
 
+        @Override
         public void run() {
             throw new UnsupportedOperationException();
         }
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java
index b294807..9274dcd 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Package.java
@@ -22,9 +22,7 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
-import java.io.InputStream;
 import java.io.IOException;
-import java.io.OutputStream;
 
 public class Package {
     private Package() {
@@ -39,10 +37,12 @@
         public Packager() {
         }
 
+        @Override
         public String getHelp() {
             return COMMAND + " <src_filename> <dst_filename>: Package a file for distribution";
         }
 
+        @Override
         public void run() throws IOException {
             if (mArgs.length != 2) {
                 throw new RuntimeException("Too many/too few arguments for command " + COMMAND);
@@ -67,11 +67,13 @@
         public Unpackager() {
         }
 
+        @Override
         public String getHelp() {
             return COMMAND + " <src_filename> <dst_filename>: Detects how a file is packaged and\n"
                     + "decrypts/uncompresses as necessary to produce a raw binary file.";
         }
 
+        @Override
         public void run() throws FileNotFoundException, IOException {
             if (mArgs.length != 2) {
                 throw new RuntimeException("Too many/too few arguments for command " + COMMAND);
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java
new file mode 100644
index 0000000..827c5e3
--- /dev/null
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.android.inputmethod.latin.dicttool;
+
+import com.android.inputmethod.latin.makedict.BinaryDictIOUtilsTests;
+import com.android.inputmethod.latin.makedict.BinaryDictInputOutputTest;
+import com.android.inputmethod.latin.makedict.FusionDictionaryTest;
+import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
+
+import java.io.IOException;
+
+/**
+ * Dicttool command implementing self-tests.
+ */
+public class Test extends Dicttool.Command {
+    public static final String COMMAND = "test";
+
+    public Test() {
+    }
+
+    @Override
+    public String getHelp() {
+        return "test";
+    }
+
+    @Override
+    public void run() throws IOException, UnsupportedFormatException {
+        test();
+    }
+
+    private void test() throws IOException, UnsupportedFormatException {
+        new BinaryDictOffdeviceUtilsTests().testGetRawDictWorks();
+        new FusionDictionaryTest().testFusion();
+        new BinaryDictInputOutputTest().testFlattenNodes();
+        new BinaryDictIOUtilsTests().testRandomWords();
+    }
+}
diff --git a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java
index fe3781d..7607113 100644
--- a/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java
+++ b/tools/dicttool/tests/com/android/inputmethod/latin/makedict/FusionDictionaryTest.java
@@ -73,10 +73,6 @@
         for (final String word : words) {
             if (--limit < 0) return;
             final CharGroup cg = FusionDictionary.findWordInTree(dict.mRoot, word);
-            if (null == cg) {
-                System.out.println("word " + dumpWord(word));
-                dumpDict(dict);
-            }
             assertNotNull(cg);
         }
     }