Merge "Get dynamic dict stats via DictionaryFacilitator"
diff --git a/java/res/layout/suggestions_strip.xml b/java/res/layout/suggestions_strip.xml
index 4894779..aefdb8ca 100644
--- a/java/res/layout/suggestions_strip.xml
+++ b/java/res/layout/suggestions_strip.xml
@@ -48,12 +48,13 @@
             android:layout_height="match_parent"
             style="?attr/suggestionWordStyle" />
         <include
+            android:id="@+id/word_to_save_divider"
             layout="@layout/suggestion_divider" />
         <TextView
             android:id="@+id/hint_add_to_dictionary"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:textAlignment="viewStart"
+            android:gravity="center_vertical|start"
             style="?attr/suggestionWordStyle" />
     </LinearLayout>
     <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
index 515051a..f4af1db 100644
--- a/java/res/values-bg/strings.xml
+++ b/java/res/values-bg/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Няма активирани методи на гласово въвеждане. Проверете настройките за език и въвеждане."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Конфигуриране на въвеждането"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Входни езици"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Помощ и отзиви"</string>
     <string name="select_language" msgid="3693815588777926848">"Езици за въвеждане"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Докоснете отново, за да запазите"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Има достъп до речник"</string>
diff --git a/java/res/values-bn-rBD/strings.xml b/java/res/values-bn-rBD/strings.xml
index 48c887d..b52409e 100644
--- a/java/res/values-bn-rBD/strings.xml
+++ b/java/res/values-bn-rBD/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"কোনো ভয়েস ইনপুট পদ্ধতি সক্ষম নয়। ভাষা &amp; ইনপুট সেটিংস পরীক্ষা করুন।"</string>
     <string name="configure_input_method" msgid="373356270290742459">"ইনপুট পদ্ধতি কনফিগার করুন"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"ইনপুট ভাষাগুলি"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"সহায়তা এবং প্রতিক্রিয়া"</string>
     <string name="select_language" msgid="3693815588777926848">"ইনপুট ভাষাগুলি"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"সংরক্ষণ করতে আবার ছোঁন"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"অভিধান উপলব্ধ"</string>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
index 933112c..2fab1b7 100644
--- a/java/res/values-ca/strings.xml
+++ b/java/res/values-ca/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"No hi ha cap mètode d\'introducció activat. Comprova la configuració d\'Idioma i introducció de text."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configura mètodes d\'entrada"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomes"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Ajuda i opinió"</string>
     <string name="select_language" msgid="3693815588777926848">"Idiomes d\'introducció"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Torna a tocar per desar"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Diccionari disponible"</string>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index 4c884cf..265e457 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nejsou povoleny žádné metody hlasového vstupu. Zkontrolujte nastavení Jazyk a vstup."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurace metod zadávání"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Vstupní jazyky"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Nápověda a zpětná vazba"</string>
     <string name="select_language" msgid="3693815588777926848">"Vstupní jazyky"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Opětovným dotykem provedete uložení"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Slovník k dispozici"</string>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
index 4b821b4..2e7c88a 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Der er ingen aktiverede stemmeinputmetoder. Kontrollér Indstillinger for sprog og input."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurer inputmetoder"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Inputsprog"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Hjælp og feedback"</string>
     <string name="select_language" msgid="3693815588777926848">"Inputsprog"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Tryk igen for at gemme"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Ordbog er tilgængelig"</string>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
index 1fe242a..cf4c554 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Keine Spracheingabemethoden aktiviert. Rufen Sie die Einstellungen für \"Sprache &amp; Eingabe\" auf."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Eingabemethoden konfigurieren"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Eingabesprachen"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Hilfe &amp; Feedback"</string>
     <string name="select_language" msgid="3693815588777926848">"Eingabesprachen"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Zum Speichern erneut berühren"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Wörterbuch verfügbar"</string>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index 0c1bca3..239541f 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Δεν έχουν ενεργοποιηθεί μέθοδοι φωνητικής εισαγωγής. Ελέγξτε τις Ρυθμίσεις Γλώσσας και εισαγωγής."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Διαμόρφωση μεθόδων εισαγωγής"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Γλώσσες εισόδου"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Βοήθεια και σχόλια"</string>
     <string name="select_language" msgid="3693815588777926848">"Γλώσσες εισόδου"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Αγγίξτε ξανά για αποθήκευση"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Λεξικό διαθέσιμο"</string>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index e810c0b..84135ef 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"No hay métodos de entrada de voz habilitados. Comprueba la configuración de Teclado e idioma."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Ayuda y comentarios"</string>
     <string name="select_language" msgid="3693815588777926848">"Idiomas de entrada"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Vuelve a tocar para guardar."</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Diccionario disponible"</string>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
index ef227bd..98b985b 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Sin métodos de introducción de voz habilitados. Comprueba ajustes de Idioma e introducción de texto."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomas"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Ayuda y opiniones"</string>
     <string name="select_language" msgid="3693815588777926848">"Idiomas de introducción"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Toca otra vez para guardar"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Hay un diccionario disponible"</string>
diff --git a/java/res/values-et-rEE/strings.xml b/java/res/values-et-rEE/strings.xml
index 243d913..042f7cf 100644
--- a/java/res/values-et-rEE/strings.xml
+++ b/java/res/values-et-rEE/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ühtegi häälsisendmeetodit pole lubatud. Kontrollige keele- ja sisendiseadeid."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Sisestusmeetodite seadistamine"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Sisestuskeeled"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Abi ja tagasiside"</string>
     <string name="select_language" msgid="3693815588777926848">"Sisestuskeeled"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Salvestamiseks puudutage uuesti"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Sõnastik saadaval"</string>
diff --git a/java/res/values-eu-rES/strings.xml b/java/res/values-eu-rES/strings.xml
index 5b86ae3..f3128ae 100644
--- a/java/res/values-eu-rES/strings.xml
+++ b/java/res/values-eu-rES/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ez da ahots bidezko idazketa-metodorik gaitu. Egiaztatu Hizkuntza eta idazketa ataleko ezarpenak."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfiguratu idazketa-metodoak"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idazketa-hizkuntzak"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Laguntza eta iritziak"</string>
     <string name="select_language" msgid="3693815588777926848">"Idazketa-hizkuntzak"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Gordetzeko, ukitu berriro"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Hiztegia erabilgarri"</string>
diff --git a/java/res/values-fr-rCA/strings.xml b/java/res/values-fr-rCA/strings.xml
index 4c6d82c..e2cf8cf 100644
--- a/java/res/values-fr-rCA/strings.xml
+++ b/java/res/values-fr-rCA/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Aucun mode d\'entrée vocale n\'a été activé. Vérifiez les paramètres de langues et d\'entrée de texte."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurer les modes de saisie"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Langues de saisie"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Aide et commentaires"</string>
     <string name="select_language" msgid="3693815588777926848">"Langues de saisie"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Appuyer de nouveau pour enregistrer"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dictionnaire disponible"</string>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index 077ead3..75961d1 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Aucun mode de saisie vocale activé. Vérifiez les paramètres de langue et de saisie."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurer les modes de saisie"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Langues de saisie"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Aide et commentaires"</string>
     <string name="select_language" msgid="3693815588777926848">"Langues de saisie"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Appuyer de nouveau pour enregistrer"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dictionnaire disponible"</string>
diff --git a/java/res/values-gl-rES/strings.xml b/java/res/values-gl-rES/strings.xml
index 8d5bd0b..40431e7 100644
--- a/java/res/values-gl-rES/strings.xml
+++ b/java/res/values-gl-rES/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Non hai ningún método de entrada de voz activado. Comproba a configuración de Idioma e entrada de texto."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Axuda e opinións"</string>
     <string name="select_language" msgid="3693815588777926848">"Idiomas de entrada"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Toca de novo para gardar"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dicionario dispoñible"</string>
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index 754ddc5..86d5130 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"कोई ध्वनि इनपुट पद्धति सक्षम नहीं है. भाषा और इनपुट सेटिंग जांचें."</string>
     <string name="configure_input_method" msgid="373356270290742459">"इनपुट पद्धति कॉन्‍फ़िगर करें"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"इनपुट भाषा"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"सहायता और फ़ीडबैक"</string>
     <string name="select_language" msgid="3693815588777926848">"इनपुट भाषाएं"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"सहेजने के लिए पुन: स्‍पर्श करें"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"शब्‍दकोश उपलब्‍ध है"</string>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index 28ec9f6..d6b1352 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nije omogućen nijedan način glasovnog unosa. Provjerite postavke jezika i unosa."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfiguriraj načine ulaza"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Jezici unosa"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Pomoć i povratne informacije"</string>
     <string name="select_language" msgid="3693815588777926848">"Jezici unosa"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Dodirnite ponovo za spremanje"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Rječnik je dostupan"</string>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
index 368deab..b38d1bf 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nincs engedélyezett hangbeviteli módszer. Nézze meg a Nyelvi és beviteli beállításokat."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Beviteli módok beállítása"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Beviteli nyelvek"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Súgó és visszajelzés"</string>
     <string name="select_language" msgid="3693815588777926848">"Beviteli nyelvek"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Érintse meg újból a mentéshez"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Van elérhető szótár"</string>
diff --git a/java/res/values-hy-rAM/strings.xml b/java/res/values-hy-rAM/strings.xml
index f0742b4..26a3b02 100644
--- a/java/res/values-hy-rAM/strings.xml
+++ b/java/res/values-hy-rAM/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ձայնային ներածման որևէ եղանակ միացված չէ։ Ստուգեք Լեզվի և ներածման կարգավորումները։"</string>
     <string name="configure_input_method" msgid="373356270290742459">"Կարգավորել մուտքագրման մեթոդները"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Մուտքագրման լեզուներ"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Օգնություն և հետադարձ կապ"</string>
     <string name="select_language" msgid="3693815588777926848">"Մուտքագրման լեզուներ"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Պահպանելու համար կրկին հպեք"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Բառարանն առկա է"</string>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
index f9353d0..9c898b7 100644
--- a/java/res/values-in/strings.xml
+++ b/java/res/values-in/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Tidak ada metode masukan suara yang diaktifkan. Periksa setelan Bahasan &amp; masukan."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurasikan metode masukan"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Bahasa masukan"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Bantuan &amp; masukan"</string>
     <string name="select_language" msgid="3693815588777926848">"Bahasa masukan"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Sentuh lagi untuk menyimpan"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Kamus yang tersedia"</string>
diff --git a/java/res/values-is-rIS/strings.xml b/java/res/values-is-rIS/strings.xml
index ecf9705..8d46c89 100644
--- a/java/res/values-is-rIS/strings.xml
+++ b/java/res/values-is-rIS/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Engar innsláttaraðferðir fyrir rödd virkar. Kannaðu stillingar tungumáls og innsláttar."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Stilla innsláttaraðferðir"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Innsláttartungumál"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Hjálp og ábendingar"</string>
     <string name="select_language" msgid="3693815588777926848">"Innsláttartungumál"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Snertu aftur til að vista"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Orðabók í boði"</string>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index ed34165..4f331a3 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"לא הופעלו שיטות של קלט קולי. בדוק את הגדרות השפה והקלט."</string>
     <string name="configure_input_method" msgid="373356270290742459">"הגדרת שיטות קלט"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"שפות קלט"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"עזרה ומשוב"</string>
     <string name="select_language" msgid="3693815588777926848">"שפות קלט"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"גע שוב כדי לשמור"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"מילון זמין"</string>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index 77e0fa0..97f84e7 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"有効になっている音声入力方法がありません。[言語と入力]設定をご確認ください。"</string>
     <string name="configure_input_method" msgid="373356270290742459">"入力方法を設定"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"入力言語"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"ヘルプとフィードバック"</string>
     <string name="select_language" msgid="3693815588777926848">"入力言語"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"保存するにはもう一度タップ"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"辞書を利用できます"</string>
diff --git a/java/res/values-ka-rGE/strings.xml b/java/res/values-ka-rGE/strings.xml
index 7e05e5f..a42b6df 100644
--- a/java/res/values-ka-rGE/strings.xml
+++ b/java/res/values-ka-rGE/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"ხმოვანი შეყვანის მეთოდები ჩართული არ არის. შეამოწმეთ ენის &amp; შეყვანის პარამეტრები."</string>
     <string name="configure_input_method" msgid="373356270290742459">"შეყვანის მეთოდების კონფიგურაცია"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"შეყვანის ენები"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"დახმარება და უკუკავშირი"</string>
     <string name="select_language" msgid="3693815588777926848">"შეყვანის ენები"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"შეეხეთ ისევ შესანახად"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"ხელმისაწვდომია ლექსიკონი"</string>
diff --git a/java/res/values-kk-rKZ/strings.xml b/java/res/values-kk-rKZ/strings.xml
index e08fd78..64ee430 100644
--- a/java/res/values-kk-rKZ/strings.xml
+++ b/java/res/values-kk-rKZ/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Дауыспен енгізу әдістері қосылмаған. «Тіл және енгізу параметрлері» тармағын тексеріңіз."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Енгізу әдістерін теңшеу"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Енгізу тілдері"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Анықтама және кері байланыс"</string>
     <string name="select_language" msgid="3693815588777926848">"Енгізу тілдері"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Сақтау үшін қайта түртіңіз"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Сөздік қолжетімді"</string>
diff --git a/java/res/values-km-rKH/strings-emoji-descriptions.xml b/java/res/values-km-rKH/strings-emoji-descriptions.xml
index 757df50..9f1d997 100644
--- a/java/res/values-km-rKH/strings-emoji-descriptions.xml
+++ b/java/res/values-km-rKH/strings-emoji-descriptions.xml
@@ -25,16 +25,16 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="spoken_emoji_00A9" msgid="2859822817116803638">"សញ្ញា​រក្សា​សិទ្ធ​"</string>
+    <string name="spoken_emoji_00A9" msgid="2859822817116803638">"សញ្ញា​រក្សា​សិទ្ធ"</string>
     <string name="spoken_emoji_00AE" msgid="7708335454134589027">"សញ្ញា​​​ចុះ​បញ្ជី"</string>
     <string name="spoken_emoji_203C" msgid="153340916701508663">"សញ្ញា​ឧទាន​​ពីរ"</string>
-    <string name="spoken_emoji_2049" msgid="4877256448299555371">"សញ្ញា​​ឧទាន​សញ្ញា​សួរ​​"</string>
+    <string name="spoken_emoji_2049" msgid="4877256448299555371">"សញ្ញា​​ឧទាន​សញ្ញា​សួរ"</string>
     <string name="spoken_emoji_2122" msgid="9188440722954720429">"សញ្ញា​​​និក្ខិត្តសញ្ញា"</string>
     <string name="spoken_emoji_2139" msgid="9114342638917304327">"ប្រភព​ព័ត៌មាន"</string>
     <string name="spoken_emoji_2194" msgid="8055202727034946680">"ព្រួញ​ឆ្វេងស្ដាំ"</string>
     <string name="spoken_emoji_2195" msgid="8028122253301087407">"ព្រួញ​ឡើង​លើ​ចុះក្រោម"</string>
     <string name="spoken_emoji_2196" msgid="4019164898967854363">"ព្រួញ​ទិសពាយព្យ"</string>
-    <string name="spoken_emoji_2197" msgid="4255723717709017801">"ព្រួញ​​ទិស​ឥសាន្ត​ឦសាន្ត​"</string>
+    <string name="spoken_emoji_2197" msgid="4255723717709017801">"ព្រួញ​​ទិស​ឥសាន្ត​ឦសាន្ត"</string>
     <string name="spoken_emoji_2198" msgid="1452063451313622090">"ព្រួញ​​ទិស​អាគ្នេយ៍"</string>
     <string name="spoken_emoji_2199" msgid="6942722693368807849">"ព្រួញ​​ទិស​និរតី"</string>
     <string name="spoken_emoji_21A9" msgid="5204750172335111188">"ព្រួញ​ទៅ​ឆ្វេង​មាន​ទំពក់"</string>
@@ -45,7 +45,7 @@
     <string name="spoken_emoji_23EA" msgid="2251396938087774944">"ត្រីកោណ​ខ្មៅ​ពីរ​ចង្អុល​ទៅ​ឆ្វេង"</string>
     <string name="spoken_emoji_23EB" msgid="3746885195641491865">"ត្រីកោណ​ខ្មៅ​ពីរ​ចង្អុល​​ឡើង​លើ"</string>
     <string name="spoken_emoji_23EC" msgid="7852372752901163416">"ត្រីកោណ​ខ្មៅ​ពីរ​ចង្អុល​​ចុះក្រោម"</string>
-    <string name="spoken_emoji_23F0" msgid="8474219588750627870">"នាឡិកា​រោទ៍​"</string>
+    <string name="spoken_emoji_23F0" msgid="8474219588750627870">"នាឡិកា​រោទ៍"</string>
     <string name="spoken_emoji_23F3" msgid="166900119581024371">"កែវ​ពិសោធន៍​មាន​ខ្សាច់ហូរ"</string>
     <string name="spoken_emoji_24C2" msgid="3948348737566038470">"អក្សរ​អឹម​ធំ​ក្នុង​រង្វង់"</string>
     <string name="spoken_emoji_25AA" msgid="7865181015100227349">"ការ៉េ​តូច​​ពណ៌ខ្មៅ"</string>
@@ -195,7 +195,7 @@
     <string name="spoken_emoji_1F312" msgid="4458575672576125401">"ព្រះ​ចន្ទ​មួយ​ចំណិត​ស្ដាំ"</string>
     <string name="spoken_emoji_1F313" msgid="7599181787989497294">"ព្រះ​ចន្ទ​ពាក់​កណ្ដាល"</string>
     <string name="spoken_emoji_1F314" msgid="4898293184964365413">"ព្រះ​ចន្ទ​មួយ​ចំណិត​ឆ្វេង"</string>
-    <string name="spoken_emoji_1F315" msgid="3218117051779496309">"ព្រះចន្ទ​ពេញ​វង់​"</string>
+    <string name="spoken_emoji_1F315" msgid="3218117051779496309">"ព្រះចន្ទ​ពេញ​វង់"</string>
     <string name="spoken_emoji_1F316" msgid="2061317145777689569">"ព្រះ​ចន្ទ​ភ្លឺ​មួយ​ចំហៀង"</string>
     <string name="spoken_emoji_1F317" msgid="2721090687319539049">"ព្រះ​ចន្ទ​ភ្លឺ​ពាក់​កណ្ដាល"</string>
     <string name="spoken_emoji_1F318" msgid="3814091755648887570">"ព្រះ​ចន្ទ​ភ្លឺ​មួយ​ចំណិត​ឆ្វេង"</string>
@@ -262,7 +262,7 @@
     <string name="spoken_emoji_1F365" msgid="4963815540953316307">"នំ​ត្រី​រាង​មូល"</string>
     <string name="spoken_emoji_1F366" msgid="7862401745277049404">"ការ៉េម​​បំពង់"</string>
     <string name="spoken_emoji_1F367" msgid="7447972978281980414">"ការ៉េម​កែវ"</string>
-    <string name="spoken_emoji_1F368" msgid="7790003146142724913">"ការ៉េម​"</string>
+    <string name="spoken_emoji_1F368" msgid="7790003146142724913">"ការ៉េម"</string>
     <string name="spoken_emoji_1F369" msgid="7383712944084857350">"ដូណាត់"</string>
     <string name="spoken_emoji_1F36A" msgid="2726271795913042295">"ខូគី"</string>
     <string name="spoken_emoji_1F36B" msgid="6342163604299875931">"​​សូកូឡា"</string>
@@ -280,7 +280,7 @@
     <string name="spoken_emoji_1F377" msgid="1762398562314172075">"កែវ​ស្រា"</string>
     <string name="spoken_emoji_1F378" msgid="5528234560590117516">"កែវ​ស្រា​ក្រឡុក"</string>
     <string name="spoken_emoji_1F379" msgid="790581290787943325">"ភេសជ្ជៈ​​​ត្រូពិក"</string>
-    <string name="spoken_emoji_1F37A" msgid="391966822450619516">"កែវ​​ស្រាបៀ​"</string>
+    <string name="spoken_emoji_1F37A" msgid="391966822450619516">"កែវ​​ស្រាបៀ"</string>
     <string name="spoken_emoji_1F37B" msgid="9015043286465670662">"ជល់​កែវ​ស្រាបៀ"</string>
     <string name="spoken_emoji_1F37C" msgid="2532113819464508894">"ដប​ទឹកដោះ​គោ"</string>
     <string name="spoken_emoji_1F380" msgid="3487363857092458827">"ខ្សែ​បូ"</string>
@@ -313,7 +313,7 @@
     <string name="spoken_emoji_1F3A7" msgid="837856608794094105">"កាស"</string>
     <string name="spoken_emoji_1F3A8" msgid="2332260356509244587">"ក្ដារ​លាយ​ពណ៌​វិចិត្រករ"</string>
     <string name="spoken_emoji_1F3A9" msgid="9045869366525115256">"មួក​​​សម្ដែង​សិល្បៈ"</string>
-    <string name="spoken_emoji_1F3AA" msgid="5728760354237132">"តង់​សៀក​"</string>
+    <string name="spoken_emoji_1F3AA" msgid="5728760354237132">"តង់​សៀក"</string>
     <string name="spoken_emoji_1F3AB" msgid="1657997517193216284">"សំបុត្រ"</string>
     <string name="spoken_emoji_1F3AC" msgid="4317366554314492152">"បន្ទះកណ្ដឹង"</string>
     <string name="spoken_emoji_1F3AD" msgid="607157286336130470">"សម្ដែង​សិល្បៈ"</string>
@@ -334,10 +334,10 @@
     <string name="spoken_emoji_1F3BC" msgid="1608424748821446230">"និមិត្តសញ្ញា​តន្ត្រី"</string>
     <string name="spoken_emoji_1F3BD" msgid="5490786111375627777">"អាវ​កីឡា​​មាន​ខ្សែ​ឆៀង"</string>
     <string name="spoken_emoji_1F3BE" msgid="1851613105691627931">"រ៉ាកែត និង​បាល់"</string>
-    <string name="spoken_emoji_1F3BF" msgid="6862405997423247921">"ជិះ​ស្គី ​និង​ក្ដារ​​ស្គី​"</string>
+    <string name="spoken_emoji_1F3BF" msgid="6862405997423247921">"ជិះ​ស្គី ​និង​ក្ដារ​​ស្គី"</string>
     <string name="spoken_emoji_1F3C0" msgid="7421420756115104085">"បាល់​បោះ​ និង​វណ្ណ​មូល"</string>
     <string name="spoken_emoji_1F3C1" msgid="6926537251677319922">"ទង់ជាតិ​ប្រណាំង​ម៉ូតូ"</string>
-    <string name="spoken_emoji_1F3C2" msgid="5708596929237987082">"អ្នក​ជិះ​​ក្ដារ​រំអិល​លើ​ព្រិល​"</string>
+    <string name="spoken_emoji_1F3C2" msgid="5708596929237987082">"អ្នក​ជិះ​​ក្ដារ​រំអិល​លើ​ព្រិល"</string>
     <string name="spoken_emoji_1F3C3" msgid="5850982999510115824">"អ្នក​រត់"</string>
     <string name="spoken_emoji_1F3C4" msgid="8468355585994639838">"អ្នក​ជិះ​ទូក​រអិល​លើ​ទឹក"</string>
     <string name="spoken_emoji_1F3C6" msgid="9094474706847545409">"ពាន​រង្វាន់"</string>
@@ -354,7 +354,7 @@
     <string name="spoken_emoji_1F3E6" msgid="342132788513806214">"ធនាគារ"</string>
     <string name="spoken_emoji_1F3E7" msgid="6322352038284944265">"ម៉ាស៊ីន​​អេធីអឹម"</string>
     <string name="spoken_emoji_1F3E8" msgid="5864918444350599907">"សណ្ឋាគារ"</string>
-    <string name="spoken_emoji_1F3E9" msgid="7830416185375326938">"សណ្ឋាគារ​ក្ដី​ស្រឡាញ់​"</string>
+    <string name="spoken_emoji_1F3E9" msgid="7830416185375326938">"សណ្ឋាគារ​ក្ដី​ស្រឡាញ់"</string>
     <string name="spoken_emoji_1F3EA" msgid="5081084413084360479">"ហាង​​ទំនិញ ២៤​ម៉ោង"</string>
     <string name="spoken_emoji_1F3EB" msgid="7010966528205150525">"សាលារៀន"</string>
     <string name="spoken_emoji_1F3EC" msgid="4845978861878295154">"ហាង​​ទំនិញធំៗ"</string>
@@ -439,12 +439,12 @@
     <string name="spoken_emoji_1F44D" msgid="6182553970602667815">"​មេដៃ​ឡើង​លើ"</string>
     <string name="spoken_emoji_1F44E" msgid="8030851867365111809">"​មេដៃ​ចុះ​ក្រោម"</string>
     <string name="spoken_emoji_1F44F" msgid="5148753662268213389">"ទះ​ដៃ"</string>
-    <string name="spoken_emoji_1F450" msgid="1012021072085157054">"លា​ដៃ​"</string>
+    <string name="spoken_emoji_1F450" msgid="1012021072085157054">"លា​ដៃ"</string>
     <string name="spoken_emoji_1F451" msgid="8257466714629051320">"មកុដ"</string>
     <string name="spoken_emoji_1F452" msgid="4567394011149905466">"មួក​​ស្ត្រី"</string>
     <string name="spoken_emoji_1F453" msgid="5978410551173163010">"វ៉ែនតា"</string>
-    <string name="spoken_emoji_1F454" msgid="348469036193323252">"ក្រ​វ៉ាត់​ករ​"</string>
-    <string name="spoken_emoji_1F455" msgid="5665118831861433578">"អាវ​យឺត​​"</string>
+    <string name="spoken_emoji_1F454" msgid="348469036193323252">"ក្រ​វ៉ាត់​ករ"</string>
+    <string name="spoken_emoji_1F455" msgid="5665118831861433578">"អាវ​យឺត"</string>
     <string name="spoken_emoji_1F456" msgid="1890991330923356408">"ខោ​ខោវប៊យ"</string>
     <string name="spoken_emoji_1F457" msgid="3904310482655702620">"សំលៀក​បំពាក់"</string>
     <string name="spoken_emoji_1F458" msgid="5704243858031107692">"គី​ម៉ូណូ"</string>
@@ -463,8 +463,8 @@
     <string name="spoken_emoji_1F465" msgid="4461307702499679879">"គណនី"</string>
     <string name="spoken_emoji_1F466" msgid="1938873085514108889">"ក្មេង​​ប្រុស"</string>
     <string name="spoken_emoji_1F467" msgid="8237080594860144998">"ក្មេង​ស្រី"</string>
-    <string name="spoken_emoji_1F468" msgid="6081300722526675382">"បុរស​"</string>
-    <string name="spoken_emoji_1F469" msgid="1090140923076108158">"ស្ត្រី​"</string>
+    <string name="spoken_emoji_1F468" msgid="6081300722526675382">"បុរស"</string>
+    <string name="spoken_emoji_1F469" msgid="1090140923076108158">"ស្ត្រី"</string>
     <string name="spoken_emoji_1F46A" msgid="5063570981942606595">"គ្រួសារ"</string>
     <string name="spoken_emoji_1F46B" msgid="6795882374287327952">"បុរស​​ និង​ស្ត្រី​កាន់ដៃ​គ្នា"</string>
     <string name="spoken_emoji_1F46C" msgid="6844464165783964495">"បុរស​ពីរ​នាក់​កាន់​ដៃ​គ្នា"</string>
@@ -490,16 +490,16 @@
     <string name="spoken_emoji_1F480" msgid="3696253485164878739">"លលាដ៍​ក្បាល"</string>
     <string name="spoken_emoji_1F481" msgid="320408708521966893">"អ្នក​ផ្ដល់​ព័ត៌មាន"</string>
     <string name="spoken_emoji_1F482" msgid="3424354860245608949">"អ្នក​យាម"</string>
-    <string name="spoken_emoji_1F483" msgid="3221113594843849083">"អ្នក​រាំ​"</string>
+    <string name="spoken_emoji_1F483" msgid="3221113594843849083">"អ្នក​រាំ"</string>
     <string name="spoken_emoji_1F484" msgid="7348014979080444885">"ក្រេម​លាប​បបូរ​មាត់"</string>
     <string name="spoken_emoji_1F485" msgid="6133507975565116339">"ថ្នាំ​លាប​​​ក្រចក"</string>
     <string name="spoken_emoji_1F486" msgid="9085459968247394155">"ម៉ាស្សា​មុខ"</string>
     <string name="spoken_emoji_1F487" msgid="1479113637259592150">"កាត់សក់"</string>
     <string name="spoken_emoji_1F488" msgid="6922559285234100252">"ស្លាក​សញ្ញា​កាត់សក់"</string>
     <string name="spoken_emoji_1F489" msgid="8114863680950147305">"ស៊ីរ៉ាំង"</string>
-    <string name="spoken_emoji_1F48A" msgid="8526843630145963032">"ថ្នាំ​គ្រាប់​"</string>
+    <string name="spoken_emoji_1F48A" msgid="8526843630145963032">"ថ្នាំ​គ្រាប់"</string>
     <string name="spoken_emoji_1F48B" msgid="2538528967897640292">"ស្នាម​ថើប"</string>
-    <string name="spoken_emoji_1F48C" msgid="1681173271652890232">"លិខិត​ស្នេហា​"</string>
+    <string name="spoken_emoji_1F48C" msgid="1681173271652890232">"លិខិត​ស្នេហា"</string>
     <string name="spoken_emoji_1F48D" msgid="8259886164999042373">"រោទ៍"</string>
     <string name="spoken_emoji_1F48E" msgid="8777981696011111101">"ត្បូង​ថ្ម"</string>
     <string name="spoken_emoji_1F48F" msgid="741593675183677907">"ថើប"</string>
@@ -525,7 +525,7 @@
     <string name="spoken_emoji_1F4A3" msgid="6378351742957821735">"គ្រាប់បែក"</string>
     <string name="spoken_emoji_1F4A4" msgid="7217736258870346625">"និមិត្ត​សញ្ញា​​ដេក"</string>
     <string name="spoken_emoji_1F4A5" msgid="5401995723541239858">"និមិត្ត​សញ្ញា​​ប៉ះ​ទង្គិច​គ្នា"</string>
-    <string name="spoken_emoji_1F4A6" msgid="3837802182716483848">"និមិត្ត​សញ្ញា​​ស្រក់​ញើស​"</string>
+    <string name="spoken_emoji_1F4A6" msgid="3837802182716483848">"និមិត្ត​សញ្ញា​​ស្រក់​ញើស"</string>
     <string name="spoken_emoji_1F4A7" msgid="5718438987757885141">"ដំណក់​ទឹក"</string>
     <string name="spoken_emoji_1F4A8" msgid="4472108229720006377">"និមិត្ត​សញ្ញា​​ដកឃ្លា"</string>
     <string name="spoken_emoji_1F4A9" msgid="1240958472788430032">"គំនរ​ធូលី"</string>
@@ -539,7 +539,7 @@
     <string name="spoken_emoji_1F4B1" msgid="8339494003418572905">"ប្ដូរ​​រូបិយប័ណ្ណ"</string>
     <string name="spoken_emoji_1F4B2" msgid="3179159430187243132">"សញ្ញា​ដុល្លារ"</string>
     <string name="spoken_emoji_1F4B3" msgid="5375412518221759596">"កាត​​ឥណទាន"</string>
-    <string name="spoken_emoji_1F4B4" msgid="1068592463669453204">"ក្រដាស​ប្រាក់​​ធនាគារ​មាន​សញ្ញា​​យ៉េន​​"</string>
+    <string name="spoken_emoji_1F4B4" msgid="1068592463669453204">"ក្រដាស​ប្រាក់​​ធនាគារ​មាន​សញ្ញា​​យ៉េន"</string>
     <string name="spoken_emoji_1F4B5" msgid="1426708699891832564">"លុយដុល្លារ"</string>
     <string name="spoken_emoji_1F4B6" msgid="8289249930736444837">"ក្រដាស​ប្រាក់​​ធនាគារ​មាន​សញ្ញា​អឺរ៉ូ"</string>
     <string name="spoken_emoji_1F4B7" msgid="5245100496860739429">"ក្រដាស​ប្រាក់​​ធនាគារ​មាន​សញ្ញា​​​ផោន"</string>
@@ -547,7 +547,7 @@
     <string name="spoken_emoji_1F4B9" msgid="647509393536679903">"ក្រាហ្វិក​និន្នាការ​ឡើង​​មាន​​សញ្ញា​យ៉េន"</string>
     <string name="spoken_emoji_1F4BA" msgid="1269737854891046321">"កៅអី"</string>
     <string name="spoken_emoji_1F4BB" msgid="6252883563347816451">"កុំព្យូទ័រ​ផ្ទាល់ខ្លួន"</string>
-    <string name="spoken_emoji_1F4BC" msgid="6182597732218446206">"វ៉ា​លី​"</string>
+    <string name="spoken_emoji_1F4BC" msgid="6182597732218446206">"វ៉ា​លី"</string>
     <string name="spoken_emoji_1F4BD" msgid="5820961044768829176">"ឌីស​​តូច"</string>
     <string name="spoken_emoji_1F4BE" msgid="4754542485835379808">"ថា​ស​​ទន់"</string>
     <string name="spoken_emoji_1F4BF" msgid="2237481756984721795">"ថាស"</string>
@@ -557,7 +557,7 @@
     <string name="spoken_emoji_1F4C3" msgid="3727274466173970142">"ទំព័រ​​កោង"</string>
     <string name="spoken_emoji_1F4C4" msgid="4382570710795501612">"ទំព័រ​បញ្ឈរ"</string>
     <string name="spoken_emoji_1F4C5" msgid="8693944622627762487">"ប្រតិទិន"</string>
-    <string name="spoken_emoji_1F4C6" msgid="8469908708708424640">"ហែក​ប្រតិទិន​"</string>
+    <string name="spoken_emoji_1F4C6" msgid="8469908708708424640">"ហែក​ប្រតិទិន"</string>
     <string name="spoken_emoji_1F4C7" msgid="2665313547987324495">"​កាត​រៀប​តាម​អក្សរ"</string>
     <string name="spoken_emoji_1F4C8" msgid="8007686702282833600">"ក្រាហ្វិក​មាន​និន្នាការ​ឡើង"</string>
     <string name="spoken_emoji_1F4C9" msgid="2271951411192893684">"ក្រាហ្វិក​មាន​និន្នាការ​ចុះ"</string>
@@ -573,11 +573,11 @@
     <string name="spoken_emoji_1F4D3" msgid="5873386492793610808">"សៀវភៅ"</string>
     <string name="spoken_emoji_1F4D4" msgid="4754469936418776360">"សៀវភៅ​មាន​ក្រប​ពណ៌"</string>
     <string name="spoken_emoji_1F4D5" msgid="4642713351802778905">"សៀវភៅ​​បិទ"</string>
-    <string name="spoken_emoji_1F4D6" msgid="6987347918381807186">"សៀវភៅ​បើក​​"</string>
+    <string name="spoken_emoji_1F4D6" msgid="6987347918381807186">"សៀវភៅ​បើក"</string>
     <string name="spoken_emoji_1F4D7" msgid="7813394163241379223">"សៀវភៅ​​ពណ៌​បៃតង"</string>
     <string name="spoken_emoji_1F4D8" msgid="7189799718984979521">"សៀវភៅ​​ពណ៌​ខៀវ"</string>
     <string name="spoken_emoji_1F4D9" msgid="3874664073186440225">"សៀវភៅ​​ពណ៌​ទឹកក្រូច"</string>
-    <string name="spoken_emoji_1F4DA" msgid="872212072924287762">"សៀវភៅ​"</string>
+    <string name="spoken_emoji_1F4DA" msgid="872212072924287762">"សៀវភៅ"</string>
     <string name="spoken_emoji_1F4DB" msgid="2015183603583392969">"ស្លាកឈ្មោះ"</string>
     <string name="spoken_emoji_1F4DC" msgid="5075845110932456783">"ក្រដាស​រមូរ"</string>
     <string name="spoken_emoji_1F4DD" msgid="2494006707147586786">"កំណត់ចំណាំ"</string>
@@ -589,7 +589,7 @@
     <string name="spoken_emoji_1F4E3" msgid="5588916572878599224">"ឧបករណ៍​បំពង​សំឡេង"</string>
     <string name="spoken_emoji_1F4E4" msgid="2063561529097749707">"ថា​ស​​​ចេញ"</string>
     <string name="spoken_emoji_1F4E5" msgid="3232462702926143576">"ថា​ស​ចូល"</string>
-    <string name="spoken_emoji_1F4E6" msgid="3399454337197561635">"កញ្ចប់​"</string>
+    <string name="spoken_emoji_1F4E6" msgid="3399454337197561635">"កញ្ចប់"</string>
     <string name="spoken_emoji_1F4E7" msgid="5557136988503873238">"និមិត្ត​សញ្ញា​អ៊ីមែល"</string>
     <string name="spoken_emoji_1F4E8" msgid="30698793974124123">"ស្រោម​​សំបុត្រ​ចូល"</string>
     <string name="spoken_emoji_1F4E9" msgid="5947550337678643166">"ស្រោម​សំបុត្រ​​មាន​សញ្ញា​ព្រួញ​ពី​លើ"</string>
@@ -626,7 +626,7 @@
     <string name="spoken_emoji_1F50C" msgid="7793219132036431680">"ដុយ​អគ្គិសនី"</string>
     <string name="spoken_emoji_1F50D" msgid="8140244710637926780">"កែវ​ពង្រីក​ចង្អុល​ខាង​ឆ្វេង"</string>
     <string name="spoken_emoji_1F50E" msgid="4751821352839693365">"កែវ​ពង្រីក​ចង្អុល​ខាង​ស្ដាំ"</string>
-    <string name="spoken_emoji_1F50F" msgid="915079280472199605">"ចាក់សោ​​​ដោយ​ប្រើ​​ប៊ិច​"</string>
+    <string name="spoken_emoji_1F50F" msgid="915079280472199605">"ចាក់សោ​​​ដោយ​ប្រើ​​ប៊ិច"</string>
     <string name="spoken_emoji_1F510" msgid="7658381761691758318">"បិទ​​សោ​ដោយ​ប្រើ​​​​កូនសោ"</string>
     <string name="spoken_emoji_1F511" msgid="262319867774655688">"សោ"</string>
     <string name="spoken_emoji_1F512" msgid="5628688337255115175">"ចាក់សោ"</string>
@@ -645,15 +645,15 @@
     <string name="spoken_emoji_1F51F" msgid="8673370823728653973">"គ្រាប់​ចុច​ ១០"</string>
     <string name="spoken_emoji_1F520" msgid="7335109890337048900">"និមិត្ត​សញ្ញា​បញ្ចូល​សម្រាប់​អក្សរ​ឡាតាំង​ធំ"</string>
     <string name="spoken_emoji_1F521" msgid="2693185864450925778">"និមិត្ត​សញ្ញា​បញ្ចូល​សម្រាប់​អក្សរ​ឡាតាំង​តូច"</string>
-    <string name="spoken_emoji_1F522" msgid="8419130286280673347">"និមិត្ត​សញ្ញា​បញ្ចូល​សម្រាប់​​លេខ​"</string>
+    <string name="spoken_emoji_1F522" msgid="8419130286280673347">"និមិត្ត​សញ្ញា​បញ្ចូល​សម្រាប់​​លេខ"</string>
     <string name="spoken_emoji_1F523" msgid="3318053476401719421">"ការ​បញ្ចូល​និមិត្តសញ្ញា"</string>
     <string name="spoken_emoji_1F524" msgid="1625073997522316331">"និមិត្ត​សញ្ញា​បញ្ចូល​សម្រាប់​អក្សរ​ឡាតាំង"</string>
     <string name="spoken_emoji_1F525" msgid="4083884189172963790">"ភ្លើង"</string>
     <string name="spoken_emoji_1F526" msgid="2035494936742643580">"ពិល​​អគ្គិសនី"</string>
     <string name="spoken_emoji_1F527" msgid="134257142354034271">"ម៉ាឡេត"</string>
     <string name="spoken_emoji_1F528" msgid="700627429570609375">"ញញួរ"</string>
-    <string name="spoken_emoji_1F529" msgid="7480548235904988573">"ឡោ​ស៊ី​​"</string>
-    <string name="spoken_emoji_1F52A" msgid="7613580031502317893">"កាំបិត​​"</string>
+    <string name="spoken_emoji_1F529" msgid="7480548235904988573">"ឡោ​ស៊ី"</string>
+    <string name="spoken_emoji_1F52A" msgid="7613580031502317893">"កាំបិត"</string>
     <string name="spoken_emoji_1F52B" msgid="4554906608328118613">"កាំភ្លើង​ខ្លី"</string>
     <string name="spoken_emoji_1F52C" msgid="1330294501371770790">"មីក្រូទស្សន៍"</string>
     <string name="spoken_emoji_1F52D" msgid="7549551775445177140">"កែវ​យឹត"</string>
@@ -662,7 +662,7 @@
     <string name="spoken_emoji_1F530" msgid="3572898444281774023">"និមិត្តសញ្ញា​ជប៉ុន​សម្រាប់​អ្នក​ចាប់ផ្ដើម"</string>
     <string name="spoken_emoji_1F531" msgid="5225633376450025396">"លំពែង​មុខ​បី"</string>
     <string name="spoken_emoji_1F532" msgid="9169568490485180779">"ប៊ូតុង​ការេ​ពណ៌​ខ្មៅ"</string>
-    <string name="spoken_emoji_1F533" msgid="6554193837201918598">"ប៊ូតុង​ការ៉េ​ពណ៌​ស​"</string>
+    <string name="spoken_emoji_1F533" msgid="6554193837201918598">"ប៊ូតុង​ការ៉េ​ពណ៌​ស"</string>
     <string name="spoken_emoji_1F534" msgid="8339298801331865340">"រង្វង់​ពណ៌​ក្រហម​​​ធំ"</string>
     <string name="spoken_emoji_1F535" msgid="1227403104835533512">"រង្វង់​ពណ៌​ខៀវ​ធំ"</string>
     <string name="spoken_emoji_1F536" msgid="5477372445510469331">"ពេជ្រ​ពណ៌​ទឹកក្រូច​ធំ"</string>
@@ -745,8 +745,8 @@
     <string name="spoken_emoji_1F628" msgid="8875777401624904224">"មុខ​ភ័យ​ខ្លាច"</string>
     <string name="spoken_emoji_1F629" msgid="1411538490319190118">"មុខ​​នឿយហត់"</string>
     <string name="spoken_emoji_1F62A" msgid="4726686726690289969">"មុខ​​ងងុយ​គេង"</string>
-    <string name="spoken_emoji_1F62B" msgid="3221980473921623613">"មុខ​អស់កម្លាំង​​"</string>
-    <string name="spoken_emoji_1F62C" msgid="4616356691941225182">"មុខ​ក្រញេវក្រញូវ​"</string>
+    <string name="spoken_emoji_1F62B" msgid="3221980473921623613">"មុខ​អស់កម្លាំង"</string>
+    <string name="spoken_emoji_1F62C" msgid="4616356691941225182">"មុខ​ក្រញេវក្រញូវ"</string>
     <string name="spoken_emoji_1F62D" msgid="4283677508698812232">"មុខ​យំ​លឺៗ"</string>
     <string name="spoken_emoji_1F62E" msgid="726083405284353894">"មុខ​បើក​មាត់"</string>
     <string name="spoken_emoji_1F62F" msgid="7746620088234710962">"មុខ​ស្ងៀមស្ងាត់"</string>
@@ -784,7 +784,7 @@
     <string name="spoken_emoji_1F683" msgid="8772750354339223092">"ទូរ​​រថភ្លើង"</string>
     <string name="spoken_emoji_1F684" msgid="346396777356203608">"រថភ្លើង​ល្បឿន​លឿន"</string>
     <string name="spoken_emoji_1F685" msgid="1237059817190832730">"រថភ្លើង​ល្បឿន​លឿន​​មាន​ច្រមុះ"</string>
-    <string name="spoken_emoji_1F686" msgid="3525197227223620343">"រថភ្លើង​"</string>
+    <string name="spoken_emoji_1F686" msgid="3525197227223620343">"រថភ្លើង"</string>
     <string name="spoken_emoji_1F687" msgid="5110143437960392837">"មេត្រូ"</string>
     <string name="spoken_emoji_1F688" msgid="4702085029871797965">"រថភ្លើង​ប្រើ​​​ពន្លឺ"</string>
     <string name="spoken_emoji_1F689" msgid="2375851019798817094">"ស្ថានីយ"</string>
@@ -803,7 +803,7 @@
     <string name="spoken_emoji_1F696" msgid="6391604457418285404">"តាក់ស៊ី​ខាង​មុខ"</string>
     <string name="spoken_emoji_1F697" msgid="7978399334396733790">"រថយន្ត"</string>
     <string name="spoken_emoji_1F698" msgid="7006050861129732018">"រថយន្ត​ខាង​មុខ"</string>
-    <string name="spoken_emoji_1F699" msgid="630317052666590607">"រថយន្ត​​​សម្រាប់​កម្សាន្ត​"</string>
+    <string name="spoken_emoji_1F699" msgid="630317052666590607">"រថយន្ត​​​សម្រាប់​កម្សាន្ត"</string>
     <string name="spoken_emoji_1F69A" msgid="4739797891735823577">"រថយន្ត​​ចែក​ចាយ"</string>
     <string name="spoken_emoji_1F69B" msgid="4715997280786620649">"ឡាន​កាមីយ៉ុង"</string>
     <string name="spoken_emoji_1F69C" msgid="5557395610750818161">"ត្រាក់ទ័រ"</string>
@@ -819,7 +819,7 @@
     <string name="spoken_emoji_1F6A6" msgid="485575967773793454">"ភ្លើង​ចរាចរណ៍​បញ្ឈរ"</string>
     <string name="spoken_emoji_1F6A7" msgid="6411048933816976794">"សញ្ញា​​សំណង់"</string>
     <string name="spoken_emoji_1F6A8" msgid="6345717218374788364">"រថយន្ត​​ប៉ូលិស​បើក​សារ៉ែន​វិល"</string>
-    <string name="spoken_emoji_1F6A9" msgid="6586380356807600412">"បង្គោល​ទង់ជាតិ​រាង​ត្រីកោណ​"</string>
+    <string name="spoken_emoji_1F6A9" msgid="6586380356807600412">"បង្គោល​ទង់ជាតិ​រាង​ត្រីកោណ"</string>
     <string name="spoken_emoji_1F6AA" msgid="8954448167261738885">"ទ្វារ"</string>
     <string name="spoken_emoji_1F6AB" msgid="5313946262888343544">"សញ្ញា​ហាម​ចូល"</string>
     <string name="spoken_emoji_1F6AC" msgid="6946858177965948288">"​សញ្ញា​ជក់​បារី"</string>
diff --git a/java/res/values-km-rKH/strings.xml b/java/res/values-km-rKH/strings.xml
index 2078128..2ea86b9 100644
--- a/java/res/values-km-rKH/strings.xml
+++ b/java/res/values-km-rKH/strings.xml
@@ -38,7 +38,7 @@
     <string name="show_language_switch_key_summary" msgid="7343403647474265713">"បង្ហាញ​នៅ​ពេល​ដែល​បើក​ភាសា​បញ្ចូល​ច្រើន"</string>
     <string name="sliding_key_input_preview" msgid="6604262359510068370">"បង្ហាញ​ទ្រនិច​បង្ហាញ​ស្លាយ"</string>
     <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"បង្ហាញ​​សញ្ញា​មើល​​ឃើញ​ខណៈ​ពេល​ដែល​រុញ​ពី​ឆ្វេង ឬ​​គ្រាប់​ចុច​​និមិត្ត​សញ្ញា"</string>
-    <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"​សោ​លេចឡើង​បោះបង់​ការ​​ពន្យារពេល​"</string>
+    <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"​សោ​លេចឡើង​បោះបង់​ការ​​ពន្យារពេល"</string>
     <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>
@@ -49,7 +49,7 @@
     <string name="enable_metrics_logging" msgid="5506372337118822837">"ធ្វើឲ្យ <xliff:g id="APPLICATION_NAME">%s</xliff:g> ប្រសើរ​ឡើង"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"រយៈ​ពេល​ចុច​ដកឃ្លា​ពីរដង"</string>
     <string name="use_double_space_period_summary" msgid="6532892187247952799">"ប៉ះ​ដកឃ្លា​ពីរ​​ដង​បញ្ចូល​​​រយៈ​ពេល​ដែល​អនុវត្ត​តាម​ដកឃ្លា"</string>
-    <string name="auto_cap" msgid="1719746674854628252">"ការ​សរសេរ​ជា​អក្សរ​ធំ​​ស្វ័យប្រវត្តិ​"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"ការ​សរសេរ​ជា​អក្សរ​ធំ​​ស្វ័យប្រវត្តិ"</string>
     <string name="auto_cap_summary" msgid="7934452761022946874">"សរសេរ​ពាក្យ​ដំបូង​​​ជា​អក្សរ​ធំ​​នៃ​ប្រយោគ​នីមួយ​ៗ"</string>
     <string name="edit_personal_dictionary" msgid="3996910038952940420">"វចនានុក្រម​ផ្ទាល់ខ្លួន"</string>
     <string name="configure_dictionaries_title" msgid="4238652338556902049">"ផ្នែក​បន្ថែម​វចនានុក្រម"</string>
@@ -57,7 +57,7 @@
     <string name="prefs_show_suggestions" msgid="8026799663445531637">"បង្ហាញ​ការ​ស្នើ​​កែ"</string>
     <string name="prefs_show_suggestions_summary" msgid="1583132279498502825">"បង្ហាញ​ពាក្យ​​បាន​​ផ្ដល់​​ស្នើ​​ខណៈ​ពេល​​​វាយ​បញ្ចូល"</string>
     <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"ទប់ស្កាត់​​ពាក្យ​​បំពាន"</string>
-    <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"កុំ​ស្នើ​ឲ្យ​ពាក្យ​បំពាន​មាន​សក្ដានុពល​"</string>
+    <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"កុំ​ស្នើ​ឲ្យ​ពាក្យ​បំពាន​មាន​សក្ដានុពល"</string>
     <string name="auto_correction" msgid="7630720885194996950">"ការ​កែ​​​ស្វ័យប្រវត្តិ"</string>
     <string name="auto_correction_summary" msgid="5625751551134658006">"ចន្លោះ​មិន​ឃើញ ​និង​សញ្ញា​​វណ្ណយុត្ត​កែ​ពាក្យ​ដែល​បាន​វាយ​ខុស​ស្វ័យប្រវត្តិ"</string>
     <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"បិទ"</string>
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"គ្មាន​វិធីសាស្ត្រ​បញ្ចូល​សំឡេង​បាន​បើក។ ពិនិត្យ​មើល​ការ​កំណត់​ភាសា &amp; ការ​បញ្ចូល។"</string>
     <string name="configure_input_method" msgid="373356270290742459">"កំណត់​រចនាសម្ព័ន្ធ​វិធីសាស្ត្រ​បញ្ចូល"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"បញ្ចូល​ភាសា"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"ជំនួយ &amp; មតិ​ត្រឡប់"</string>
     <string name="select_language" msgid="3693815588777926848">"​​បញ្ចូល​ភាសា"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"ប៉ះ​ម្ដង​ទៀត​ ដើម្បី​រក្សា​ទុក"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"មាន​វចនានុក្រម"</string>
@@ -116,7 +115,7 @@
     <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"ថិរវេលា​​ញ័រ​​ពេល​ចុច​គ្រាប់ចុច"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"កម្រិត​សំឡេង​ពេល​ចុច​គ្រាប់​ចុច"</string>
     <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"អាន​ឯកសារ​វចនានុក្រម​ខាង​ក្រៅ"</string>
-    <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"គ្មាន​ឯកសារ​វចនានុក្រម​នៅ​ក្នុង​ថត​ទាញ​យក​​"</string>
+    <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"គ្មាន​ឯកសារ​វចនានុក្រម​នៅ​ក្នុង​ថត​ទាញ​យក"</string>
     <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"ជ្រើស​ឯកសារ​វចនានុក្រម​ ដើម្បី​ដំឡើង"</string>
     <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"ពិត​ជា​ដំឡើង​ឯកសារ​នេះ​សម្រាប់ <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string>
     <string name="error" msgid="8940763624668513648">"មាន​កំហុស"</string>
@@ -143,7 +142,7 @@
     <string name="dictionary_provider_name" msgid="3027315045397363079">"កម្មវិធី​ផ្ដល់​វចនានុក្រម"</string>
     <string name="dictionary_service_name" msgid="6237472350693511448">"សេវាកម្ម​​វចនានុក្រម"</string>
     <string name="download_description" msgid="6014835283119198591">"ព័ត៌មាន​បច្ចុប្បន្នភាព​វចនានុក្រម"</string>
-    <string name="dictionary_settings_title" msgid="8091417676045693313">"ផ្នែក​បន្ថែម​វចនានុក្រម​​"</string>
+    <string name="dictionary_settings_title" msgid="8091417676045693313">"ផ្នែក​បន្ថែម​វចនានុក្រម"</string>
     <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"វចនានុក្រម​​​​​អាច​ប្រើ​បាន"</string>
     <string name="dictionary_settings_summary" msgid="5305694987799824349">"ការ​កំណត់​សម្រាប់​វចនានុក្រម"</string>
     <string name="user_dictionaries" msgid="3582332055892252845">"វចនានុក្រម​​​អ្នក​ប្រើ"</string>
@@ -159,10 +158,10 @@
     <string name="message_updating" msgid="4457761393932375219">"ពិនិត្យមើល​បច្ចុប្បន្នភាព"</string>
     <string name="message_loading" msgid="5638680861387748936">"កំពុង​ផ្ទុក..."</string>
     <string name="main_dict_description" msgid="3072821352793492143">"វចនានុក្រម​ចម្បង"</string>
-    <string name="cancel" msgid="6830980399865683324">"បោះ​បង់​"</string>
+    <string name="cancel" msgid="6830980399865683324">"បោះ​បង់"</string>
     <string name="go_to_settings" msgid="3876892339342569259">"ការ​កំណត់"</string>
     <string name="install_dict" msgid="180852772562189365">"ដំឡើង"</string>
-    <string name="cancel_download_dict" msgid="7843340278507019303">"បោះ​បង់​"</string>
+    <string name="cancel_download_dict" msgid="7843340278507019303">"បោះ​បង់"</string>
     <string name="delete_dict" msgid="756853268088330054">"លុប"</string>
     <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"ភាសា​ដែល​បាន​ជ្រើស​នៅ​លើ​ឧបករណ៍​ចល័ត​មាន​វចនានុក្រម​អាច​ប្រើ​បាន។&lt;br/&gt; យើង​ផ្ដល់​អនុសាសន៍​ឲ្យ &lt;b&gt;ទាញ​យក&lt;/b&gt; វចនានុក្រម​ភាសា <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ដើម្បី​បង្កើន​បទពិសោធន៍​វាយ​បញ្ចូល​របស់​អ្នក។&lt;br/&gt; &lt;br/&gt; ការ​ទាញ​យក​អាច​ចំណាយ​ពេល​ប្រហែល​ពីរ​នាទី​នៅ​តាម 3G។ ការ​គិត​ថ្លៃ​អាច​អនុវត្ត​ប្រសិន​បើ​អ្នក​មិន​ប្រើ &lt;b&gt;ផែនការ​ទិន្នន័យ​គ្មាន​ដែន​កំណត់&lt;/b&gt;.&lt;br/&gt; បើ​អ្នក​មិន​ប្រាកដ​​ថា​ផែនការ​ណា​មួយ​ដែល​អ្នក​មាន យើង​ផ្ដល់​អនុសាសន៍​ឲ្យ​​ភ្ជាប់​វ៉ាយហ្វាយ ដើម្បី​ចាប់ផ្ដើម​ទាញ​យក​ដោយ​ស្វ័យ​ប្រវត្តិ។&lt;br/&gt; &lt;br/&gt; ជំនួយ៖ អ្នក​អាច​ទាញ​យក និង​លុប​វចនានុក្រម​ដោយ​ចូល​ទៅ​ &lt;b&gt;ភាសា &amp; ការ​បញ្ចូល&lt;/b&gt; នៅ​ក្នុង​ម៉ឺនុយ &lt;b&gt;ការ​កំណត់&lt;/b&gt; សម្រាប់​ឧបករណ៍​ចល័ត។"</string>
     <string name="download_over_metered" msgid="1643065851159409546">"ទាញ​យក​ឥឡូវ​នេះ (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> មេកាបៃ)"</string>
@@ -180,7 +179,7 @@
     <string name="user_dict_settings_add_word_option_name" msgid="6665558053408962865">"ពាក្យ៖"</string>
     <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"ផ្លូវកាត់​៖"</string>
     <string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"ភាសា៖"</string>
-    <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"វាយ​បញ្ចូល​ពាក្យ​"</string>
+    <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"វាយ​បញ្ចូល​ពាក្យ"</string>
     <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"ផ្លូវកាត់​ជា​ជម្រើស"</string>
     <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"កែ​ពាក្យ"</string>
     <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"កែ"</string>
diff --git a/java/res/values-kn-rIN/strings.xml b/java/res/values-kn-rIN/strings.xml
index 92c39f3..4fcf06f 100644
--- a/java/res/values-kn-rIN/strings.xml
+++ b/java/res/values-kn-rIN/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"ಯಾವುದೇ ಧ್ವನಿ ಇನ್‌ಪುಟ್ ವಿಧಾನಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿಲ್ಲ. ಭಾಷೆ &amp; ಇನ್‌ಪುಟ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ."</string>
     <string name="configure_input_method" msgid="373356270290742459">"ಇನ್‌ಪುಟ್ ವಿಧಾನಗಳನ್ನು ಕಾನ್ಫಿಗರ್ ಮಾಡಿ"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"ಇನ್‌ಪುಟ್ ಭಾಷೆಗಳು"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"ಸಹಾಯ &amp; ಪ್ರತಿಕ್ರಿಯೆ"</string>
     <string name="select_language" msgid="3693815588777926848">"ಇನ್‌ಪುಟ್ ಭಾಷೆಗಳು"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"ಉಳಿಸಲು ಮತ್ತೆ ಸ್ಪರ್ಶಿಸಿ"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"ನಿಘಂಟು ಲಭ್ಯವಿದೆ"</string>
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
index 29d7aa7..73f8f86 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"사용 설정된 음성 입력 방법이 없습니다. 언어 및 입력 설정을 확인하세요."</string>
     <string name="configure_input_method" msgid="373356270290742459">"입력 방법 설정"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"입력 언어"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"도움말 및 의견"</string>
     <string name="select_language" msgid="3693815588777926848">"입력 언어"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"저장하려면 다시 터치"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"사전 사용 가능"</string>
diff --git a/java/res/values-ky-rKG/strings.xml b/java/res/values-ky-rKG/strings.xml
index 7054e3f..ad8317d 100644
--- a/java/res/values-ky-rKG/strings.xml
+++ b/java/res/values-ky-rKG/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Үн менен киргизүү ыкмаларынын бири да иштетилген эмес. Тил &amp; киргизүү жөндөөлөрүн текшериңиз."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Дайндрд киргзүү ыкмалрн конфигрцлоо"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Киргизүү тилдери"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Жардам &amp; жооп пикир"</string>
     <string name="select_language" msgid="3693815588777926848">"Киргизүү тилдери"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Сактоо үчүн кайра тийип коюңуз"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Сөздүк бар"</string>
diff --git a/java/res/values-lo-rLA/strings-emoji-descriptions.xml b/java/res/values-lo-rLA/strings-emoji-descriptions.xml
index 0747fa6..83a702e 100644
--- a/java/res/values-lo-rLA/strings-emoji-descriptions.xml
+++ b/java/res/values-lo-rLA/strings-emoji-descriptions.xml
@@ -210,7 +210,7 @@
     <string name="spoken_emoji_1F330" msgid="3115760035618051575">"​ລູກ​ເກົາ​ລັດ"</string>
     <string name="spoken_emoji_1F331" msgid="5658888205290008691">"​ກ້າ​ໄມ້"</string>
     <string name="spoken_emoji_1F332" msgid="2935650450421165938">"ຕົ້ນ​ໄມ້​ບໍ່​ຜັດ​ໃບ"</string>
-    <string name="spoken_emoji_1F333" msgid="5898847427062482675">"​ຕົ້ນ​ໄມ້​ຜັດໃບ​"</string>
+    <string name="spoken_emoji_1F333" msgid="5898847427062482675">"​ຕົ້ນ​ໄມ້​ຜັດໃບ"</string>
     <string name="spoken_emoji_1F334" msgid="6183375224678417894">"​ຕົ້ນ​ປາມ"</string>
     <string name="spoken_emoji_1F335" msgid="5352418412103584941">"​ກະ​ບອງ​ເພັດ"</string>
     <string name="spoken_emoji_1F337" msgid="3839107352363566289">"​ທິວ​ລິບ"</string>
@@ -450,7 +450,7 @@
     <string name="spoken_emoji_1F458" msgid="5704243858031107692">"​ກິ​ໂມ​ໂນ"</string>
     <string name="spoken_emoji_1F459" msgid="3553148747050035251">"​ບິ​ກີ​ນີ"</string>
     <string name="spoken_emoji_1F45A" msgid="1389654639484716101">"​ເສື້ອ​ຜ້າ​ຜູ່​ຍິງ"</string>
-    <string name="spoken_emoji_1F45B" msgid="1113293170254222904">"ກະ​ເປົາ​"</string>
+    <string name="spoken_emoji_1F45B" msgid="1113293170254222904">"ກະ​ເປົາ"</string>
     <string name="spoken_emoji_1F45C" msgid="3410257778598006936">"ກະ​ເປົາ"</string>
     <string name="spoken_emoji_1F45D" msgid="812176504300064819">"​ກະ​ເປົາ"</string>
     <string name="spoken_emoji_1F45E" msgid="2901741399934723562">"​ເກີບ​ຜູ່​ຊາຍ"</string>
diff --git a/java/res/values-lo-rLA/strings-letter-descriptions.xml b/java/res/values-lo-rLA/strings-letter-descriptions.xml
index ecc0b7a..47f7cbc 100644
--- a/java/res/values-lo-rLA/strings-letter-descriptions.xml
+++ b/java/res/values-lo-rLA/strings-letter-descriptions.xml
@@ -186,7 +186,7 @@
     <string name="spoken_symbol_2019" msgid="8892530161598134083">"Right single quotation mark"</string>
     <string name="spoken_symbol_201A" msgid="2072987157683446644">"Single low-9 quotation mark"</string>
     <string name="spoken_symbol_201C" msgid="4588048378803665427">"​ເຄື່ອງ​ໝາຍ​ວົງ​ຢືມ​ຊ້າຍ"</string>
-    <string name="spoken_symbol_201D" msgid="1642776849495925895">"​ເຄື່ອງ​ໝາຍ​ວົງ​ຢືມ​ຂວາ​"</string>
+    <string name="spoken_symbol_201D" msgid="1642776849495925895">"​ເຄື່ອງ​ໝາຍ​ວົງ​ຢືມ​ຂວາ"</string>
     <string name="spoken_symbol_2020" msgid="9084628638189344431">"Dagger"</string>
     <string name="spoken_symbol_2021" msgid="5081396468559426475">"Double dagger"</string>
     <string name="spoken_symbol_2030" msgid="9068837172419431755">"​ເຄື່ອງ​ໝາຍ​ຕໍ່​ໄມລ໌"</string>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
index 218300e..5878982 100644
--- a/java/res/values-lv/strings.xml
+++ b/java/res/values-lv/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nav iespējota neviena balss ievades metode. Pārbaudiet valodas un ievades iestatījumus."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Ievades metožu konfigurēšana"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Ievades valodas"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Palīdzība un atsauksmes"</string>
     <string name="select_language" msgid="3693815588777926848">"Ievades valodas"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Pieskarieties vēlreiz, lai saglabātu."</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Ir pieejama vārdnīca."</string>
diff --git a/java/res/values-mk-rMK/strings.xml b/java/res/values-mk-rMK/strings.xml
index dd10f07..3c6d872 100644
--- a/java/res/values-mk-rMK/strings.xml
+++ b/java/res/values-mk-rMK/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Не се овозможени методи за гласовно внесување. Проверете ги поставките за Јазик и внесување."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Конфигурирај методи на влез"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Влезни јазици"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Помош и повратни информации"</string>
     <string name="select_language" msgid="3693815588777926848">"Влезни јазици"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Допрете повторно за да се зачува"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Речникот е достапен"</string>
diff --git a/java/res/values-ml-rIN/strings.xml b/java/res/values-ml-rIN/strings.xml
index 69d56bd..5826eab 100644
--- a/java/res/values-ml-rIN/strings.xml
+++ b/java/res/values-ml-rIN/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"വോയ്‌സ് ടൈപ്പുചെയ്യൽ രീതികളൊന്നും പ്രവർത്തനക്ഷമമല്ല. ഭാഷ &amp; ടൈപ്പു ചെയ്യൽ ക്രമീകരണങ്ങൾ പരിശോധിക്കുക."</string>
     <string name="configure_input_method" msgid="373356270290742459">"ടൈപ്പുചെയ്യൽ രീതികൾ കോൺഫിഗർ ചെയ്യുക"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"ടൈപ്പുചെയ്യൽ ഭാഷകൾ"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"സഹായവും ഫീഡ്‌ബാക്കും"</string>
     <string name="select_language" msgid="3693815588777926848">"ടൈപ്പുചെയ്യൽ ഭാഷകൾ"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"സംരക്ഷിക്കുന്നതിനായി വീണ്ടും സ്‌പർശിക്കുക"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"നിഘണ്ടു ലഭ്യമാണ്"</string>
diff --git a/java/res/values-mr-rIN/strings.xml b/java/res/values-mr-rIN/strings.xml
index 9323c71..677438c 100644
--- a/java/res/values-mr-rIN/strings.xml
+++ b/java/res/values-mr-rIN/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"व्हॉइस इनपुट पद्धती सक्षम केल्या नाहीत. भाषा आणि इनपुट सेटिंग्ज तपासा."</string>
     <string name="configure_input_method" msgid="373356270290742459">"इनपुट पद्धती कॉन्फिगर करा"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"इनपुट भाषा"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"मदत आणि अभिप्राय"</string>
     <string name="select_language" msgid="3693815588777926848">"इनपुट भाषा"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"जतन करण्यासाठी पुन्हा स्पर्श करा"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"शब्दकोश उपलब्ध"</string>
diff --git a/java/res/values-ms-rMY/strings.xml b/java/res/values-ms-rMY/strings.xml
index 78cdd0d..758ff10 100644
--- a/java/res/values-ms-rMY/strings.xml
+++ b/java/res/values-ms-rMY/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Tiada kaedah input suara didayakan. Semak Bahasa &amp; tetapan input."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurasikan kaedah input"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Bahasa input"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Bantuan &amp; m/balas"</string>
     <string name="select_language" msgid="3693815588777926848">"Bahasa input"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Sentuh lagi untuk menyimpan"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Kamus tersedia"</string>
diff --git a/java/res/values-my-rMM/strings-action-keys.xml b/java/res/values-my-rMM/strings-action-keys.xml
index d15c9e5..f7a2ca9 100644
--- a/java/res/values-my-rMM/strings-action-keys.xml
+++ b/java/res/values-my-rMM/strings-action-keys.xml
@@ -27,5 +27,5 @@
     <string name="label_send_key" msgid="482252074224462163">"ပို့ရန်"</string>
     <string name="label_search_key" msgid="7965186050435796642">"ရှာဖွေရန်"</string>
     <string name="label_pause_key" msgid="2225922926459730642">"ဆိုင်းငံ့ရန်"</string>
-    <string name="label_wait_key" msgid="5891247853595466039">"စောင့်ဆိုင်းရန်"</string>
+    <string name="label_wait_key" msgid="5891247853595466039">"စောင့်ဆိုင်းရန်"</string>
 </resources>
diff --git a/java/res/values-my-rMM/strings-letter-descriptions.xml b/java/res/values-my-rMM/strings-letter-descriptions.xml
index 6dabe0f..e926c70 100644
--- a/java/res/values-my-rMM/strings-letter-descriptions.xml
+++ b/java/res/values-my-rMM/strings-letter-descriptions.xml
@@ -29,7 +29,7 @@
     <string name="spoken_accented_letter_00AA" msgid="4374325261868451570">"ဣထိလိင် အစဉ်ပြ အညွှန်း"</string>
     <string name="spoken_accented_letter_00B5" msgid="9031387673828823891">"မိုက်ခရို သင်္ကေတ"</string>
     <string name="spoken_accented_letter_00BA" msgid="5045198452071207437">"ပုလိင် အစဉ်ပြ အညွှန်း"</string>
-    <string name="spoken_accented_letter_00DF" msgid="2260098367028134281">"ပြတ်သားသည့် S"</string>
+    <string name="spoken_accented_letter_00DF" msgid="2260098367028134281">"ပြတ်သားသည့် S"</string>
     <string name="spoken_accented_letter_00E0" msgid="2234515772182387086">"A၊ တည်ငြိမ်သော"</string>
     <string name="spoken_accented_letter_00E1" msgid="7780174500802535063">"A၊ စူးရှသော"</string>
     <string name="spoken_accented_letter_00E2" msgid="7054108480488102631">"A၊ သရသံသင်္ကေတ"</string>
@@ -133,45 +133,45 @@
     <string name="spoken_accented_letter_0259" msgid="2464085263158415898">"Schwa"</string>
     <string name="spoken_accented_letter_1EA1" msgid="688124877202887630">"A၊ အောက်မှာ အစက်"</string>
     <string name="spoken_accented_letter_1EA3" msgid="327960130366386256">"A အပေါ်မှာ ချိတ်"</string>
-    <string name="spoken_accented_letter_1EA5" msgid="637406363453769610">"A၊ သရသံသင်္ကေတ နှင့် စူးရှသော"</string>
-    <string name="spoken_accented_letter_1EA7" msgid="1419591804181615409">"A၊ သရသံသင်္ကေတ နှင့် တည်ငြိမ်သော"</string>
-    <string name="spoken_accented_letter_1EA9" msgid="6068887382734896756">"A၊ သရသံသင်္ကေတ နှင့် အပေါ်မှာ ချိတ်"</string>
-    <string name="spoken_accented_letter_1EAB" msgid="7236523151662538333">"A၊ သရသံသင်္ကေတ နှင့် tilde"</string>
-    <string name="spoken_accented_letter_1EAD" msgid="2363364864106332076">"A,၊ သရသံသင်္ကေတ နှင့် အောက်မှာ အစက်"</string>
-    <string name="spoken_accented_letter_1EAF" msgid="1576329511464272935">"A၊ တည်ငြိမ်သော နှင့် စူးရှသော"</string>
-    <string name="spoken_accented_letter_1EB1" msgid="4634735072816076592">"A၊ breve နှင့် တည်ငြိမ်သော"</string>
-    <string name="spoken_accented_letter_1EB3" msgid="2325245849038771534">"A၊ breve နှင့် အပေါ်မှာ ချိတ်"</string>
-    <string name="spoken_accented_letter_1EB5" msgid="3720427596242746295">"A၊ breve နှင့် tilde"</string>
-    <string name="spoken_accented_letter_1EB7" msgid="700415535653646695">"A၊ breve နှင့် အောက်မှာ အစက်"</string>
+    <string name="spoken_accented_letter_1EA5" msgid="637406363453769610">"A၊ သရသံသင်္ကေတ နှင့် စူးရှသော"</string>
+    <string name="spoken_accented_letter_1EA7" msgid="1419591804181615409">"A၊ သရသံသင်္ကေတ နှင့် တည်ငြိမ်သော"</string>
+    <string name="spoken_accented_letter_1EA9" msgid="6068887382734896756">"A၊ သရသံသင်္ကေတ နှင့် အပေါ်မှာ ချိတ်"</string>
+    <string name="spoken_accented_letter_1EAB" msgid="7236523151662538333">"A၊ သရသံသင်္ကေတ နှင့် tilde"</string>
+    <string name="spoken_accented_letter_1EAD" msgid="2363364864106332076">"A,၊ သရသံသင်္ကေတ နှင့် အောက်မှာ အစက်"</string>
+    <string name="spoken_accented_letter_1EAF" msgid="1576329511464272935">"A၊ တည်ငြိမ်သော နှင့် စူးရှသော"</string>
+    <string name="spoken_accented_letter_1EB1" msgid="4634735072816076592">"A၊ breve နှင့် တည်ငြိမ်သော"</string>
+    <string name="spoken_accented_letter_1EB3" msgid="2325245849038771534">"A၊ breve နှင့် အပေါ်မှာ ချိတ်"</string>
+    <string name="spoken_accented_letter_1EB5" msgid="3720427596242746295">"A၊ breve နှင့် tilde"</string>
+    <string name="spoken_accented_letter_1EB7" msgid="700415535653646695">"A၊ breve နှင့် အောက်မှာ အစက်"</string>
     <string name="spoken_accented_letter_1EB9" msgid="3901338692305890487">"E၊ အောက်မှာ အစက်"</string>
     <string name="spoken_accented_letter_1EBB" msgid="4028688699415417302">"E၊ အပေါ်မှာ ချိတ်"</string>
     <string name="spoken_accented_letter_1EBD" msgid="181253633045931897">"E၊ tilde"</string>
-    <string name="spoken_accented_letter_1EBF" msgid="3309618845007944963">"E၊ သရသံသင်္ကေတ နှင့် စူးရှသော"</string>
-    <string name="spoken_accented_letter_1EC1" msgid="8139046749226332542">"E၊ သရသံသင်္ကေတ နှင့် တည်ငြိမ်သော"</string>
-    <string name="spoken_accented_letter_1EC3" msgid="3239674223053133383">"E၊ သရသံသင်္ကေတ နှင့် ချိတ် အပေါ်မှာ"</string>
-    <string name="spoken_accented_letter_1EC5" msgid="2216559244705714587">"E၊ သရသံသင်္ကေတ နှင့် tilde"</string>
-    <string name="spoken_accented_letter_1EC7" msgid="9012731468253986792">"E၊ သရသံသင်္ကေတ နှင့် အောက်မှာ အစက်"</string>
+    <string name="spoken_accented_letter_1EBF" msgid="3309618845007944963">"E၊ သရသံသင်္ကေတ နှင့် စူးရှသော"</string>
+    <string name="spoken_accented_letter_1EC1" msgid="8139046749226332542">"E၊ သရသံသင်္ကေတ နှင့် တည်ငြိမ်သော"</string>
+    <string name="spoken_accented_letter_1EC3" msgid="3239674223053133383">"E၊ သရသံသင်္ကေတ နှင့် ချိတ် အပေါ်မှာ"</string>
+    <string name="spoken_accented_letter_1EC5" msgid="2216559244705714587">"E၊ သရသံသင်္ကေတ နှင့် tilde"</string>
+    <string name="spoken_accented_letter_1EC7" msgid="9012731468253986792">"E၊ သရသံသင်္ကေတ နှင့် အောက်မှာ အစက်"</string>
     <string name="spoken_accented_letter_1EC9" msgid="2901917620195717034">"I၊ အပေါ်မှာ ချိတ်"</string>
     <string name="spoken_accented_letter_1ECB" msgid="5470387489820034621">"I၊ အောက်မှာ အစက်"</string>
     <string name="spoken_accented_letter_1ECD" msgid="1340122876914839806">"O၊ အောက်မှာ အစက်"</string>
     <string name="spoken_accented_letter_1ECF" msgid="2326921263882559755">"O၊ အပေါ်မှာ ချိတ်"</string>
-    <string name="spoken_accented_letter_1ED1" msgid="2885683296042774958">"O၊ သရသံသင်္ကေတ နှင့် စူးရှသော"</string>
-    <string name="spoken_accented_letter_1ED3" msgid="6857664926477376178">"O၊ သရသံသင်္ကေတ နှင့် တည်ငြိမ်သော"</string>
-    <string name="spoken_accented_letter_1ED5" msgid="2015209467290624062">"O၊ သရသံသင်္ကေတ နှင့် အပေါ်မှာ ချိတ်"</string>
-    <string name="spoken_accented_letter_1ED7" msgid="7924481354960306389">"O၊ သရသံသင်္ကေတ နှင့် tilde"</string>
-    <string name="spoken_accented_letter_1ED9" msgid="7023315590332365554">"O၊ သရသံသင်္ကေတ နှင့် အောက်မှာ အစက်"</string>
-    <string name="spoken_accented_letter_1EDB" msgid="2379438944917634496">"O၊ horn နှင့် စူးရှသော"</string>
-    <string name="spoken_accented_letter_1EDD" msgid="8107077534204404085">"O၊ horn နှင့် တည်ငြိမ်သော"</string>
-    <string name="spoken_accented_letter_1EDF" msgid="1846880105528347966">"O၊ horn နှင့် အပေါ်မှာ ချိတ်"</string>
-    <string name="spoken_accented_letter_1EE1" msgid="1520037313389776718">"O၊ horn နှင့် tilde"</string>
-    <string name="spoken_accented_letter_1EE3" msgid="907964027171008963">"O၊ horn နှင့် အောက်မှာ အစက်"</string>
+    <string name="spoken_accented_letter_1ED1" msgid="2885683296042774958">"O၊ သရသံသင်္ကေတ နှင့် စူးရှသော"</string>
+    <string name="spoken_accented_letter_1ED3" msgid="6857664926477376178">"O၊ သရသံသင်္ကေတ နှင့် တည်ငြိမ်သော"</string>
+    <string name="spoken_accented_letter_1ED5" msgid="2015209467290624062">"O၊ သရသံသင်္ကေတ နှင့် အပေါ်မှာ ချိတ်"</string>
+    <string name="spoken_accented_letter_1ED7" msgid="7924481354960306389">"O၊ သရသံသင်္ကေတ နှင့် tilde"</string>
+    <string name="spoken_accented_letter_1ED9" msgid="7023315590332365554">"O၊ သရသံသင်္ကေတ နှင့် အောက်မှာ အစက်"</string>
+    <string name="spoken_accented_letter_1EDB" msgid="2379438944917634496">"O၊ horn နှင့် စူးရှသော"</string>
+    <string name="spoken_accented_letter_1EDD" msgid="8107077534204404085">"O၊ horn နှင့် တည်ငြိမ်သော"</string>
+    <string name="spoken_accented_letter_1EDF" msgid="1846880105528347966">"O၊ horn နှင့် အပေါ်မှာ ချိတ်"</string>
+    <string name="spoken_accented_letter_1EE1" msgid="1520037313389776718">"O၊ horn နှင့် tilde"</string>
+    <string name="spoken_accented_letter_1EE3" msgid="907964027171008963">"O၊ horn နှင့် အောက်မှာ အစက်"</string>
     <string name="spoken_accented_letter_1EE5" msgid="1522024630360038700">"U၊ အောက်မှာ အစက်"</string>
     <string name="spoken_accented_letter_1EE7" msgid="7815412228302952637">"U၊ အပေါ်မှာ ချိတ်"</string>
-    <string name="spoken_accented_letter_1EE9" msgid="4219119671251485651">"U၊ horn နှင့် စူးရှသော"</string>
-    <string name="spoken_accented_letter_1EEB" msgid="4086009841269002231">"U၊ horn နှင့် တည်ငြိမ်သော"</string>
-    <string name="spoken_accented_letter_1EED" msgid="3528151733528719847">"U၊  horn နှင့် အပေါ်မှာ ချိတ်"</string>
-    <string name="spoken_accented_letter_1EEF" msgid="3508548229409072119">"U၊ horn နှင့် tilde"</string>
-    <string name="spoken_accented_letter_1EF1" msgid="1912816350401931115">"U၊ horn နှင့် အောက်မှာ အစက်"</string>
+    <string name="spoken_accented_letter_1EE9" msgid="4219119671251485651">"U၊ horn နှင့် စူးရှသော"</string>
+    <string name="spoken_accented_letter_1EEB" msgid="4086009841269002231">"U၊ horn နှင့် တည်ငြိမ်သော"</string>
+    <string name="spoken_accented_letter_1EED" msgid="3528151733528719847">"U၊  horn နှင့် အပေါ်မှာ ချိတ်"</string>
+    <string name="spoken_accented_letter_1EEF" msgid="3508548229409072119">"U၊ horn နှင့် tilde"</string>
+    <string name="spoken_accented_letter_1EF1" msgid="1912816350401931115">"U၊ horn နှင့် အောက်မှာ အစက်"</string>
     <string name="spoken_accented_letter_1EF3" msgid="7211760439435946494">"Y၊ တည်ငြိမ်သော"</string>
     <string name="spoken_accented_letter_1EF5" msgid="8998864482764007384">"Y၊ အောက်မှာ အစက်"</string>
     <string name="spoken_accented_letter_1EF7" msgid="922043627252869200">"Y၊ အပေါ်မှာ ချိတ်"</string>
diff --git a/java/res/values-my-rMM/strings.xml b/java/res/values-my-rMM/strings.xml
index 37d99d6..6862124 100644
--- a/java/res/values-my-rMM/strings.xml
+++ b/java/res/values-my-rMM/strings.xml
@@ -31,7 +31,7 @@
     <string name="settings_screen_multi_lingual" msgid="6829970893413937235">"ဘာသာများစွာ ရွေးချယ်မှု"</string>
     <string name="settings_screen_gesture" msgid="9113437621722871665">"အမူယာစာရိုက်ခြင်း စိတ်ကြိုက်များ"</string>
     <string name="settings_screen_correction" msgid="1616818407747682955">"စာအမှားပြပြင်ခြင်း"</string>
-    <string name="settings_screen_advanced" msgid="7472408607625972994">"အဆင့်မြင့်"</string>
+    <string name="settings_screen_advanced" msgid="7472408607625972994">"အဆင့်မြင့်"</string>
     <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"အခြားထည့်သွင်းမည့် နည်းလမ်းများသို့ ပြောင်းရန်"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"ဘာသာပြောင်းသည့် ကီးသည် အခြားထည့်သွင်းရန် နည်းလမ်းများလည်း ပါဝင်သည်"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"ဘာသာစကား ပြောင်းခလုတ်"</string>
@@ -46,7 +46,7 @@
     <string name="use_contacts_dict" msgid="4435317977804180815">"အဆယ်ကသွယ်အမည်များ အကြံပြုမည်"</string>
     <string name="use_contacts_dict_summary" msgid="6599983334507879959">"အကြံပြုချက်များနှင့် အမှားပြင်ခြင်းများအတွက် အဆက်သွယ်မှ အမည်များ အသုံးပြုမည်"</string>
     <string name="use_personalized_dicts" msgid="5167396352105467626">"ကိုယ်ရေးကိုယ်တာ အကြံပြုချက်များ"</string>
-    <string name="enable_metrics_logging" msgid="5506372337118822837">"မြှင့်တင်ပါ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
+    <string name="enable_metrics_logging" msgid="5506372337118822837">"မြှင့်တင်ပါ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
     <string name="use_double_space_period" msgid="8781529969425082860">"နှစ်နေရာခြား အဆုံးသတ်"</string>
     <string name="use_double_space_period_summary" msgid="6532892187247952799">"အချိန်ကာလ"</string>
     <string name="auto_cap" msgid="1719746674854628252">"အော်တိုစာလုံးကြီးပြောင်း"</string>
@@ -76,9 +76,9 @@
     <string name="voice_input" msgid="3583258583521397548">"အသံထည့်သွင်းရန် ခလုတ်"</string>
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"မည်သည့် Check Language &amp; input settings."</string>
     <string name="configure_input_method" msgid="373356270290742459">"ထည့်သွင်းရန် နည်းလမ်းကို ပြုပြင်မည်"</string>
-    <string name="language_selection_title" msgid="1651299598555326750">"ထည့်သွင်းမှု ဘာသာ"</string>
+    <string name="language_selection_title" msgid="1651299598555326750">"ထည့်သွင်းမှု ဘာသာ"</string>
     <string name="help_and_feedback" msgid="5328219371839879161">"အကူအညီ &amp; တုံ့ပြန်ချက်"</string>
-    <string name="select_language" msgid="3693815588777926848">"ထည့်သွင်းမှု ဘာသာ"</string>
+    <string name="select_language" msgid="3693815588777926848">"ထည့်သွင်းမှု ဘာသာ"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"သိမ်းရန် နောက်တစ်ကြိမ်နှိပ်ပါ"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"အဘိဓါန်ရနိုင်"</string>
     <string name="keyboard_layout" msgid="8451164783510487501">"ကီးဘုတ်အရောင်"</string>
@@ -149,7 +149,7 @@
     <string name="default_user_dict_pref_name" msgid="1625055720489280530">"သုံးစွဲသူ၏ အဘိဓာန်"</string>
     <string name="dictionary_available" msgid="4728975345815214218">"အဘိဓါန်ရရှိနိုင်"</string>
     <string name="dictionary_downloading" msgid="2982650524622620983">"လက်ရှိ ဒေါင်းလုပ်လုပ်နေသည်"</string>
-    <string name="dictionary_installed" msgid="8081558343559342962">"ထည့်သွင်းပြီး"</string>
+    <string name="dictionary_installed" msgid="8081558343559342962">"ထည့်သွင်းပြီး"</string>
     <string name="dictionary_disabled" msgid="8950383219564621762">"ထည့်သွင်းထားပြီး၊ ပိတ်ထားသည်"</string>
     <string name="cannot_connect_to_dict_service" msgid="9216933695765732398">"အဘိဓါန်ဝန်ဆောင်မှုသို့ ချိတ်ဆက်ရန် ပြဿနာရှိနေသည်"</string>
     <string name="no_dictionaries_available" msgid="8039920716566132611">"အဘိဓါန်မရှိ"</string>
@@ -163,7 +163,7 @@
     <string name="install_dict" msgid="180852772562189365">"တပ်ဆင်ပါ"</string>
     <string name="cancel_download_dict" msgid="7843340278507019303">"ပယ်ဖျက်ရန်"</string>
     <string name="delete_dict" msgid="756853268088330054">"ဖျက်ရန်"</string>
-    <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"သင့်ဖုန်းရှိ ရွေးချယ်ထားသည့် ဘာသာအတွက် အဘိဓါန်ရှိပါသည်။ &lt;br/&gt; အဘိဓါန်အား &lt;b&gt;ဒေါင်းလုပ်လုပ်ကာ&lt;/b&gt; the <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>  သင့်စာရိုက် အတွေ့အကြုံတိုးတက်စေရန် ကျွန်ုပ်တို့အကြံပြုပါသည်။ &lt;br/&gt; &lt;br/&gt; ဒေါင်းလုပ်လုပ်ရန် 3G ပေါ်တွင် ၁ မှ ၂ မိနစ်ခန့်ကြာနိုင်သည်။ သင့်တွင် &lt;b&gt;အကန့်သတ်မှရိ အချက်လက် သုံးစွဲမှု&lt;/b&gt;မရှိလျှင် ငွေကျသင့်နိုင်ပါသည်။ &lt;br/&gt; သင့်တွင် မည်သည့်အချက်လက်သုံးစွဲမှု ရှိနေသည်ကိုမသိလျှင်၊ အလိုအလျောက် ဒေါင်းလုပ်လုပ်ရန် Wi-Fi ကွန်ရက်တစ်ခု ရှာဖွေရန် တိုက်တွန်းပါသည်။ &lt;br/&gt; &lt;br/&gt; နည်းလမ်း: သင့်ဖုန်းကိရိယာရှိ &lt;b&gt;ဆက်တင်ထဲတွင်&lt;/b&gt; &lt;b&gt;ဘာသာ &amp; ထည့်သွင်းမှု&lt;/b&gt; သို့သွားကာ အဘိဓါန်များကို ဒေါင်းလုပ်လုပ်နိုင် ဖယ်ရှားနိုင်ပါသည်။"</string>
+    <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"သင့်ဖုန်းရှိ ရွေးချယ်ထားသည့် ဘာသာအတွက် အဘိဓါန်ရှိပါသည်။ &lt;br/&gt; အဘိဓါန်အား &lt;b&gt;ဒေါင်းလုပ်လုပ်ကာ&lt;/b&gt; the <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g>  သင့်စာရိုက် အတွေ့အကြုံတိုးတက်စေရန် ကျွန်ုပ်တို့အကြံပြုပါသည်။ &lt;br/&gt; &lt;br/&gt; ဒေါင်းလုပ်လုပ်ရန် 3G ပေါ်တွင် ၁ မှ ၂ မိနစ်ခန့်ကြာနိုင်သည်။ သင့်တွင် &lt;b&gt;အကန့်သတ်မှရိ အချက်လက် သုံးစွဲမှု&lt;/b&gt;မရှိလျှင် ငွေကျသင့်နိုင်ပါသည်။ &lt;br/&gt; သင့်တွင် မည်သည့်အချက်လက်သုံးစွဲမှု ရှိနေသည်ကိုမသိလျှင်၊ အလိုအလျောက် ဒေါင်းလုပ်လုပ်ရန် Wi-Fi ကွန်ရက်တစ်ခု ရှာဖွေရန် တိုက်တွန်းပါသည်။ &lt;br/&gt; &lt;br/&gt; နည်းလမ်း: သင့်ဖုန်းကိရိယာရှိ &lt;b&gt;ဆက်တင်ထဲတွင်&lt;/b&gt; &lt;b&gt;ဘာသာ &amp; ထည့်သွင်းမှု&lt;/b&gt; သို့သွားကာ အဘိဓါန်များကို ဒေါင်းလုပ်လုပ်နိုင် ဖယ်ရှားနိုင်ပါသည်။"</string>
     <string name="download_over_metered" msgid="1643065851159409546">"ယခုဒေါင်းလုပ်လုပ်မည် (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>MB)"</string>
     <string name="do_not_download_over_metered" msgid="2176209579313941583">"Wi-Fi အသုံးပြု၍ ဒေါင်းလုပ်လုပ်ရန်"</string>
     <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> အတွက် အဘိဓါန် ရနိုင်ပါသည်"</string>
@@ -184,7 +184,7 @@
     <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"စာလုံးကို ပြင်ဆင်မည်"</string>
     <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"တည်းဖြတ်ရန်"</string>
     <string name="user_dict_settings_context_menu_delete_title" msgid="8142932447689461181">"ဖျက်ရန်"</string>
-    <string name="user_dict_settings_empty_text" msgid="558499587532668203">"သင့်အဘိဓာန်ထဲတွင် မည်သည့်စာလုံးမှမရှိပါ။ ထပ်ထည့်ခြင်း(+)ခလုတ်ကို ထိ၍ စာလုံးထည့်ပါ။"</string>
+    <string name="user_dict_settings_empty_text" msgid="558499587532668203">"သင့်အဘိဓာန်ထဲတွင် မည်သည့်စာလုံးမှမရှိပါ။ ထပ်ထည့်ခြင်း(+)ခလုတ်ကို ထိ၍ စာလုံးထည့်ပါ။"</string>
     <string name="user_dict_settings_all_languages" msgid="8276126583216298886">"ဘာသာစကားအားလုံးအတွက်"</string>
     <string name="user_dict_settings_more_languages" msgid="7131268499685180461">"ဘာသာစကားပိုများများ…"</string>
     <string name="user_dict_settings_delete" msgid="110413335187193859">"ဖျက်သိမ်းရန်"</string>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
index c307286..e450717 100644
--- a/java/res/values-nb/strings.xml
+++ b/java/res/values-nb/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ingen taleinndatametoder er aktivert. Sjekk Språk og inndata-innstillingene."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurer inndatametoder"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Inndataspråk"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Hjelp og tilbakemelding"</string>
     <string name="select_language" msgid="3693815588777926848">"Inndataspråk"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Trykk på nytt for å lagre"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Ordbok tilgjengelig"</string>
diff --git a/java/res/values-ne-rNP/strings.xml b/java/res/values-ne-rNP/strings.xml
index 291b08f..926ae13 100644
--- a/java/res/values-ne-rNP/strings.xml
+++ b/java/res/values-ne-rNP/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"कुनै आवाज इनपुट विधिहरू सक्षम गरिएका छैनन्। भाषा र इनपुट सेटिङहरूको जाँच गर्नुहोस्।"</string>
     <string name="configure_input_method" msgid="373356270290742459">"इनपुट विधिहरू कन्फिगर गर्नुहोस्"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"इनपुट भाषाहरू"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"मद्दत र प्रतिक्रिया"</string>
     <string name="select_language" msgid="3693815588777926848">"इनपुट भाषाहरू"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"बचत गर्न पुनः छुनुहोस्"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"उपलब्ध शब्दकोश"</string>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
index 6a391e7..aa4aca8 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -77,10 +77,9 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Geen spraakinvoermethoden ingeschakeld. Ga naar \'Instellingen voor taal en invoer\'."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Invoermethoden configureren"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Invoertalen"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Help en feedback"</string>
     <string name="select_language" msgid="3693815588777926848">"Invoertalen"</string>
-    <string name="hint_add_to_dictionary" msgid="573678656946085380">"Raak nogmaals aan om op te slaan"</string>
+    <string name="hint_add_to_dictionary" msgid="573678656946085380">"Tik nogmaals om op te slaan"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Woordenboek beschikbaar"</string>
     <string name="keyboard_layout" msgid="8451164783510487501">"Toetsenbordthema"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Engels (GB)"</string>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
index ada0134..2c709ad 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nie włączono żadnych metod wprowadzania głosowego. Sprawdź ustawienia języka i wprowadzania."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfiguruj metody wprowadzania"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Języki wprowadzania"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Pomoc i opinie"</string>
     <string name="select_language" msgid="3693815588777926848">"Języki wprowadzania"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Dotknij ponownie, aby zapisać"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Słownik dostępny"</string>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index 5707057..9bd407e 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nenhum método de entrada de texto por voz ativado. Verifique as definições de Idioma e introdução."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de introdução"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Ajuda e comentários"</string>
     <string name="select_language" msgid="3693815588777926848">"Idiomas de introdução"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Toque novamente para guardar"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dicionário disponível"</string>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index 16420c4..4faee4b 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nenhum método de entrada de texto por voz ativado. Verifique as configurações \"Idioma e entrada\"."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Ajuda e feedback"</string>
     <string name="select_language" msgid="3693815588777926848">"Idiomas de entrada"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Toque novamente para salvar"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dicionário disponível"</string>
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index 67b1eef..412ec0e 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nicio metodă de intrare vocală activată. Verificați setările pentru limbă și introducere de text."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configuraţi metodele de intrare"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Selectaţi limba"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Ajutor și feedback"</string>
     <string name="select_language" msgid="3693815588777926848">"Limbi de introducere de text"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Atingeţi din nou pentru a salva"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dicţionar disponibil"</string>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index 7487fe5..eada313 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Голосовой способ ввода не включен. Проверьте раздел настроек \"Язык и ввод\"."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Настройка способов ввода"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Языки ввода"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Справка/отзыв"</string>
     <string name="select_language" msgid="3693815588777926848">"Языки ввода"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Нажмите, чтобы сохранить"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Доступен словарь"</string>
diff --git a/java/res/values-si-rLK/strings.xml b/java/res/values-si-rLK/strings.xml
index 034f3cd..4829988 100644
--- a/java/res/values-si-rLK/strings.xml
+++ b/java/res/values-si-rLK/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"හඬ ආදාන සබල කර නැත. භාෂාව සහ ආදාන සැකසීම් පරීක්ෂා කරන්න."</string>
     <string name="configure_input_method" msgid="373356270290742459">"ආදාන ක්‍රම වින්‍යාස කරන්න"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"ආදාන භාෂා"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"උදවු සහ ප්‍රතිපෝෂණ"</string>
     <string name="select_language" msgid="3693815588777926848">"ආදාන භාෂා"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"සුරැකීමට නැවත ස්පර්ශ කරන්න"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"ශබ්ද කෝෂය ලබාගත හැක"</string>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
index 2728c37..107f379 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nie sú povolené žiadne metódy hlasového vstupu. Skontrolujte nastavenia položky Jazyk a vstup."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurovať metódy vstupu"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Jazyky vstupu"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Pomocník a spätná väzba"</string>
     <string name="select_language" msgid="3693815588777926848">"Jazyky vstupu"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Opätovným dotykom uložíte"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"K dispozícii je slovník"</string>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index 9b15cc3..db24507 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ni omogočenih glasovnih načinov vnosa. Preverite nastavitve v razdelku »Jezik in vnos«."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Nastavitev načinov vnosa"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Jeziki vnosa"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Pomoč in povratne informacije"</string>
     <string name="select_language" msgid="3693815588777926848">"Jeziki vnosa"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Dotaknite se še enkrat, da shranite"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Slovar je na voljo"</string>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index 6739fcf..8cef0d0 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ниједан метод гласовног уноса није омогућен. Проверите Подешавања језика и уноса."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Конфигурисање метода уноса"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Језици за унос"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Помоћ и повратне информације"</string>
     <string name="select_language" msgid="3693815588777926848">"Језици уноса"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Поново додирните да бисте сачували"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Речник је доступан"</string>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
index 1c090e2..c5782cd 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ingen röstinmatningsmetod har aktiverats. Kontrollera språk- och inmatningsinställningarna."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurera inmatningsmetoder"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Inmatningsspråk"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Hjälp och feedback"</string>
     <string name="select_language" msgid="3693815588777926848">"Inmatningsspråk"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Spara genom att trycka igen"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"En ordlista är tillgänglig"</string>
diff --git a/java/res/values-ta-rIN/strings-talkback-descriptions.xml b/java/res/values-ta-rIN/strings-talkback-descriptions.xml
index a65c8de..911e1a5 100644
--- a/java/res/values-ta-rIN/strings-talkback-descriptions.xml
+++ b/java/res/values-ta-rIN/strings-talkback-descriptions.xml
@@ -35,7 +35,7 @@
     <string name="spoken_description_to_symbol" msgid="8244903740201126590">"சின்னங்கள்"</string>
     <string name="spoken_description_to_alpha" msgid="4081215210530031950">"எழுத்துகள்"</string>
     <string name="spoken_description_to_numeric" msgid="4560261331530795682">"எண்கள்"</string>
-    <string name="spoken_description_settings" msgid="7281251004003143204">"அமைப்புகள்"</string>
+    <string name="spoken_description_settings" msgid="7281251004003143204">"அமைப்பு"</string>
     <string name="spoken_description_tab" msgid="8210782459446866716">"டேப்"</string>
     <string name="spoken_description_space" msgid="5908716896642059145">"ஸ்பேஸ்"</string>
     <string name="spoken_description_mic" msgid="6153138783813452464">"குரல் உள்ளீடு"</string>
diff --git a/java/res/values-ta-rIN/strings.xml b/java/res/values-ta-rIN/strings.xml
index 0f0f142..606a255 100644
--- a/java/res/values-ta-rIN/strings.xml
+++ b/java/res/values-ta-rIN/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"குரல் உள்ளீட்டு முறைகள் எதுவும் இயக்கப்படவில்லை. மொழி &amp; உள்ளீட்டு அமைப்புகளைச் சரிபார்க்கவும்."</string>
     <string name="configure_input_method" msgid="373356270290742459">"உள்ளீட்டு முறைகளை உள்ளமைத்தல்"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"உள்ளீட்டு மொழிகள்"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"உதவி &amp; கருத்து"</string>
     <string name="select_language" msgid="3693815588777926848">"உள்ளீட்டு மொழிகள்"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"சேமிக்க தொடவும்"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"அகராதி உள்ளது"</string>
@@ -145,7 +144,7 @@
     <string name="download_description" msgid="6014835283119198591">"அகராதியின் புதுப்பிப்பு தகவல்"</string>
     <string name="dictionary_settings_title" msgid="8091417676045693313">"துணை அகராதிகள்"</string>
     <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"அகராதி கிடைக்கிறது"</string>
-    <string name="dictionary_settings_summary" msgid="5305694987799824349">"அகராதிகளுக்கான அமைப்புகள்"</string>
+    <string name="dictionary_settings_summary" msgid="5305694987799824349">"அகராதிகளுக்கான அமைப்பு"</string>
     <string name="user_dictionaries" msgid="3582332055892252845">"பயனர் அகராதிகள்"</string>
     <string name="default_user_dict_pref_name" msgid="1625055720489280530">"பயனர் அகராதி"</string>
     <string name="dictionary_available" msgid="4728975345815214218">"அகராதி கிடைக்கிறது"</string>
@@ -160,11 +159,11 @@
     <string name="message_loading" msgid="5638680861387748936">"ஏற்றுகிறது..."</string>
     <string name="main_dict_description" msgid="3072821352793492143">"முதன்மை அகராதி"</string>
     <string name="cancel" msgid="6830980399865683324">"ரத்துசெய்"</string>
-    <string name="go_to_settings" msgid="3876892339342569259">"அமைப்புகள்"</string>
+    <string name="go_to_settings" msgid="3876892339342569259">"அமைப்பு"</string>
     <string name="install_dict" msgid="180852772562189365">"நிறுவு"</string>
     <string name="cancel_download_dict" msgid="7843340278507019303">"ரத்துசெய்"</string>
     <string name="delete_dict" msgid="756853268088330054">"நீக்கு"</string>
-    <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"உங்கள் மொபைலில் தேர்ந்தெடுத்த மொழிக்கு அகராதி உள்ளது.&lt;br/&gt; உங்கள் உள்ளீட்டு அனுபவத்தை மேம்படுத்த <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> அகராதியைப்  &lt;b&gt;பதிவிறக்குவதைப்&lt;/b&gt; பரிந்துரைக்கிறோம்.&lt;br/&gt; &lt;br/&gt; 3G இல் பதிவிறக்கத்திற்கு ஒன்று அல்லது இரண்டு நிமிடங்கள் ஆகலாம். உங்களிடம் &lt;b&gt;வரம்பில்லா தரவு திட்டம்&lt;/b&gt; இல்லையெனில் கட்டணம் விதிக்கப்படலாம்.&lt;br/&gt; உங்களிடம் எந்தத் தரவு திட்டம் உள்ளது என்பது உறுதியாகத் தெரியவில்லையெனில், பதிவிறக்கத்தைத் தானாகத் துவங்க, வைஃபை இணைப்பைக் கண்டறிவதைப் பரிந்துரைக்கிறோம்.&lt;br/&gt; &lt;br/&gt; உதவிக்குறிப்பு: உங்கள் மொபைல் சாதனத்தில் &lt;b&gt;அமைப்புகள்&lt;/b&gt; மெனுவில் உள்ள &lt;b&gt;மொழி &amp; உள்ளீடு&lt;/b&gt; என்பதற்குச் செலவதன் மூலம் அகராதிகளைப் பதிவிறக்கலாம் மற்றும் அகற்றலாம்."</string>
+    <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"உங்கள் மொபைலில் தேர்ந்தெடுத்த மொழிக்கு அகராதி உள்ளது.&lt;br/&gt; உங்கள் உள்ளீட்டு அனுபவத்தை மேம்படுத்த <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> அகராதியைப்  &lt;b&gt;பதிவிறக்குவதைப்&lt;/b&gt; பரிந்துரைக்கிறோம்.&lt;br/&gt; &lt;br/&gt; 3G இல் பதிவிறக்கத்திற்கு ஒன்று அல்லது இரண்டு நிமிடங்கள் ஆகலாம். உங்களிடம் &lt;b&gt;வரம்பில்லா தரவு திட்டம்&lt;/b&gt; இல்லையெனில் கட்டணம் விதிக்கப்படலாம்.&lt;br/&gt; உங்களிடம் எந்தத் தரவு திட்டம் உள்ளது என்பது உறுதியாகத் தெரியவில்லையெனில், பதிவிறக்கத்தைத் தானாகத் துவங்க, வைஃபை இணைப்பைக் கண்டறிவதைப் பரிந்துரைக்கிறோம்.&lt;br/&gt; &lt;br/&gt; உதவிக்குறிப்பு: உங்கள் மொபைல் சாதனத்தில் &lt;b&gt;அமைப்பு&lt;/b&gt; மெனுவில் உள்ள &lt;b&gt;மொழி &amp; உள்ளீடு&lt;/b&gt; என்பதற்குச் செலவதன் மூலம் அகராதிகளைப் பதிவிறக்கலாம் மற்றும் அகற்றலாம்."</string>
     <string name="download_over_metered" msgid="1643065851159409546">"இப்போது பதிவிறக்கு (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g>மெ.பை.)"</string>
     <string name="do_not_download_over_metered" msgid="2176209579313941583">"வைஃபை வழியாகப் பதிவிறக்கு"</string>
     <string name="dict_available_notification_title" msgid="4583842811218581658">"<xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> மொழிக்கு அகராதி கிடைக்கிறது"</string>
diff --git a/java/res/values-te-rIN/strings.xml b/java/res/values-te-rIN/strings.xml
index 4e92d1b..75152db 100644
--- a/java/res/values-te-rIN/strings.xml
+++ b/java/res/values-te-rIN/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"వాయిస్ ఇన్‌పుట్ పద్ధతులు ఏవీ ప్రారంభించబడలేదు. భాష &amp; ఇన్‌పుట్ సెట్టింగ్‌లను తనిఖీ చేయండి."</string>
     <string name="configure_input_method" msgid="373356270290742459">"ఇన్‌పుట్ పద్ధతులను కాన్ఫిగర్ చేయండి"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"ఇన్‌పుట్ భాషలు"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"సహాయం &amp; అభిప్రాయం"</string>
     <string name="select_language" msgid="3693815588777926848">"ఇన్‌పుట్ భాషలు"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"సేవ్ చేయడానికి మళ్లీ తాకండి"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"నిఘంటువు అందుబాటులో ఉంది"</string>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
index edbe88a..e22845a 100644
--- a/java/res/values-tl/strings.xml
+++ b/java/res/values-tl/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Walang naka-enable na pamamaraan ng pag-input ng boses. Suriin ang mga setting ng Pag-input ng wika."</string>
     <string name="configure_input_method" msgid="373356270290742459">"I-configure ang mga pamamaraan ng pag-input"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Mag-input ng mga wika"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Tulong at feedback"</string>
     <string name="select_language" msgid="3693815588777926848">"Mga wika ng input"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Pinduting muli upang i-save"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Available ang diksyunaryo"</string>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index 87bafcc..38ad569 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Hiçbir ses girişi yöntemi etkinleştirilmedi. Dil ve giriş ayarlarını kontrol edin."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Giriş yöntemlerini yapılandır"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Giriş dilleri"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Yardım ve geri bildirim"</string>
     <string name="select_language" msgid="3693815588777926848">"Giriş dilleri"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Kaydetmek için tekrar dokunun"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Sözlük kullanılabilir"</string>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
index 63eb40b..f0048ae 100644
--- a/java/res/values-uk/strings.xml
+++ b/java/res/values-uk/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Способи голосового вводу не ввімкнено. Перейдіть у налаштування \"Мова та введення\"."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Налаштування методів введення"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Мови вводу"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Довідка й відгуки"</string>
     <string name="select_language" msgid="3693815588777926848">"Мови введення"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Торкніться знову, щоб зберегти"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Словник доступний"</string>
diff --git a/java/res/values-ur-rPK/strings.xml b/java/res/values-ur-rPK/strings.xml
index fee6f15..b1ad5fa 100644
--- a/java/res/values-ur-rPK/strings.xml
+++ b/java/res/values-ur-rPK/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"کوئی صوتی اندراج کے طریقے فعال نہیں ہیں۔ زبان اور ان پٹ ترتیبات کو چیک کریں۔"</string>
     <string name="configure_input_method" msgid="373356270290742459">"اندراج کے طریقے کنفیگر کریں"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"ان پٹ زبانیں"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"مدد اور تاثرات"</string>
     <string name="select_language" msgid="3693815588777926848">"ان پٹ زبانیں"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"محفوظ کرنے کیلئے دوبارہ ٹچ کریں"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"لغت دستیاب ہے"</string>
diff --git a/java/res/values-uz-rUZ/strings.xml b/java/res/values-uz-rUZ/strings.xml
index adb7ad8..41321e7 100644
--- a/java/res/values-uz-rUZ/strings.xml
+++ b/java/res/values-uz-rUZ/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Ovoz bilan yozish usuli yoqilmagan. Til va matn kiritish sozlamalarini tekshiring."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Matn kiritish usullarini sozlash"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Matn kiritish tillari"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Yordam va fikr-mulohaza"</string>
     <string name="select_language" msgid="3693815588777926848">"Matn kiritish tillari"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Saqlash uchun yana bosing"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Lug‘at mavjud"</string>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
index 3965e4f..30c8d9d 100644
--- a/java/res/values-vi/strings.xml
+++ b/java/res/values-vi/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Không có phương thức nhập bằng giọng nói nào được bật. Kiểm tra cài đặt Ngôn ngữ và phương thức nhập."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Định cấu hình phương thức nhập"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Ngôn ngữ nhập"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"Trợ giúp và phản hồi"</string>
     <string name="select_language" msgid="3693815588777926848">"Ngôn ngữ nhập"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Chạm lại để lưu"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Có sẵn từ điển"</string>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index aec0c0c..0dfb9f9 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"未启用任何语音输入法。请检查“语言和输入法”设置。"</string>
     <string name="configure_input_method" msgid="373356270290742459">"配置输入法"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"输入语言"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"帮助和反馈"</string>
     <string name="select_language" msgid="3693815588777926848">"输入语言"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"再次触摸即可保存"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"有可用字典"</string>
diff --git a/java/res/values-zh-rHK/strings.xml b/java/res/values-zh-rHK/strings.xml
index f74fa31..791074c 100644
--- a/java/res/values-zh-rHK/strings.xml
+++ b/java/res/values-zh-rHK/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"尚未啟用語音輸入法,請檢查語言和輸入設定。"</string>
     <string name="configure_input_method" msgid="373356270290742459">"設定輸入法"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"輸入語言"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"說明與意見反映"</string>
     <string name="select_language" msgid="3693815588777926848">"輸入語言"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"再次輕觸即可儲存"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"可使用字典"</string>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index e371de2..97a0052 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -77,8 +77,7 @@
     <string name="voice_input_disabled_summary" msgid="8141750303464726129">"尚未啟動語音輸入法,請檢查語言與輸入設定。"</string>
     <string name="configure_input_method" msgid="373356270290742459">"設定輸入法"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"輸入語言"</string>
-    <!-- no translation found for help_and_feedback (5328219371839879161) -->
-    <skip />
+    <string name="help_and_feedback" msgid="5328219371839879161">"說明與意見回饋"</string>
     <string name="select_language" msgid="3693815588777926848">"輸入語言"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"再次輕觸即可儲存"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"可用的字典"</string>
diff --git a/java/res/values/config-common.xml b/java/res/values/config-common.xml
index 063fbfb..36fd30a 100644
--- a/java/res/values/config-common.xml
+++ b/java/res/values/config-common.xml
@@ -24,7 +24,7 @@
          at input history to suggest a hopefully helpful suggestions for the next word? -->
     <bool name="config_default_next_word_prediction">true</bool>
 
-    <integer name="config_delay_update_shift_state">100</integer>
+    <integer name="config_delay_in_milliseconds_to_update_shift_state">100</integer>
     <integer name="config_double_space_period_timeout">1100</integer>
 
     <integer name="config_key_repeat_start_timeout">400</integer>
@@ -107,8 +107,8 @@
     <!-- Common suggestion strip configuration. -->
     <integer name="config_suggestions_count_in_strip">3</integer>
     <fraction name="config_center_suggestion_percentile">36%</fraction>
-    <integer name="config_delay_update_suggestions">100</integer>
-    <integer name="config_delay_update_old_suggestions">300</integer>
+    <integer name="config_delay_in_milliseconds_to_update_suggestions">100</integer>
+    <integer name="config_delay_in_milliseconds_to_update_old_suggestions">300</integer>
 
     <!-- Common more suggestions configuraion. -->
     <dimen name="config_more_suggestions_key_horizontal_padding">12dp</dimen>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index c3f5cf4..2a6495a 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -168,6 +168,8 @@
 
     <!-- Add to dictionary hint -->
     <string name="hint_add_to_dictionary">Touch again to save</string>
+    <!-- Add to dictionary hint -->
+    <string name="hint_add_to_dictionary_without_word">Touch here to save</string>
 
     <!-- Inform the user that a particular language has an available dictionary -->
     <string name="has_dictionary">Dictionary available</string>
diff --git a/java/res/xml-sw600dp/key_comma.xml b/java/res/xml-sw600dp/key_comma.xml
index 67199e2..e616a8d 100644
--- a/java/res/xml-sw600dp/key_comma.xml
+++ b/java/res/xml-sw600dp/key_comma.xml
@@ -2,7 +2,7 @@
 <!--
 /*
 **
-** Copyright 2014, The Android Open Source Project
+** Copyright 2012, 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.
@@ -21,27 +21,36 @@
 <merge
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
-    <!-- The table comma key which may have settings as popup key. -->
-    <!-- Kept as a separate file for cleaner overriding by an overlay.  -->
-    <key-style
-        latin:styleName="baseTabletCommaKeyStyle"
-        latin:keySpec="!text/keyspec_tablet_comma"
-        latin:keyHintLabel="!text/keyhintlabel_tablet_comma"
-        latin:keyLabelFlags="hasPopupHint"
-        latin:parentStyle="hasShiftedLetterHintStyle" />
     <switch>
         <case
-            latin:clobberSettingsKey="true"
+            latin:mode="url"
         >
             <Key
-                latin:moreKeys="!text/morekeys_tablet_comma"
-                latin:keyStyle="baseTabletCommaKeyStyle" />
+                latin:keySpec="/"
+                latin:keyStyle="settingsMoreKeysStyle" />
         </case>
-        <!-- clobberSettingsKey="false" -->
+        <case
+            latin:mode="email"
+        >
+            <Key
+                latin:keySpec="\@"
+                latin:keyStyle="settingsMoreKeysStyle" />
+        </case>
+        <case
+            latin:keyboardLayoutSet="dvorak"
+        >
+            <Key
+                latin:keySpec="!"
+                latin:moreKeys="!text/morekeys_exclamation,%"
+                latin:keyStyle="settingsMoreKeysStyle" />
+        </case>
         <default>
             <Key
-                latin:moreKeys="!text/morekeys_tablet_comma,!text/keyspec_settings"
-                latin:keyStyle="baseTabletCommaKeyStyle" />
+                latin:keySpec="!text/keyspec_tablet_comma"
+                latin:moreKeys="!text/morekeys_tablet_comma,%"
+                latin:keyHintLabel="!text/keyhintlabel_tablet_comma"
+                latin:keyLabelFlags="hasPopupHint"
+                latin:keyStyle="settingsMoreKeysStyle" />
         </default>
     </switch>
 </merge>
diff --git a/java/res/xml-sw600dp/key_f1.xml b/java/res/xml-sw600dp/key_f1.xml
deleted file mode 100644
index ba78a64..0000000
--- a/java/res/xml-sw600dp/key_f1.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, 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.
-*/
--->
-
-<merge
-    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
-    <switch>
-        <case
-            latin:mode="email"
-        >
-            <Key
-                latin:keySpec="\@" />
-        </case>
-        <default>
-            <Key
-                latin:keySpec="/" />
-        </default>
-    </switch>
-</merge>
diff --git a/java/res/xml-sw600dp/key_period.xml b/java/res/xml-sw600dp/key_period.xml
index d2909d8..df1daf7 100644
--- a/java/res/xml-sw600dp/key_period.xml
+++ b/java/res/xml-sw600dp/key_period.xml
@@ -35,6 +35,13 @@
                 latin:moreKeys="!autoColumnOrder!8,\\,,.,',#,),(,/,;,@,:,-,&quot;,+,\\%,&amp;"
                 latin:backgroundType="functional" />
         </case>
+        <case
+            latin:keyboardLayoutSet="dvorak"
+        >
+            <Key
+                latin:keySpec="\?"
+                latin:moreKeys="!text/morekeys_tablet_period,!text/morekeys_question" />
+        </case>
         <default>
             <Key
                 latin:keySpec="!text/keyspec_tablet_period"
diff --git a/java/res/xml-sw600dp/key_question_exclamation.xml b/java/res/xml-sw600dp/key_question_exclamation.xml
deleted file mode 100644
index edee5c5..0000000
--- a/java/res/xml-sw600dp/key_question_exclamation.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, 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.
-*/
--->
-
-<merge
-    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
-    <switch>
-        <case
-            latin:mode="email|url"
-        >
-            <Key
-                latin:keySpec="-" />
-        </case>
-        <default>
-            <Key
-                latin:keySpec="\?"
-                latin:keyHintLabel="!"
-                latin:moreKeys="!"
-                latin:keyStyle="hasShiftedLetterHintStyle" />
-        </default>
-    </switch>
-</merge>
diff --git a/java/res/xml-sw600dp/key_space_5kw.xml b/java/res/xml-sw600dp/key_space_7kw.xml
similarity index 93%
rename from java/res/xml-sw600dp/key_space_5kw.xml
rename to java/res/xml-sw600dp/key_space_7kw.xml
index 8302184..3311f81 100644
--- a/java/res/xml-sw600dp/key_space_5kw.xml
+++ b/java/res/xml-sw600dp/key_space_7kw.xml
@@ -34,7 +34,7 @@
                 latin:keyStyle="languageSwitchKeyStyle" />
             <Key
                 latin:keyStyle="spaceKeyStyle"
-                latin:keyWidth="27.0%p" />
+                latin:keyWidth="45.0%p" />
             <Key
                 latin:keyStyle="zwnjKeyStyle" />
         </case>
@@ -44,7 +44,7 @@
         >
             <Key
                 latin:keyStyle="spaceKeyStyle"
-                latin:keyWidth="36.0%p" />
+                latin:keyWidth="54.0%p" />
             <Key
                 latin:keyStyle="zwnjKeyStyle" />
         </case>
@@ -55,13 +55,13 @@
                 latin:keyStyle="languageSwitchKeyStyle" />
             <Key
                 latin:keyStyle="spaceKeyStyle"
-                latin:keyWidth="36.0%p" />
+                latin:keyWidth="54.0%p" />
         </case>
         <!-- languageSwitchKeyEnabled="false" -->
         <default>
             <Key
                 latin:keyStyle="spaceKeyStyle"
-                latin:keyWidth="45.0%p" />
+                latin:keyWidth="63.0%p" />
         </default>
     </switch>
 </merge>
diff --git a/java/res/xml-sw600dp/key_styles_common.xml b/java/res/xml-sw600dp/key_styles_common.xml
index 1b52b1e..c750a93 100644
--- a/java/res/xml-sw600dp/key_styles_common.xml
+++ b/java/res/xml-sw600dp/key_styles_common.xml
@@ -36,6 +36,9 @@
         </default>
     </switch>
     <!-- Base key style for the key which may have settings key as more keys. -->
+    <key-style
+        latin:styleName="baseSettingsMoreKeysStyle"
+        latin:parentStyle="hasShiftedLetterHintStyle" />
     <include
         latin:keyboardLayout="@xml/key_styles_settings" />
     <!-- Functional key styles -->
diff --git a/java/res/xml-sw600dp/row_dvorak4.xml b/java/res/xml-sw600dp/row_dvorak4.xml
deleted file mode 100644
index ab2b560..0000000
--- a/java/res/xml-sw600dp/row_dvorak4.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, 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.
-*/
--->
-
-<merge
-    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
-    <Row
-        latin:keyWidth="9.0%p"
-        latin:backgroundType="functional"
-    >
-        <Key
-            latin:keyStyle="toSymbolKeyStyle"
-            latin:keyWidth="10.0%p" />
-        <include
-            latin:keyboardLayout="@xml/key_settings" />
-        <Key
-            latin:keySpec="_"
-            latin:keyHintLabel="-"
-            latin:moreKeys="-"
-            latin:keyStyle="hasShiftedLetterHintStyle" />
-        <include
-            latin:keyXPos="28.0%p"
-            latin:keyboardLayout="@xml/key_space_5kw"
-            latin:backgroundType="normal" />
-        <include
-            latin:keyboardLayout="@xml/key_f1" />
-        <include
-            latin:keyboardLayout="@xml/key_question_exclamation" />
-        <include
-            latin:keyboardLayout="@xml/key_f2" />
-    </Row>
-</merge>
diff --git a/java/res/xml-sw600dp/row_pcqwerty5.xml b/java/res/xml-sw600dp/row_pcqwerty5.xml
index ac07f11..4dcae14 100644
--- a/java/res/xml-sw600dp/row_pcqwerty5.xml
+++ b/java/res/xml-sw600dp/row_pcqwerty5.xml
@@ -50,6 +50,6 @@
             latin:keyXPos="-9.0%p"
             latin:keyWidth="9.0%p"
             latin:backgroundType="functional"
-            latin:keyboardLayout="@xml/key_f2" />
+            latin:keyboardLayout="@xml/key_emoji" />
     </Row>
 </merge>
diff --git a/java/res/xml-sw600dp/row_qwerty4.xml b/java/res/xml-sw600dp/row_qwerty4.xml
index 0eb86f2..ed7150d 100644
--- a/java/res/xml-sw600dp/row_qwerty4.xml
+++ b/java/res/xml-sw600dp/row_qwerty4.xml
@@ -30,18 +30,14 @@
             latin:keyWidth="10.0%p" />
         <include
             latin:keyboardLayout="@xml/key_comma" />
-        <Key
-            latin:keySpec="_" />
         <!-- Space key. -->
         <include
-            latin:keyXPos="28.0%p"
-            latin:keyboardLayout="@xml/key_space_5kw"
+            latin:keyXPos="19.0%p"
+            latin:keyboardLayout="@xml/key_space_7kw"
             latin:backgroundType="normal" />
         <include
-            latin:keyboardLayout="@xml/key_f1" />
-        <include
             latin:keyboardLayout="@xml/key_period" />
         <include
-            latin:keyboardLayout="@xml/key_f2" />
+            latin:keyboardLayout="@xml/key_emoji" />
     </Row>
 </merge>
diff --git a/java/res/xml-sw600dp/rows_dvorak.xml b/java/res/xml-sw600dp/rows_dvorak.xml
index 8859267..c8f5e3a 100644
--- a/java/res/xml-sw600dp/rows_dvorak.xml
+++ b/java/res/xml-sw600dp/rows_dvorak.xml
@@ -53,6 +53,8 @@
             latin:keyStyle="shiftKeyStyle"
             latin:keyWidth="fillRight" />
     </Row>
+    <!-- Dvorak layout shares almost the same row with Qwerty layout.
+         The difference is defined in xml-sw600dp/row_qwerty4.xml. -->
     <include
-        latin:keyboardLayout="@xml/row_dvorak4" />
+        latin:keyboardLayout="@xml/row_qwerty4" />
 </merge>
diff --git a/java/res/xml-sw600dp/rows_symbols.xml b/java/res/xml-sw600dp/rows_symbols.xml
index a915c33..05e7c68 100644
--- a/java/res/xml-sw600dp/rows_symbols.xml
+++ b/java/res/xml-sw600dp/rows_symbols.xml
@@ -70,6 +70,6 @@
         <include
             latin:keyboardLayout="@xml/row_symbols4" />
         <include
-            latin:keyboardLayout="@xml/key_f2" />
+            latin:keyboardLayout="@xml/key_emoji" />
     </Row>
 </merge>
diff --git a/java/res/xml-sw600dp/rows_symbols_shift.xml b/java/res/xml-sw600dp/rows_symbols_shift.xml
index 7ead4d5..70ac42e 100644
--- a/java/res/xml-sw600dp/rows_symbols_shift.xml
+++ b/java/res/xml-sw600dp/rows_symbols_shift.xml
@@ -72,6 +72,6 @@
         <include
             latin:keyboardLayout="@xml/row_symbols_shift4" />
         <include
-            latin:keyboardLayout="@xml/key_f2" />
+            latin:keyboardLayout="@xml/key_emoji" />
     </Row>
 </merge>
diff --git a/java/res/xml/key_f1.xml b/java/res/xml/key_comma.xml
similarity index 82%
rename from java/res/xml/key_f1.xml
rename to java/res/xml/key_comma.xml
index 7bd7385..cf919a8 100644
--- a/java/res/xml/key_f1.xml
+++ b/java/res/xml/key_comma.xml
@@ -23,6 +23,15 @@
 >
     <switch>
         <case
+            latin:keyboardLayoutSet="dvorak"
+        >
+            <Key
+                latin:keySpec="q"
+                latin:moreKeys="!text/morekeys_q,%"
+                latin:backgroundType="normal"
+                latin:keyStyle="settingsMoreKeysStyle" />
+        </case>
+        <case
             latin:mode="url"
         >
             <Key
diff --git a/java/res/xml/key_f2.xml b/java/res/xml/key_emoji.xml
similarity index 100%
rename from java/res/xml/key_f2.xml
rename to java/res/xml/key_emoji.xml
diff --git a/java/res/xml/key_period.xml b/java/res/xml/key_period.xml
index e1d4bbd..fc27c02 100644
--- a/java/res/xml/key_period.xml
+++ b/java/res/xml/key_period.xml
@@ -48,6 +48,14 @@
                 latin:moreKeys="!text/morekeys_punctuation"
                 latin:backgroundType="functional" />
         </case>
+        <case
+            latin:keyboardLayoutSet="dvorak"
+        >
+            <Key
+                latin:keySpec="z"
+                latin:keyLabelFlags="hasPopupHint"
+                latin:moreKeys="!text/morekeys_punctuation,!text/morekeys_z" />
+        </case>
         <default>
             <Key
                 latin:keySpec="!text/keyspec_period"
diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml
index 2d006c9..167e6f8 100644
--- a/java/res/xml/key_styles_common.xml
+++ b/java/res/xml/key_styles_common.xml
@@ -36,6 +36,8 @@
         </default>
     </switch>
     <!-- Base key style for the key which may have settings key as more keys. -->
+    <key-style
+        latin:styleName="baseSettingsMoreKeysStyle" />
     <include
         latin:keyboardLayout="@xml/key_styles_settings" />
     <!-- Functional key styles -->
diff --git a/java/res/xml/key_styles_settings.xml b/java/res/xml/key_styles_settings.xml
index 956b402..a504bed 100644
--- a/java/res/xml/key_styles_settings.xml
+++ b/java/res/xml/key_styles_settings.xml
@@ -29,15 +29,17 @@
         >
             <key-style
                 latin:styleName="settingsMoreKeysStyle"
-                latin:backgroundType="functional" />
+                latin:backgroundType="functional"
+                latin:parentStyle="baseSettingsMoreKeysStyle" />
         </case>
         <!-- clobberSettingsKey="false" -->
         <default>
             <key-style
                 latin:styleName="settingsMoreKeysStyle"
                 latin:keyLabelFlags="hasPopupHint"
-                latin:moreKeys="!text/keyspec_settings"
-                latin:backgroundType="functional" />
+                latin:additionalMoreKeys="!text/keyspec_settings"
+                latin:backgroundType="functional"
+                latin:parentStyle="baseSettingsMoreKeysStyle" />
         </default>
     </switch>
 </merge>
diff --git a/java/res/xml/row_dvorak4.xml b/java/res/xml/row_dvorak4.xml
deleted file mode 100644
index e7a3ee7..0000000
--- a/java/res/xml/row_dvorak4.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, 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.
-*/
--->
-
-<merge
-    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
-    <Row
-        latin:keyWidth="10%p"
-    >
-        <Key
-            latin:keyStyle="toSymbolKeyStyle"
-            latin:keyWidth="15%p" />
-        <Key
-            latin:keySpec="q"
-            latin:backgroundType="normal"
-            latin:keyStyle="settingsMoreKeysStyle" />
-        <include
-            latin:keyXPos="25%p"
-            latin:keyboardLayout="@xml/key_space_5kw" />
-        <Key
-            latin:keySpec="z"
-            latin:keyLabelFlags="hasPopupHint"
-            latin:moreKeys="!text/morekeys_punctuation,!text/morekeys_z" />
-        <Key
-            latin:keyStyle="enterKeyStyle"
-            latin:keyWidth="fillRight" />
-    </Row>
-</merge>
diff --git a/java/res/xml/row_qwerty4.xml b/java/res/xml/row_qwerty4.xml
index 509092d..5bc104f 100644
--- a/java/res/xml/row_qwerty4.xml
+++ b/java/res/xml/row_qwerty4.xml
@@ -28,7 +28,7 @@
             latin:keyStyle="toSymbolKeyStyle"
             latin:keyWidth="15%p" />
         <include
-            latin:keyboardLayout="@xml/key_f1" />
+            latin:keyboardLayout="@xml/key_comma" />
         <include
             latin:keyXPos="25%p"
             latin:keyboardLayout="@xml/key_space_5kw" />
diff --git a/java/res/xml/rows_dvorak.xml b/java/res/xml/rows_dvorak.xml
index 13d7021..f656613 100644
--- a/java/res/xml/rows_dvorak.xml
+++ b/java/res/xml/rows_dvorak.xml
@@ -49,6 +49,8 @@
             latin:keyWidth="fillRight"
             latin:visualInsetsLeft="1%p" />
     </Row>
+    <!-- Dvorak layout shares almost the same row with Qwerty layout.
+         The difference is defined in xml/row_qwerty4.xml. -->
     <include
-        latin:keyboardLayout="@xml/row_dvorak4" />
+        latin:keyboardLayout="@xml/row_qwerty4" />
 </merge>
diff --git a/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
index b84d402..94a1ee6 100644
--- a/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
+++ b/java/src/com/android/inputmethod/accessibility/MainKeyboardAccessibilityDelegate.java
@@ -121,7 +121,7 @@
      */
     private void announceKeyboardLanguage(final Keyboard keyboard) {
         final String languageText = SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(
-                keyboard.mId.mSubtype);
+                keyboard.mId.mSubtype.getRawSubtype());
         sendWindowStateChanged(languageText);
     }
 
diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java
index 3658672..b9a5367 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatUtils.java
@@ -21,6 +21,7 @@
 
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
@@ -64,6 +65,10 @@
                 overridesImplicitlyEnabledSubtype, id);
     }
 
+    public static boolean isAsciiCapable(final RichInputMethodSubtype subtype) {
+        return isAsciiCapable(subtype.getRawSubtype());
+    }
+
     public static boolean isAsciiCapable(final InputMethodSubtype subtype) {
         return isAsciiCapableWithAPI(subtype)
                 || subtype.containsExtraValueKey(Constants.Subtype.ExtraValue.ASCII_CAPABLE);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 3c11675..538e515 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -21,9 +21,9 @@
 import android.text.InputType;
 import android.text.TextUtils;
 import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.compat.EditorInfoCompatUtils;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.utils.InputTypeUtils;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 
@@ -62,7 +62,7 @@
     public static final int ELEMENT_EMOJI_CATEGORY5 = 15;
     public static final int ELEMENT_EMOJI_CATEGORY6 = 16;
 
-    public final InputMethodSubtype mSubtype;
+    public final RichInputMethodSubtype mSubtype;
     public final Locale mLocale;
     public final int mWidth;
     public final int mHeight;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index d6d0b21..0804ceb 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -28,7 +28,6 @@
 import android.util.SparseArray;
 import android.util.Xml;
 import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.compat.EditorInfoCompatUtils;
 import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
@@ -37,6 +36,7 @@
 import com.android.inputmethod.keyboard.internal.KeysCache;
 import com.android.inputmethod.latin.InputAttributes;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.SubtypeSwitcher;
 import com.android.inputmethod.latin.define.DebugFlags;
 import com.android.inputmethod.latin.utils.InputTypeUtils;
@@ -109,7 +109,7 @@
         boolean mVoiceInputKeyEnabled;
         boolean mNoSettingsKey;
         boolean mLanguageSwitchKeyEnabled;
-        InputMethodSubtype mSubtype;
+        RichInputMethodSubtype mSubtype;
         boolean mIsSpellChecker;
         int mKeyboardWidth;
         int mKeyboardHeight;
@@ -245,7 +245,7 @@
             return this;
         }
 
-        public Builder setSubtype(final InputMethodSubtype subtype) {
+        public Builder setSubtype(final RichInputMethodSubtype subtype) {
             final boolean asciiCapable = InputMethodSubtypeCompatUtils.isAsciiCapable(subtype);
             // TODO: Consolidate with {@link InputAttributes}.
             @SuppressWarnings("deprecation")
@@ -254,7 +254,7 @@
             final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii(
                     mParams.mEditorInfo.imeOptions)
                     || deprecatedForceAscii;
-            final InputMethodSubtype keyboardSubtype = (forceAscii && !asciiCapable)
+            final RichInputMethodSubtype keyboardSubtype = (forceAscii && !asciiCapable)
                     ? SubtypeSwitcher.getInstance().getNoLanguageSubtype()
                     : subtype;
             mParams.mSubtype = keyboardSubtype;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 140e768..77cdf49 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -261,6 +261,9 @@
     }
 
     public void onToggleEmojiKeyboard() {
+        if (mKeyboardLayoutSet == null) {
+            return;
+        }
         if (isShowingEmojiPalettes()) {
             setAlphabetKeyboard();
         } else {
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 1ef53a6..847d907 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -34,7 +34,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.accessibility.AccessibilityUtils;
 import com.android.inputmethod.accessibility.MainKeyboardAccessibilityDelegate;
@@ -54,10 +53,10 @@
 import com.android.inputmethod.keyboard.internal.TimerHandler;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.settings.DebugSettings;
 import com.android.inputmethod.latin.utils.CoordinateUtils;
-import com.android.inputmethod.latin.utils.SpacebarLanguageUtils;
 import com.android.inputmethod.latin.utils.TypefaceUtils;
 
 import java.util.WeakHashMap;
@@ -849,16 +848,16 @@
 
     // Layout language name on spacebar.
     private String layoutLanguageOnSpacebar(final Paint paint,
-            final InputMethodSubtype subtype, final int width) {
+            final RichInputMethodSubtype subtype, final int width) {
         // Choose appropriate language name to fit into the width.
         if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarHelper.FORMAT_TYPE_FULL_LOCALE) {
-            final String fullText = SpacebarLanguageUtils.getFullDisplayName(subtype);
+            final String fullText = subtype.getFullDisplayName();
             if (fitsTextIntoWidth(width, fullText, paint)) {
                 return fullText;
             }
         }
 
-        final String middleText = SpacebarLanguageUtils.getMiddleDisplayName(subtype);
+        final String middleText = subtype.getMiddleDisplayName();
         if (fitsTextIntoWidth(width, middleText, paint)) {
             return middleText;
         }
@@ -872,7 +871,7 @@
         paint.setTextAlign(Align.CENTER);
         paint.setTypeface(Typeface.DEFAULT);
         paint.setTextSize(mLanguageOnSpacebarTextSize);
-        final InputMethodSubtype subtype = getKeyboard().mId.mSubtype;
+        final RichInputMethodSubtype subtype = getKeyboard().mId.mSubtype;
         final String language = layoutLanguageOnSpacebar(paint, subtype, width);
         // Draw language text with shadow
         final float descent = paint.descent();
diff --git a/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java b/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java
index 6400a24..72ad2bd 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelper.java
@@ -18,6 +18,7 @@
 
 import android.view.inputmethod.InputMethodSubtype;
 
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 
 import java.util.Collections;
@@ -34,8 +35,8 @@
     private List<InputMethodSubtype> mEnabledSubtypes = Collections.emptyList();
     private boolean mIsSystemLanguageSameAsInputLanguage;
 
-    public int getLanguageOnSpacebarFormatType(final InputMethodSubtype subtype) {
-        if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
+    public int getLanguageOnSpacebarFormatType(final RichInputMethodSubtype subtype) {
+        if (subtype.isNoLanguage()) {
             return FORMAT_TYPE_FULL_LOCALE;
         }
         // Only this subtype is enabled and equals to the system locale.
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index e1d8099..87b34a9 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -51,6 +51,7 @@
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CursorAnchorInfo;
 import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethod;
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.accessibility.AccessibilityUtils;
@@ -192,8 +193,8 @@
         private static final int ARG1_FALSE = 0;
         private static final int ARG1_TRUE = 1;
 
-        private int mDelayUpdateSuggestions;
-        private int mDelayUpdateShiftState;
+        private int mDelayInMillisecondsToUpdateSuggestions;
+        private int mDelayInMillisecondsToUpdateShiftState;
 
         public UIHandler(final LatinIME ownerInstance) {
             super(ownerInstance);
@@ -205,8 +206,10 @@
                 return;
             }
             final Resources res = latinIme.getResources();
-            mDelayUpdateSuggestions = res.getInteger(R.integer.config_delay_update_suggestions);
-            mDelayUpdateShiftState = res.getInteger(R.integer.config_delay_update_shift_state);
+            mDelayInMillisecondsToUpdateSuggestions =
+                    res.getInteger(R.integer.config_delay_in_milliseconds_to_update_suggestions);
+            mDelayInMillisecondsToUpdateShiftState =
+                    res.getInteger(R.integer.config_delay_in_milliseconds_to_update_shift_state);
         }
 
         @Override
@@ -272,7 +275,7 @@
 
         public void postUpdateSuggestionStrip(final int inputStyle) {
             sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP, inputStyle,
-                    0 /* ignored */), mDelayUpdateSuggestions);
+                    0 /* ignored */), mDelayInMillisecondsToUpdateSuggestions);
         }
 
         public void postReopenDictionaries() {
@@ -285,16 +288,14 @@
             if (latinIme == null) {
                 return;
             }
-            if (!latinIme.mSettings.getCurrent()
-                    .isSuggestionsEnabledPerUserSettings()) {
+            if (!latinIme.mSettings.getCurrent().isSuggestionsEnabledPerUserSettings()) {
                 return;
             }
             removeMessages(MSG_RESUME_SUGGESTIONS);
             if (shouldDelay) {
                 sendMessageDelayed(obtainMessage(MSG_RESUME_SUGGESTIONS,
-                                shouldIncludeResumedWordInSuggestions ? ARG1_TRUE : ARG1_FALSE,
-                                0 /* ignored */),
-                        mDelayUpdateSuggestions);
+                        shouldIncludeResumedWordInSuggestions ? ARG1_TRUE : ARG1_FALSE,
+                        0 /* ignored */), mDelayInMillisecondsToUpdateSuggestions);
             } else {
                 sendMessage(obtainMessage(MSG_RESUME_SUGGESTIONS,
                         shouldIncludeResumedWordInSuggestions ? ARG1_TRUE : ARG1_FALSE,
@@ -335,7 +336,8 @@
 
         public void postUpdateShiftState() {
             removeMessages(MSG_UPDATE_SHIFT_STATE);
-            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState);
+            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE),
+                    mDelayInMillisecondsToUpdateShiftState);
         }
 
         @UsedForTesting
@@ -747,7 +749,8 @@
     public void onCurrentInputMethodSubtypeChanged(final InputMethodSubtype subtype) {
         // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
         // is not guaranteed. It may even be called at the same time on a different thread.
-        mSubtypeSwitcher.onSubtypeChanged(subtype);
+        final RichInputMethodSubtype richSubtype = new RichInputMethodSubtype(subtype);
+        mSubtypeSwitcher.onSubtypeChanged(richSubtype);
         mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype));
         loadKeyboard();
     }
@@ -1138,6 +1141,17 @@
     }
 
     @Override
+    public boolean onShowInputRequested(final int flags, final boolean configChange) {
+        if ((flags & InputMethod.SHOW_EXPLICIT) == 0 && mKeyboardSwitcher.hasHardwareKeyboard()) {
+            // Even when IME is implicitly shown and physical keyboard is connected, we should
+            // show {@link InputView}.
+            // See {@link InputMethodService#onShowInputRequested(int,boolean)}.
+            return true;
+        }
+        return super.onShowInputRequested(flags, configChange);
+    }
+
+    @Override
     public boolean onEvaluateFullscreenMode() {
         if (mKeyboardSwitcher.hasHardwareKeyboard()) {
             // If there is a hardware keyboard, disable full screen mode.
@@ -1258,10 +1272,26 @@
         mSubtypeState.switchSubtype(token, mRichImm);
     }
 
+    // TODO: Instead of checking for alphabetic keyboard here, separate keycodes for
+    // alphabetic shift and shift while in symbol layout and get rid of this method.
+    private int getCodePointForKeyboard(final int codePoint) {
+        if (Constants.CODE_SHIFT == codePoint) {
+            final Keyboard currentKeyboard = mKeyboardSwitcher.getKeyboard();
+            if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) {
+                return codePoint;
+            } else {
+                return Constants.CODE_SYMBOL_SHIFT;
+            }
+        } else {
+            return codePoint;
+        }
+    }
+
     // Implementation of {@link KeyboardActionListener}.
     @Override
     public void onCodeInput(final int codePoint, final int x, final int y,
             final boolean isKeyRepeat) {
+        // TODO: this processing does not belong inside LatinIME, the caller should be doing this.
         final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
         // x and y include some padding, but everything down the line (especially native
         // code) needs the coordinates in the keyboard frame.
@@ -1270,36 +1300,30 @@
         // this transformation, it should be done already before calling onCodeInput.
         final int keyX = mainKeyboardView.getKeyX(x);
         final int keyY = mainKeyboardView.getKeyY(y);
-        final int codeToSend;
-        if (Constants.CODE_SHIFT == codePoint) {
-            // TODO: Instead of checking for alphabetic keyboard here, separate keycodes for
-            // alphabetic shift and shift while in symbol layout.
-            final Keyboard currentKeyboard = mKeyboardSwitcher.getKeyboard();
-            if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) {
-                codeToSend = codePoint;
-            } else {
-                codeToSend = Constants.CODE_SYMBOL_SHIFT;
-            }
-        } else {
-            codeToSend = codePoint;
-        }
-        if (Constants.CODE_SHORTCUT == codePoint) {
+        final Event event = createSoftwareKeypressEvent(getCodePointForKeyboard(codePoint),
+                keyX, keyY, isKeyRepeat);
+        onEvent(event);
+    }
+
+    // This method is public for testability of LatinIME, but also in the future it should
+    // completely replace #onCodeInput.
+    public void onEvent(final Event event) {
+        if (Constants.CODE_SHORTCUT == event.mCodePoint) {
             mSubtypeSwitcher.switchToShortcutIME(this);
-            // Still call the *#onCodeInput methods for readability.
         }
-        final Event event = createSoftwareKeypressEvent(codeToSend, keyX, keyY, isKeyRepeat);
         final InputTransaction completeInputTransaction =
                 mInputLogic.onCodeInput(mSettings.getCurrent(), event,
                         mKeyboardSwitcher.getKeyboardShiftMode(),
                         mKeyboardSwitcher.getCurrentKeyboardScriptId(), mHandler);
         updateStateAfterInputTransaction(completeInputTransaction);
-        mKeyboardSwitcher.onCodeInput(codePoint, getCurrentAutoCapsState(),
+        mKeyboardSwitcher.onCodeInput(event.mCodePoint, getCurrentAutoCapsState(),
                 getCurrentRecapitalizeState());
     }
 
     // A helper method to split the code point and the key code. Ultimately, they should not be
     // squashed into the same variable, and this method should be removed.
-    private static Event createSoftwareKeypressEvent(final int keyCodeOrCodePoint, final int keyX,
+    // public for testing, as we don't want to copy the same logic into test code
+    public static Event createSoftwareKeypressEvent(final int keyCodeOrCodePoint, final int keyX,
              final int keyY, final boolean isKeyRepeat) {
         final int keyCode;
         final int codePoint;
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index ea63cef..0355576 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -16,9 +16,13 @@
 
 package com.android.inputmethod.latin;
 
+import android.graphics.Color;
 import android.inputmethodservice.InputMethodService;
 import android.os.Build;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
 import android.text.TextUtils;
+import android.text.style.BackgroundColorSpan;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.inputmethod.CompletionInfo;
@@ -81,6 +85,18 @@
      */
     private final StringBuilder mComposingText = new StringBuilder();
 
+    /**
+     * This variable is a temporary object used in
+     * {@link #commitTextWithBackgroundColor(CharSequence, int, int)} to avoid object creation.
+     */
+    private SpannableStringBuilder mTempObjectForCommitText = new SpannableStringBuilder();
+    /**
+     * This variable is used to track whether the last committed text had the background color or
+     * not.
+     * TODO: Omit this flag if possible.
+     */
+    private boolean mLastCommittedTextHasBackgroundColor = false;
+
     private final InputMethodService mParent;
     InputConnection mIC;
     int mNestLevel;
@@ -219,12 +235,37 @@
         // it works, but it's wrong and should be fixed.
         mCommittedTextBeforeComposingText.append(mComposingText);
         mComposingText.setLength(0);
+        // TODO: Clear this flag in setComposingRegion() and setComposingText() as well if needed.
+        mLastCommittedTextHasBackgroundColor = false;
         if (null != mIC) {
             mIC.finishComposingText();
         }
     }
 
-    public void commitText(final CharSequence text, final int i) {
+    /**
+     * Synonym of {@code commitTextWithBackgroundColor(text, newCursorPosition, Color.TRANSPARENT}.
+     * @param text The text to commit. This may include styles.
+     * See {@link InputConnection#commitText(CharSequence, int)}.
+     * @param newCursorPosition The new cursor position around the text.
+     * See {@link InputConnection#commitText(CharSequence, int)}.
+     */
+    public void commitText(final CharSequence text, final int newCursorPosition) {
+        commitTextWithBackgroundColor(text, newCursorPosition, Color.TRANSPARENT);
+    }
+
+    /**
+     * Calls {@link InputConnection#commitText(CharSequence, int)} with the given background color.
+     * @param text The text to commit. This may include styles.
+     * See {@link InputConnection#commitText(CharSequence, int)}.
+     * @param newCursorPosition The new cursor position around the text.
+     * See {@link InputConnection#commitText(CharSequence, int)}.
+     * @param color The background color to be attached. Set {@link Color#TRANSPARENT} to disable
+     * the background color. Note that this method specifies {@link BackgroundColorSpan} with
+     * {@link Spanned#SPAN_COMPOSING} flag, meaning that the background color persists until
+     * {@link #finishComposingText()} is called.
+     */
+    public void commitTextWithBackgroundColor(final CharSequence text, final int newCursorPosition,
+            final int color) {
         if (DEBUG_BATCH_NESTING) checkBatchEdit();
         if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug();
         mCommittedTextBeforeComposingText.append(text);
@@ -234,11 +275,43 @@
         mExpectedSelStart += text.length() - mComposingText.length();
         mExpectedSelEnd = mExpectedSelStart;
         mComposingText.setLength(0);
+        mLastCommittedTextHasBackgroundColor = false;
         if (null != mIC) {
-            mIC.commitText(text, i);
+            if (color == Color.TRANSPARENT) {
+                mIC.commitText(text, newCursorPosition);
+            } else {
+                mTempObjectForCommitText.clear();
+                mTempObjectForCommitText.append(text);
+                final BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(color);
+                mTempObjectForCommitText.setSpan(backgroundColorSpan, 0, text.length(),
+                        Spanned.SPAN_COMPOSING | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                mIC.commitText(mTempObjectForCommitText, newCursorPosition);
+                mLastCommittedTextHasBackgroundColor = true;
+            }
         }
     }
 
+    /**
+     * Removes the background color from the highlighted text if necessary. Should be called while
+     * there is no on-going composing text.
+     *
+     * <p>CAVEAT: This method internally calls {@link InputConnection#finishComposingText()}.
+     * Be careful of any unexpected side effects.</p>
+     */
+    public void removeBackgroundColorFromHighlightedTextIfNecessary() {
+        // TODO: We haven't yet full tested if we really need to check this flag or not. Omit this
+        // flag if everything works fine without this condition.
+        if (!mLastCommittedTextHasBackgroundColor) {
+            return;
+        }
+        if (mComposingText.length() > 0) {
+            Log.e(TAG, "clearSpansWithComposingFlags should be called when composing text is " +
+                    "empty. mComposingText=" + mComposingText);
+            return;
+        }
+        finishComposingText();
+    }
+
     public CharSequence getSelectedText(final int flags) {
         return (null == mIC) ? null : mIC.getSelectedText(flags);
     }
diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
index e43c182..0d5ce7d 100644
--- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
+++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
@@ -298,10 +298,14 @@
         return INDEX_NOT_FOUND;
     }
 
-    public InputMethodSubtype getCurrentInputMethodSubtype(
-            final InputMethodSubtype defaultSubtype) {
+    public RichInputMethodSubtype getCurrentInputMethodSubtype(
+            final RichInputMethodSubtype defaultSubtype) {
         final InputMethodSubtype currentSubtype = mImmWrapper.mImm.getCurrentInputMethodSubtype();
-        return (currentSubtype != null) ? currentSubtype : defaultSubtype;
+        if (currentSubtype == null) {
+            return defaultSubtype;
+        }
+        // TODO: Determine locales to use for multi-lingual use.
+        return new RichInputMethodSubtype(currentSubtype);
     }
 
     public boolean hasMultipleEnabledIMEsOrSubtypes(final boolean shouldIncludeAuxiliarySubtypes) {
diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java b/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java
new file mode 100644
index 0000000..0b08c48
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/RichInputMethodSubtype.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.latin.utils.LocaleUtils;
+import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * Enrichment class for InputMethodSubtype to enable concurrent multi-lingual input.
+ *
+ * Right now, this returns the extra value of its primary subtype.
+ */
+public final class RichInputMethodSubtype {
+    private final InputMethodSubtype mSubtype;
+    private final Locale[] mLocales;
+
+    public RichInputMethodSubtype(final InputMethodSubtype subtype, final Locale... locales) {
+        mSubtype = subtype;
+        mLocales = new Locale[locales.length+1];
+        mLocales[0] = LocaleUtils.constructLocaleFromString(mSubtype.getLocale());
+        System.arraycopy(locales, 0, mLocales, 1, locales.length);
+    }
+
+    // Extra values are determined by the primary subtype. This is probably right, but
+    // we may have to revisit this later.
+    public String getExtraValueOf(final String key) {
+        return mSubtype.getExtraValueOf(key);
+    }
+
+    // The mode is also determined by the primary subtype.
+    public String getMode() {
+        return mSubtype.getMode();
+    }
+
+    public boolean isNoLanguage() {
+        if (mLocales.length > 1) {
+            return false;
+        }
+        return SubtypeLocaleUtils.NO_LANGUAGE.equals(mSubtype.getLocale());
+    }
+
+    public String getNameForLogging() {
+        return toString();
+    }
+
+    // InputMethodSubtype's display name for spacebar text in its locale.
+    //        isAdditionalSubtype (T=true, F=false)
+    // locale layout  |  Middle      Full
+    // ------ ------- - --------- ----------------------
+    //  en_US qwerty  F  English   English (US)           exception
+    //  en_GB qwerty  F  English   English (UK)           exception
+    //  es_US spanish F  Español   Español (EE.UU.)       exception
+    //  fr    azerty  F  Français  Français
+    //  fr_CA qwerty  F  Français  Français (Canada)
+    //  fr_CH swiss   F  Français  Français (Suisse)
+    //  de    qwertz  F  Deutsch   Deutsch
+    //  de_CH swiss   T  Deutsch   Deutsch (Schweiz)
+    //  zz    qwerty  F  QWERTY    QWERTY
+    //  fr    qwertz  T  Français  Français
+    //  de    qwerty  T  Deutsch   Deutsch
+    //  en_US azerty  T  English   English (US)
+    //  zz    azerty  T  AZERTY    AZERTY
+    // Get the RichInputMethodSubtype's full display name in its locale.
+    public String getFullDisplayName() {
+        if (isNoLanguage()) {
+            return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(mSubtype);
+        }
+        return SubtypeLocaleUtils.getSubtypeLocaleDisplayName(mSubtype.getLocale());
+    }
+
+    // Get the RichInputMethodSubtype's middle display name in its locale.
+    public String getMiddleDisplayName() {
+        if (isNoLanguage()) {
+            return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(mSubtype);
+        }
+        return SubtypeLocaleUtils.getSubtypeLanguageDisplayName(mSubtype.getLocale());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof RichInputMethodSubtype)) {
+            return false;
+        }
+        final RichInputMethodSubtype other = (RichInputMethodSubtype)o;
+        return mSubtype.equals(other.mSubtype) && Arrays.equals(mLocales, other.mLocales);
+    }
+
+    @Override
+    public int hashCode() {
+        return mSubtype.hashCode() + Arrays.hashCode(mLocales);
+    }
+
+    @Override
+    public String toString() {
+        return "Multi-lingual subtype: " + mSubtype.toString() + ", " + Arrays.toString(mLocales);
+    }
+
+    // TODO: remove this method! We can always have several locales. Multi-lingual input will only
+    // be done when this method is gone.
+    public String getLocale() {
+        return mSubtype.getLocale();
+    }
+
+    // TODO: remove this method
+    public InputMethodSubtype getRawSubtype() { return mSubtype; }
+}
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index a725e16..45d67ff 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -58,8 +58,8 @@
             new LanguageOnSpacebarHelper();
     private InputMethodInfo mShortcutInputMethodInfo;
     private InputMethodSubtype mShortcutSubtype;
-    private InputMethodSubtype mNoLanguageSubtype;
-    private InputMethodSubtype mEmojiSubtype;
+    private RichInputMethodSubtype mNoLanguageSubtype;
+    private RichInputMethodSubtype mEmojiSubtype;
     private boolean mIsNetworkConnected;
 
     private static final String KEYBOARD_MODE = "keyboard";
@@ -70,26 +70,26 @@
             + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE
             + "," + Constants.Subtype.ExtraValue.ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE
             + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE;
-    private static final InputMethodSubtype DUMMY_NO_LANGUAGE_SUBTYPE =
-            InputMethodSubtypeCompatUtils.newInputMethodSubtype(
+    private static final RichInputMethodSubtype DUMMY_NO_LANGUAGE_SUBTYPE =
+            new RichInputMethodSubtype(InputMethodSubtypeCompatUtils.newInputMethodSubtype(
                     R.string.subtype_no_language_qwerty, R.drawable.ic_ime_switcher_dark,
                     SubtypeLocaleUtils.NO_LANGUAGE, KEYBOARD_MODE,
                     EXTRA_VALUE_OF_DUMMY_NO_LANGUAGE_SUBTYPE,
                     false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */,
-                    SUBTYPE_ID_OF_DUMMY_NO_LANGUAGE_SUBTYPE);
+                    SUBTYPE_ID_OF_DUMMY_NO_LANGUAGE_SUBTYPE));
     // Caveat: We probably should remove this when we add an Emoji subtype in {@link R.xml.method}.
     // Dummy Emoji subtype. See {@link R.xml.method}.
     private static final int SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE = 0xd78b2ed0;
     private static final String EXTRA_VALUE_OF_DUMMY_EMOJI_SUBTYPE =
             "KeyboardLayoutSet=" + SubtypeLocaleUtils.EMOJI
             + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE;
-    private static final InputMethodSubtype DUMMY_EMOJI_SUBTYPE =
+    private static final RichInputMethodSubtype DUMMY_EMOJI_SUBTYPE = new RichInputMethodSubtype(
             InputMethodSubtypeCompatUtils.newInputMethodSubtype(
                     R.string.subtype_emoji, R.drawable.ic_ime_switcher_dark,
                     SubtypeLocaleUtils.NO_LANGUAGE, KEYBOARD_MODE,
                     EXTRA_VALUE_OF_DUMMY_EMOJI_SUBTYPE,
                     false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */,
-                    SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE);
+                    SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE));
 
     public static SubtypeSwitcher getInstance() {
         return sInstance;
@@ -165,18 +165,17 @@
     }
 
     // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function.
-    public void onSubtypeChanged(final InputMethodSubtype newSubtype) {
+    public void onSubtypeChanged(final RichInputMethodSubtype newSubtype) {
         if (DBG) {
-            Log.w(TAG, "onSubtypeChanged: "
-                    + SubtypeLocaleUtils.getSubtypeNameForLogging(newSubtype));
+            Log.w(TAG, "onSubtypeChanged: " + newSubtype.getNameForLogging());
         }
 
         final Locale newLocale = SubtypeLocaleUtils.getSubtypeLocale(newSubtype);
         final Locale systemLocale = mResources.getConfiguration().locale;
         final boolean sameLocale = systemLocale.equals(newLocale);
         final boolean sameLanguage = systemLocale.getLanguage().equals(newLocale.getLanguage());
-        final boolean implicitlyEnabled =
-                mRichImm.checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype);
+        final boolean implicitlyEnabled = mRichImm
+                .checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype.getRawSubtype());
         mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(
                 sameLocale || (sameLanguage && implicitlyEnabled));
 
@@ -250,7 +249,7 @@
     // Subtype Switching functions //
     //////////////////////////////////
 
-    public int getLanguageOnSpacebarFormatType(final InputMethodSubtype subtype) {
+    public int getLanguageOnSpacebarFormatType(final RichInputMethodSubtype subtype) {
         return mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(subtype);
     }
 
@@ -279,10 +278,10 @@
         return true;
     }
 
-    private static InputMethodSubtype sForcedSubtypeForTesting = null;
+    private static RichInputMethodSubtype sForcedSubtypeForTesting = null;
     @UsedForTesting
     void forceSubtype(final InputMethodSubtype subtype) {
-        sForcedSubtypeForTesting = subtype;
+        sForcedSubtypeForTesting = new RichInputMethodSubtype(subtype);
     }
 
     public Locale getCurrentSubtypeLocale() {
@@ -292,17 +291,18 @@
         return SubtypeLocaleUtils.getSubtypeLocale(getCurrentSubtype());
     }
 
-    public InputMethodSubtype getCurrentSubtype() {
+    public RichInputMethodSubtype getCurrentSubtype() {
         if (null != sForcedSubtypeForTesting) {
             return sForcedSubtypeForTesting;
         }
         return mRichImm.getCurrentInputMethodSubtype(getNoLanguageSubtype());
     }
 
-    public InputMethodSubtype getNoLanguageSubtype() {
+    public RichInputMethodSubtype getNoLanguageSubtype() {
         if (mNoLanguageSubtype == null) {
-            mNoLanguageSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                    SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY);
+            mNoLanguageSubtype = new RichInputMethodSubtype(
+                    mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                            SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY));
         }
         if (mNoLanguageSubtype != null) {
             return mNoLanguageSubtype;
@@ -313,10 +313,14 @@
         return DUMMY_NO_LANGUAGE_SUBTYPE;
     }
 
-    public InputMethodSubtype getEmojiSubtype() {
+    public RichInputMethodSubtype getEmojiSubtype() {
         if (mEmojiSubtype == null) {
-            mEmojiSubtype = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                    SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.EMOJI);
+            final InputMethodSubtype rawEmojiSubtype =
+                    mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                        SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.EMOJI);
+            if (null != rawEmojiSubtype) {
+                mEmojiSubtype = new RichInputMethodSubtype(rawEmojiSubtype);
+            }
         }
         if (mEmojiSubtype != null) {
             return mEmojiSubtype;
@@ -328,6 +332,6 @@
     }
 
     public String getCombiningRulesExtraValueOfCurrentSubtype() {
-        return SubtypeLocaleUtils.getCombiningRulesExtraValue(getCurrentSubtype());
+        return SubtypeLocaleUtils.getCombiningRulesExtraValue(getCurrentSubtype().getRawSubtype());
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index d7693af..38fcb68 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -19,6 +19,7 @@
 import android.text.TextUtils;
 import android.view.inputmethod.CompletionInfo;
 
+import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.define.DebugFlags;
 import com.android.inputmethod.latin.utils.StringUtils;
 
@@ -420,4 +421,18 @@
                 mWillAutoCorrect, mIsObsoleteSuggestions, mIsPrediction,
                 INPUT_STYLE_TAIL_BATCH);
     }
+
+    /**
+     * @return the {@link SuggestedWordInfo} which corresponds to the word that is originally
+     * typed by the user. Otherwise returns {@code null}. Note that gesture input is not
+     * considered to be a typed word.
+     */
+    @UsedForTesting
+    public SuggestedWordInfo getTypedWordInfoOrNull() {
+        if (this == EMPTY) {
+            return null;
+        }
+        final SuggestedWordInfo info = getInfo(SuggestedWords.INDEX_OF_TYPED_WORD);
+        return (info.getKind() == SuggestedWordInfo.KIND_TYPED) ? info : null;
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 348bae6..616828e 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.latin.inputlogic;
 
+import android.graphics.Color;
 import android.os.SystemClock;
 import android.text.SpannableString;
 import android.text.TextUtils;
@@ -232,6 +233,20 @@
     }
 
     /**
+     * Determines whether "Touch again to save" should be shown or not.
+     * @param suggestionInfo the suggested word chosen by the user.
+     * @return {@code true} if we should show the "Touch again to save" hint.
+     */
+    private boolean shouldShowAddToDictionaryHint(final SuggestedWordInfo suggestionInfo) {
+        // We should show the "Touch again to save" hint if the user pressed the first entry
+        // AND it's in none of our current dictionaries (main, user or otherwise).
+        return (suggestionInfo.isKindOf(SuggestedWordInfo.KIND_TYPED)
+                || suggestionInfo.isKindOf(SuggestedWordInfo.KIND_OOV_CORRECTION))
+                && !mDictionaryFacilitator.isValidWord(suggestionInfo.mWord, true /* ignoreCase */)
+                && mDictionaryFacilitator.isUserDictionaryEnabled();
+    }
+
+    /**
      * A suggestion was picked from the suggestion strip.
      * @param settingsValues the current values of the settings.
      * @param suggestionInfo the suggestion info.
@@ -297,14 +312,7 @@
         mSpaceState = SpaceState.PHANTOM;
         inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
 
-        // We should show the "Touch again to save" hint if the user pressed the first entry
-        // AND it's in none of our current dictionaries (main, user or otherwise).
-        final boolean showingAddToDictionaryHint =
-                (suggestionInfo.isKindOf(SuggestedWordInfo.KIND_TYPED)
-                        || suggestionInfo.isKindOf(SuggestedWordInfo.KIND_OOV_CORRECTION))
-                        && !mDictionaryFacilitator.isValidWord(suggestion, true /* ignoreCase */);
-
-        if (showingAddToDictionaryHint && mDictionaryFacilitator.isUserDictionaryEnabled()) {
+        if (shouldShowAddToDictionaryHint(suggestionInfo)) {
             mSuggestionStripViewAccessor.showAddToDictionaryHint(suggestion);
         } else {
             // If we're not showing the "Touch again to save", then update the suggestion strip.
@@ -743,6 +751,13 @@
             final InputTransaction inputTransaction,
             // TODO: remove this argument
             final LatinIME.UIHandler handler) {
+        // In case the "add to dictionary" hint was still displayed.
+        // TODO: Do we really need to check if we have composing text here?
+        if (!mWordComposer.isComposingWord() &&
+                mSuggestionStripViewAccessor.isShowingAddToDictionaryHint()) {
+            mSuggestionStripViewAccessor.dismissAddToDictionaryHint();
+        }
+
         final int codePoint = event.mCodePoint;
         mSpaceState = SpaceState.NONE;
         if (inputTransaction.mSettingsValues.isWordSeparator(codePoint)
@@ -838,8 +853,6 @@
             } else {
                 sendKeyCodePoint(settingsValues, codePoint);
             }
-            // In case the "add to dictionary" hint was still displayed.
-            mSuggestionStripViewAccessor.dismissAddToDictionaryHint();
         }
         inputTransaction.setRequiresUpdateSuggestions();
     }
@@ -1994,7 +2007,9 @@
     }
 
     /**
-     * Commits the chosen word to the text field and saves it for later retrieval.
+     * Commits the chosen word to the text field and saves it for later retrieval. This is a
+     * synonym of {@code commitChosenWordWithBackgroundColor(settingsValues, chosenWord,
+     * commitType, separatorString, Color.TRANSPARENT}.
      *
      * @param settingsValues the current values of the settings.
      * @param chosenWord the word we want to commit.
@@ -2003,6 +2018,23 @@
      */
     private void commitChosenWord(final SettingsValues settingsValues, final String chosenWord,
             final int commitType, final String separatorString) {
+        commitChosenWordWithBackgroundColor(settingsValues, chosenWord, commitType, separatorString,
+                Color.TRANSPARENT);
+    }
+
+    /**
+     * Commits the chosen word to the text field and saves it for later retrieval.
+     *
+     * @param settingsValues the current values of the settings.
+     * @param chosenWord the word we want to commit.
+     * @param commitType the type of the commit, as one of LastComposedWord.COMMIT_TYPE_*
+     * @param separatorString the separator that's causing the commit, or NOT_A_SEPARATOR if none.
+     * @param backgroundColor the background color to be specified with the committed text. Pass
+     * {@link Color#TRANSPARENT} to not specify the background color.
+     */
+    private void commitChosenWordWithBackgroundColor(final SettingsValues settingsValues,
+            final String chosenWord, final int commitType, final String separatorString,
+            final int backgroundColor) {
         final SuggestedWords suggestedWords = mSuggestedWords;
         final CharSequence chosenWordWithSuggestions =
                 SuggestionSpanUtils.getTextWithSuggestionSpan(mLatinIME, chosenWord,
@@ -2012,7 +2044,7 @@
         // information from the 1st previous word.
         final PrevWordsInfo prevWordsInfo = mConnection.getPrevWordsInfoFromNthPreviousWord(
                 settingsValues.mSpacingAndPunctuations, mWordComposer.isComposingWord() ? 2 : 1);
-        mConnection.commitText(chosenWordWithSuggestions, 1);
+        mConnection.commitTextWithBackgroundColor(chosenWordWithSuggestions, 1, backgroundColor);
         // Add the word to the user history dictionary
         performAdditionToUserHistoryDictionary(settingsValues, chosenWord, prevWordsInfo);
         // TODO: figure out here if this is an auto-correct or if the best word is actually
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index c12474b..a9789d8 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -51,7 +51,7 @@
 
     // From resources:
     public final SpacingAndPunctuations mSpacingAndPunctuations;
-    public final int mDelayUpdateOldSuggestions;
+    public final int mDelayInMillisecondsToUpdateOldSuggestions;
     public final long mDoubleSpacePeriodTimeout;
 
     // From preferences, in the same order as xml/prefs.xml:
@@ -107,7 +107,8 @@
             final InputAttributes inputAttributes) {
         mLocale = res.getConfiguration().locale;
         // Get the resources
-        mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions);
+        mDelayInMillisecondsToUpdateOldSuggestions =
+                res.getInteger(R.integer.config_delay_in_milliseconds_to_update_old_suggestions);
         mSpacingAndPunctuations = new SpacingAndPunctuations(res);
 
         // Store the input attributes
@@ -337,8 +338,8 @@
         final StringBuilder sb = new StringBuilder("Current settings :");
         sb.append("\n   mSpacingAndPunctuations = ");
         sb.append("" + mSpacingAndPunctuations.dump());
-        sb.append("\n   mDelayUpdateOldSuggestions = ");
-        sb.append("" + mDelayUpdateOldSuggestions);
+        sb.append("\n   mDelayInMillisecondsToUpdateOldSuggestions = ");
+        sb.append("" + mDelayInMillisecondsToUpdateOldSuggestions);
         sb.append("\n   mAutoCap = ");
         sb.append("" + mAutoCap);
         sb.append("\n   mVibrateOn = ");
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 90398de..47bff3e 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -39,6 +39,7 @@
 import com.android.inputmethod.latin.DictionaryFactory;
 import com.android.inputmethod.latin.PrevWordsInfo;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
 import com.android.inputmethod.latin.UserBinaryDictionary;
@@ -334,7 +335,7 @@
         final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(this, editorInfo);
         builder.setKeyboardGeometry(
                 SPELLCHECKER_DUMMY_KEYBOARD_WIDTH, SPELLCHECKER_DUMMY_KEYBOARD_HEIGHT);
-        builder.setSubtype(subtype);
+        builder.setSubtype(new RichInputMethodSubtype(subtype));
         builder.setIsSpellChecker(true /* isSpellChecker */);
         builder.disableTouchPositionCorrectionData();
         return builder.build();
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index 346aea3..9d186d4 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -125,9 +125,9 @@
         }
 
         private static final int[][] COLUMN_ORDER_TO_NUMBER = {
-            { 0, },
-            { 1, 0, },
-            { 2, 0, 1},
+            { 0 }, // center
+            { 1, 0 }, // right-left
+            { 1, 0, 2 }, // center-left-right
         };
 
         public int getNumColumnInRow(final int index) {
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index 7307ca1..1e8df89 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -45,11 +45,14 @@
 import android.widget.TextView;
 
 import com.android.inputmethod.accessibility.AccessibilityUtils;
+import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.PunctuationSuggestions;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SuggestedWords;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.define.DebugFlags;
+import com.android.inputmethod.latin.settings.Settings;
+import com.android.inputmethod.latin.settings.SettingsValues;
 import com.android.inputmethod.latin.utils.AutoCorrectionUtils;
 import com.android.inputmethod.latin.utils.ResourceUtils;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
@@ -72,7 +75,7 @@
     private int mMaxMoreSuggestionsRow;
     public final float mMinMoreSuggestionsWidth;
     public final int mMoreSuggestionsBottomGap;
-    public boolean mMoreSuggestionsAvailable;
+    private boolean mMoreSuggestionsAvailable;
 
     // The index of these {@link ArrayList} is the position in the suggestion strip. The indices
     // increase towards the right for LTR scripts and the left for RTL scripts, starting with 0.
@@ -223,11 +226,59 @@
         return spannedWord;
     }
 
+    /**
+     * Convert an index of {@link SuggestedWords} to position in the suggestion strip.
+     * @param indexInSuggestedWords the index of {@link SuggestedWords}.
+     * @param suggestedWords the suggested words list
+     * @return Non-negative integer of the position in the suggestion strip.
+     *         Negative integer if the word of the index shouldn't be shown on the suggestion strip.
+     */
     private int getPositionInSuggestionStrip(final int indexInSuggestedWords,
             final SuggestedWords suggestedWords) {
+        final SettingsValues settingsValues = Settings.getInstance().getCurrent();
+        final boolean shouldOmitTypedWord = shouldOmitTypedWord(suggestedWords.mInputStyle,
+                settingsValues.mGestureFloatingPreviewTextEnabled,
+                settingsValues.mShouldShowUiToAcceptTypedWord);
+        return getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords.mWillAutoCorrect,
+                settingsValues.mShouldShowUiToAcceptTypedWord && shouldOmitTypedWord,
+                mCenterPositionInStrip, mTypedWordPositionWhenAutocorrect);
+    }
+
+    @UsedForTesting
+    static boolean shouldOmitTypedWord(final int inputStyle,
+            final boolean gestureFloatingPreviewTextEnabled,
+            final boolean shouldShowUiToAcceptTypedWord) {
+        final boolean omitTypedWord = (inputStyle == SuggestedWords.INPUT_STYLE_TYPING)
+                || (inputStyle == SuggestedWords.INPUT_STYLE_TAIL_BATCH)
+                || (inputStyle == SuggestedWords.INPUT_STYLE_UPDATE_BATCH
+                        && gestureFloatingPreviewTextEnabled);
+        return shouldShowUiToAcceptTypedWord && omitTypedWord;
+    }
+
+    @UsedForTesting
+    static int getPositionInSuggestionStrip(final int indexInSuggestedWords,
+            final boolean willAutoCorrect, final boolean omitTypedWord,
+            final int centerPositionInStrip, final int typedWordPositionWhenAutoCorrect) {
+        if (omitTypedWord) {
+            if (indexInSuggestedWords == SuggestedWords.INDEX_OF_TYPED_WORD) {
+                // Ignore.
+                return -1;
+            }
+            if (indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION) {
+                // Center in the suggestion strip.
+                return centerPositionInStrip;
+            }
+            // If neither of those, the order in the suggestion strip is left of the center first
+            // then right of the center, to both edges of the suggestion strip.
+            // For example, center-1, center+1, center-2, center+2, and so on.
+            final int n = indexInSuggestedWords;
+            final int offsetFromCenter = (n % 2) == 0 ? -(n / 2) : (n / 2);
+            final int positionInSuggestionStrip = centerPositionInStrip + offsetFromCenter;
+            return positionInSuggestionStrip;
+        }
         final int indexToDisplayMostImportantSuggestion;
         final int indexToDisplaySecondMostImportantSuggestion;
-        if (suggestedWords.mWillAutoCorrect) {
+        if (willAutoCorrect) {
             indexToDisplayMostImportantSuggestion = SuggestedWords.INDEX_OF_AUTO_CORRECTION;
             indexToDisplaySecondMostImportantSuggestion = SuggestedWords.INDEX_OF_TYPED_WORD;
         } else {
@@ -235,25 +286,31 @@
             indexToDisplaySecondMostImportantSuggestion = SuggestedWords.INDEX_OF_AUTO_CORRECTION;
         }
         if (indexInSuggestedWords == indexToDisplayMostImportantSuggestion) {
-            return mCenterPositionInStrip;
+            // Center in the suggestion strip.
+            return centerPositionInStrip;
         }
         if (indexInSuggestedWords == indexToDisplaySecondMostImportantSuggestion) {
-            return mTypedWordPositionWhenAutocorrect;
+            // Center-1.
+            return typedWordPositionWhenAutoCorrect;
         }
-        // If neither of those, the order in the suggestion strip is the same as in SuggestedWords.
-        return indexInSuggestedWords;
+        // If neither of those, the order in the suggestion strip is right of the center first
+        // then left of the center, to both edges of the suggestion strip.
+        // For example, Center+1, center-2, center+2, center-3, and so on.
+        final int n = indexInSuggestedWords + 1;
+        final int offsetFromCenter = (n % 2) == 0 ? -(n / 2) : (n / 2);
+        final int positionInSuggestionStrip = centerPositionInStrip + offsetFromCenter;
+        return positionInSuggestionStrip;
     }
 
     private int getSuggestionTextColor(final SuggestedWords suggestedWords,
             final int indexInSuggestedWords) {
-        final int positionInStrip =
-                getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords);
         // Use identity for strings, not #equals : it's the typed word if it's the same object
         final boolean isTypedWord = suggestedWords.getInfo(indexInSuggestedWords).isKindOf(
                 SuggestedWordInfo.KIND_TYPED);
 
         final int color;
-        if (positionInStrip == mCenterPositionInStrip && suggestedWords.mWillAutoCorrect) {
+        if (indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION
+                && suggestedWords.mWillAutoCorrect) {
             color = mColorAutoCorrect;
         } else if (isTypedWord && suggestedWords.mTypedWordValid) {
             color = mColorValidTypedWord;
@@ -265,7 +322,8 @@
         if (DebugFlags.DEBUG_ENABLED && suggestedWords.size() > 1) {
             // If we auto-correct, then the autocorrection is in slot 0 and the typed word
             // is in slot 1.
-            if (positionInStrip == mCenterPositionInStrip
+            if (indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION
+                    && suggestedWords.mWillAutoCorrect
                     && AutoCorrectionUtils.shouldBlockAutoCorrectionBySafetyNet(
                             suggestedWords.getLabel(SuggestedWords.INDEX_OF_AUTO_CORRECTION),
                             suggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD))) {
@@ -292,31 +350,31 @@
     }
 
     /**
-     * Layout suggestions to the suggestions strip. And returns the number of suggestions displayed
-     * in the suggestions strip.
+     * Layout suggestions to the suggestions strip. And returns the start index of more
+     * suggestions.
      *
      * @param suggestedWords suggestions to be shown in the suggestions strip.
      * @param stripView the suggestions strip view.
      * @param placerView the view where the debug info will be placed.
-     * @return the number of suggestions displayed in the suggestions strip
+     * @return the start index of more suggestions.
      */
-    public int layoutAndReturnSuggestionCountInStrip(final SuggestedWords suggestedWords,
+    public int layoutAndReturnStartIndexOfMoreSuggestions(final SuggestedWords suggestedWords,
             final ViewGroup stripView, final ViewGroup placerView) {
         if (suggestedWords.isPunctuationSuggestions()) {
-            return layoutPunctuationSuggestionsAndReturnSuggestionCountInStrip(
+            return layoutPunctuationsAndReturnStartIndexOfMoreSuggestions(
                     (PunctuationSuggestions)suggestedWords, stripView);
         }
 
-        setupWordViewsTextAndColor(suggestedWords, mSuggestionsCountInStrip);
+        final int startIndexOfMoreSuggestions = setupWordViewsAndReturnStartIndexOfMoreSuggestions(
+                suggestedWords, mSuggestionsCountInStrip);
         final TextView centerWordView = mWordViews.get(mCenterPositionInStrip);
         final int stripWidth = stripView.getWidth();
         final int centerWidth = getSuggestionWidth(mCenterPositionInStrip, stripWidth);
-        final int countInStrip;
         if (suggestedWords.size() == 1 || getTextScaleX(centerWordView.getText(), centerWidth,
                 centerWordView.getPaint()) < MIN_TEXT_XSCALE) {
             // Layout only the most relevant suggested word at the center of the suggestion strip
             // by consolidating all slots in the strip.
-            countInStrip = 1;
+            final int countInStrip = 1;
             mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip);
             layoutWord(mCenterPositionInStrip, stripWidth - mPadding);
             stripView.addView(centerWordView);
@@ -324,31 +382,33 @@
             if (SuggestionStripView.DBG) {
                 layoutDebugInfo(mCenterPositionInStrip, placerView, stripWidth);
             }
-        } else {
-            countInStrip = mSuggestionsCountInStrip;
-            mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip);
-            int x = 0;
-            for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) {
-                if (positionInStrip != 0) {
-                    final View divider = mDividerViews.get(positionInStrip);
-                    // Add divider if this isn't the left most suggestion in suggestions strip.
-                    addDivider(stripView, divider);
-                    x += divider.getMeasuredWidth();
-                }
+            final Integer lastIndex = (Integer)centerWordView.getTag();
+            return (lastIndex == null ? 0 : lastIndex) + 1;
+        }
 
-                final int width = getSuggestionWidth(positionInStrip, stripWidth);
-                final TextView wordView = layoutWord(positionInStrip, width);
-                stripView.addView(wordView);
-                setLayoutWeight(wordView, getSuggestionWeight(positionInStrip),
-                        ViewGroup.LayoutParams.MATCH_PARENT);
-                x += wordView.getMeasuredWidth();
+        final int countInStrip = mSuggestionsCountInStrip;
+        mMoreSuggestionsAvailable = (suggestedWords.size() > countInStrip);
+        int x = 0;
+        for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) {
+            if (positionInStrip != 0) {
+                final View divider = mDividerViews.get(positionInStrip);
+                // Add divider if this isn't the left most suggestion in suggestions strip.
+                addDivider(stripView, divider);
+                x += divider.getMeasuredWidth();
+            }
 
-                if (SuggestionStripView.DBG) {
-                    layoutDebugInfo(positionInStrip, placerView, x);
-                }
+            final int width = getSuggestionWidth(positionInStrip, stripWidth);
+            final TextView wordView = layoutWord(positionInStrip, width);
+            stripView.addView(wordView);
+            setLayoutWeight(wordView, getSuggestionWeight(positionInStrip),
+                    ViewGroup.LayoutParams.MATCH_PARENT);
+            x += wordView.getMeasuredWidth();
+
+            if (SuggestionStripView.DBG) {
+                layoutDebugInfo(positionInStrip, placerView, x);
             }
         }
-        return countInStrip;
+        return startIndexOfMoreSuggestions;
     }
 
     /**
@@ -426,10 +486,10 @@
         return (1.0f - mCenterSuggestionWeight) / (mSuggestionsCountInStrip - 1);
     }
 
-    private void setupWordViewsTextAndColor(final SuggestedWords suggestedWords,
-            final int countInStrip) {
+    private int setupWordViewsAndReturnStartIndexOfMoreSuggestions(
+            final SuggestedWords suggestedWords, final int maxSuggestionInStrip) {
         // Clear all suggestions first
-        for (int positionInStrip = 0; positionInStrip < countInStrip; ++positionInStrip) {
+        for (int positionInStrip = 0; positionInStrip < maxSuggestionInStrip; ++positionInStrip) {
             final TextView wordView = mWordViews.get(positionInStrip);
             wordView.setText(null);
             wordView.setTag(null);
@@ -438,11 +498,15 @@
                 mDebugInfoViews.get(positionInStrip).setText(null);
             }
         }
-        final int count = Math.min(suggestedWords.size(), countInStrip);
-        for (int indexInSuggestedWords = 0; indexInSuggestedWords < count;
-                indexInSuggestedWords++) {
+        int count = 0;
+        int indexInSuggestedWords;
+        for (indexInSuggestedWords = 0; indexInSuggestedWords < suggestedWords.size()
+                && count < maxSuggestionInStrip; indexInSuggestedWords++) {
             final int positionInStrip =
                     getPositionInSuggestionStrip(indexInSuggestedWords, suggestedWords);
+            if (positionInStrip < 0) {
+                continue;
+            }
             final TextView wordView = mWordViews.get(positionInStrip);
             // {@link TextView#getTag()} is used to get the index in suggestedWords at
             // {@link SuggestionStripView#onClick(View)}.
@@ -453,10 +517,12 @@
                 mDebugInfoViews.get(positionInStrip).setText(
                         suggestedWords.getDebugString(indexInSuggestedWords));
             }
+            count++;
         }
+        return indexInSuggestedWords;
     }
 
-    private int layoutPunctuationSuggestionsAndReturnSuggestionCountInStrip(
+    private int layoutPunctuationsAndReturnStartIndexOfMoreSuggestions(
             final PunctuationSuggestions punctuationSuggestions, final ViewGroup stripView) {
         final int countInStrip = Math.min(punctuationSuggestions.size(), PUNCTUATIONS_IN_STRIP);
         for (int positionInStrip = 0; positionInStrip < countInStrip; positionInStrip++) {
@@ -483,8 +549,11 @@
     }
 
     public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip) {
+        final boolean shouldShowUiToAcceptTypedWord = Settings.getInstance().getCurrent()
+                .mShouldShowUiToAcceptTypedWord;
         final int stripWidth = addToDictionaryStrip.getWidth();
-        final int width = stripWidth - mDividerWidth - mPadding * 2;
+        final int width = shouldShowUiToAcceptTypedWord ? stripWidth
+                : stripWidth - mDividerWidth - mPadding * 2;
 
         final TextView wordView = (TextView)addToDictionaryStrip.findViewById(R.id.word_to_save);
         wordView.setTextColor(mColorTypedWord);
@@ -494,25 +563,38 @@
         wordView.setText(wordToSave);
         wordView.setTextScaleX(wordScaleX);
         setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
+        final int wordVisibility = shouldShowUiToAcceptTypedWord ? View.GONE : View.VISIBLE;
+        wordView.setVisibility(wordVisibility);
+        addToDictionaryStrip.findViewById(R.id.word_to_save_divider).setVisibility(wordVisibility);
 
+        final Resources res = addToDictionaryStrip.getResources();
+        final CharSequence hintText;
+        final int hintWidth;
+        final float hintWeight;
         final TextView hintView = (TextView)addToDictionaryStrip.findViewById(
                 R.id.hint_add_to_dictionary);
+        if (shouldShowUiToAcceptTypedWord) {
+            hintText = res.getText(R.string.hint_add_to_dictionary_without_word);
+            hintWidth = width;
+            hintWeight = 1.0f;
+            hintView.setGravity(Gravity.CENTER);
+        } else {
+            final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip)
+                    == ViewCompat.LAYOUT_DIRECTION_RTL);
+            final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW;
+            final boolean isRtlSystem = SubtypeLocaleUtils.isRtlLanguage(
+                    res.getConfiguration().locale);
+            final CharSequence hint = res.getText(R.string.hint_add_to_dictionary);
+            hintText = (isRtlLanguage == isRtlSystem) ? (arrow + hint) : (hint + arrow);
+            hintWidth = width - wordWidth;
+            hintWeight = 1.0f - mCenterSuggestionWeight;
+            hintView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
+        }
         hintView.setTextColor(mColorAutoCorrect);
-        final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip)
-                == ViewCompat.LAYOUT_DIRECTION_RTL);
-        final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW;
-        final Resources res = addToDictionaryStrip.getResources();
-        final boolean isRtlSystem = SubtypeLocaleUtils.isRtlLanguage(res.getConfiguration().locale);
-        final CharSequence hintText = res.getText(R.string.hint_add_to_dictionary);
-        final String hintWithArrow = (isRtlLanguage == isRtlSystem)
-                ? (arrow + hintText) : (hintText + arrow);
-        final int hintWidth = width - wordWidth;
-        hintView.setTextScaleX(1.0f); // Reset textScaleX.
-        final float hintScaleX = getTextScaleX(hintWithArrow, hintWidth, hintView.getPaint());
-        hintView.setText(hintWithArrow);
+        final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint());
+        hintView.setText(hintText);
         hintView.setTextScaleX(hintScaleX);
-        setLayoutWeight(
-                hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
+        setLayoutWeight(hintView, hintWeight, ViewGroup.LayoutParams.MATCH_PARENT);
     }
 
     public void layoutImportantNotice(final View importantNoticeStrip,
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index 9b8c38a..33745a8 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -83,7 +83,7 @@
 
     Listener mListener;
     private SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
-    private int mSuggestionsCountInStrip;
+    private int mStartIndexOfMoreSuggestions;
 
     private final SuggestionStripLayoutHelper mLayoutHelper;
     private final StripVisibilityGroup mStripVisibilityGroup;
@@ -214,7 +214,7 @@
         clear();
         mStripVisibilityGroup.setLayoutDirection(isRtlLanguage);
         mSuggestedWords = suggestedWords;
-        mSuggestionsCountInStrip = mLayoutHelper.layoutAndReturnSuggestionCountInStrip(
+        mStartIndexOfMoreSuggestions = mLayoutHelper.layoutAndReturnStartIndexOfMoreSuggestions(
                 mSuggestedWords, mSuggestionsStrip, this);
         mStripVisibilityGroup.showSuggestionsStrip();
     }
@@ -337,7 +337,7 @@
             return false;
         }
         final SuggestionStripLayoutHelper layoutHelper = mLayoutHelper;
-        if (!layoutHelper.mMoreSuggestionsAvailable) {
+        if (mSuggestedWords.size() <= mStartIndexOfMoreSuggestions) {
             return false;
         }
         // Dismiss another {@link MoreKeysPanel} that may be being showed, for example
@@ -350,7 +350,7 @@
         final View container = mMoreSuggestionsContainer;
         final int maxWidth = stripWidth - container.getPaddingLeft() - container.getPaddingRight();
         final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder;
-        builder.layout(mSuggestedWords, mSuggestionsCountInStrip, maxWidth,
+        builder.layout(mSuggestedWords, mStartIndexOfMoreSuggestions, maxWidth,
                 (int)(maxWidth * layoutHelper.mMinMoreSuggestionsWidth),
                 layoutHelper.getMaxMoreSuggestionsRow(), parentKeyboard);
         mMoreSuggestionsView.setKeyboard(builder.build());
@@ -363,7 +363,7 @@
                 mMoreSuggestionsListener);
         mOriginX = mLastX;
         mOriginY = mLastY;
-        for (int i = 0; i < mSuggestionsCountInStrip; i++) {
+        for (int i = 0; i < mStartIndexOfMoreSuggestions; i++) {
             mWordViews.get(i).setPressed(false);
         }
         return true;
diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
index 2797328..2207ffe 100644
--- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
@@ -35,6 +35,7 @@
 import com.android.inputmethod.keyboard.KeyboardLayoutSet;
 import com.android.inputmethod.latin.DictionaryFacilitator;
 import com.android.inputmethod.latin.PrevWordsInfo;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.WordComposer;
 import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
@@ -131,7 +132,7 @@
         final int keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res);
         final int keyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res);
         builder.setKeyboardGeometry(keyboardWidth, keyboardHeight);
-        builder.setSubtype(subtype);
+        builder.setSubtype(new RichInputMethodSubtype(subtype));
         builder.setIsSpellChecker(false /* isSpellChecker */);
         final KeyboardLayoutSet layoutSet = builder.build();
         mKeyboard = layoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
diff --git a/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java b/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java
deleted file mode 100644
index 1ca895f..0000000
--- a/java/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtils.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.latin.utils;
-
-import android.view.inputmethod.InputMethodSubtype;
-
-public final class SpacebarLanguageUtils {
-    private SpacebarLanguageUtils() {
-        // Intentional empty constructor for utility class.
-    }
-
-    // InputMethodSubtype's display name for spacebar text in its locale.
-    //        isAdditionalSubtype (T=true, F=false)
-    // locale layout  |  Middle      Full
-    // ------ ------- - --------- ----------------------
-    //  en_US qwerty  F  English   English (US)           exception
-    //  en_GB qwerty  F  English   English (UK)           exception
-    //  es_US spanish F  Español   Español (EE.UU.)       exception
-    //  fr    azerty  F  Français  Français
-    //  fr_CA qwerty  F  Français  Français (Canada)
-    //  fr_CH swiss   F  Français  Français (Suisse)
-    //  de    qwertz  F  Deutsch   Deutsch
-    //  de_CH swiss   T  Deutsch   Deutsch (Schweiz)
-    //  zz    qwerty  F  QWERTY    QWERTY
-    //  fr    qwertz  T  Français  Français
-    //  de    qwerty  T  Deutsch   Deutsch
-    //  en_US azerty  T  English   English (US)
-    //  zz    azerty  T  AZERTY    AZERTY
-    // Get InputMethodSubtype's full display name in its locale.
-    public static String getFullDisplayName(final InputMethodSubtype subtype) {
-        if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
-            return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype);
-        }
-        return SubtypeLocaleUtils.getSubtypeLocaleDisplayName(subtype.getLocale());
-    }
-
-    // Get InputMethodSubtype's middle display name in its locale.
-    public static String getMiddleDisplayName(final InputMethodSubtype subtype) {
-        if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
-            return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype);
-        }
-        return SubtypeLocaleUtils.getSubtypeLanguageDisplayName(subtype.getLocale());
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
index 0db4106..96a6510 100644
--- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
@@ -27,12 +27,17 @@
 
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
 
+/**
+ * A helper class to deal with subtype locales.
+  */
+// TODO: consolidate this into RichInputMethodSubtype
 public final class SubtypeLocaleUtils {
     private static final String TAG = SubtypeLocaleUtils.class.getSimpleName();
 
@@ -109,10 +114,10 @@
             sKeyboardLayoutToNameIdsMap.put(key, noLanguageResId);
         }
 
-        final String[] excetionalLocaleInRootLocale = res.getStringArray(
+        final String[] exceptionalLocaleInRootLocale = res.getStringArray(
                 R.array.subtype_locale_displayed_in_root_locale);
-        for (int i = 0; i < excetionalLocaleInRootLocale.length; i++) {
-            sExceptionalLocaleDisplayedInRootLocale.add(excetionalLocaleInRootLocale[i]);
+        for (int i = 0; i < exceptionalLocaleInRootLocale.length; i++) {
+            sExceptionalLocaleDisplayedInRootLocale.add(exceptionalLocaleInRootLocale[i]);
         }
 
         final String[] exceptionalLocales = res.getStringArray(
@@ -260,6 +265,7 @@
     private static String getSubtypeDisplayNameInternal(final InputMethodSubtype subtype,
             final Locale displayLocale) {
         final String replacementString = getReplacementString(subtype, displayLocale);
+        // TODO: rework this for multi-lingual subtypes
         final int nameResId = subtype.getNameResId();
         final RunInLocale<String> getSubtypeName = new RunInLocale<String>() {
             @Override
@@ -282,12 +288,14 @@
                 getSubtypeName.runInLocale(sResources, displayLocale), displayLocale);
     }
 
-    public static boolean isNoLanguage(final InputMethodSubtype subtype) {
+    public static Locale getSubtypeLocale(final InputMethodSubtype subtype) {
         final String localeString = subtype.getLocale();
-        return NO_LANGUAGE.equals(localeString);
+        return LocaleUtils.constructLocaleFromString(localeString);
     }
 
-    public static Locale getSubtypeLocale(final InputMethodSubtype subtype) {
+    // TODO: remove this. When RichInputMethodSubtype#getLocale is removed we can do away with this
+    // method at the same time.
+    public static Locale getSubtypeLocale(final RichInputMethodSubtype subtype) {
         final String localeString = subtype.getLocale();
         return LocaleUtils.constructLocaleFromString(localeString);
     }
@@ -301,6 +309,10 @@
         return sKeyboardLayoutToDisplayNameMap.get(layoutName);
     }
 
+    public static String getKeyboardLayoutSetName(final RichInputMethodSubtype subtype) {
+        return getKeyboardLayoutSetName(subtype.getRawSubtype());
+    }
+
     public static String getKeyboardLayoutSetName(final InputMethodSubtype subtype) {
         String keyboardLayoutSet = subtype.getExtraValueOf(KEYBOARD_LAYOUT_SET);
         if (keyboardLayoutSet == null) {
@@ -336,7 +348,7 @@
         return Arrays.binarySearch(SORTED_RTL_LANGUAGES, language) >= 0;
     }
 
-    public static boolean isRtlLanguage(final InputMethodSubtype subtype) {
+    public static boolean isRtlLanguage(final RichInputMethodSubtype subtype) {
         return isRtlLanguage(getSubtypeLocale(subtype));
     }
 
diff --git a/native/jni/NativeFileList.mk b/native/jni/NativeFileList.mk
index 7a732a5..4a89b2b 100644
--- a/native/jni/NativeFileList.mk
+++ b/native/jni/NativeFileList.mk
@@ -128,6 +128,7 @@
     suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp \
     suggest/policyimpl/dictionary/structure/v4/content/probability_entry_test.cpp \
     suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer_test.cpp \
+    suggest/policyimpl/dictionary/utils/byte_array_utils_test.cpp \
     suggest/policyimpl/dictionary/utils/trie_map_test.cpp \
     utils/autocorrection_threshold_utils_test.cpp \
     utils/int_array_view_test.cpp
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp
index bbcea2e..ea2d24e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp
@@ -16,6 +16,11 @@
 
 #include "suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h"
 
+#include <algorithm>
+#include <cstring>
+
+#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h"
+
 namespace latinime {
 
 bool LanguageModelDictContent::save(FILE *const file) const {
@@ -66,6 +71,19 @@
     return mTrieMap.remove(wordId, bitmapEntryIndex);
 }
 
+bool LanguageModelDictContent::truncateEntries(const int *const entryCounts,
+        const int *const maxEntryCounts, const HeaderPolicy *const headerPolicy) {
+    for (int i = 0; i <= MAX_PREV_WORD_COUNT_FOR_N_GRAM; ++i) {
+        if (entryCounts[i] <= maxEntryCounts[i]) {
+            continue;
+        }
+        if (!turncateEntriesInSpecifiedLevel(headerPolicy, maxEntryCounts[i], i)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 bool LanguageModelDictContent::runGCInner(
         const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap,
         const TrieMap::TrieMapRange trieMapRange,
@@ -118,4 +136,129 @@
     return bitmapEntryIndex;
 }
 
+bool LanguageModelDictContent::updateAllProbabilityEntriesInner(const int bitmapEntryIndex,
+        const int level, const HeaderPolicy *const headerPolicy, int *const outEntryCounts) {
+    for (const auto &entry : mTrieMap.getEntriesInSpecifiedLevel(bitmapEntryIndex)) {
+        if (level > MAX_PREV_WORD_COUNT_FOR_N_GRAM) {
+            AKLOGE("Invalid level. level: %d, MAX_PREV_WORD_COUNT_FOR_N_GRAM: %d.",
+                    level, MAX_PREV_WORD_COUNT_FOR_N_GRAM);
+            return false;
+        }
+        const ProbabilityEntry probabilityEntry =
+                ProbabilityEntry::decode(entry.value(), mHasHistoricalInfo);
+        if (mHasHistoricalInfo && !probabilityEntry.representsBeginningOfSentence()) {
+            const HistoricalInfo historicalInfo = ForgettingCurveUtils::createHistoricalInfoToSave(
+                    probabilityEntry.getHistoricalInfo(), headerPolicy);
+            if (ForgettingCurveUtils::needsToKeep(&historicalInfo, headerPolicy)) {
+                // Update the entry.
+                const ProbabilityEntry updatedEntry(probabilityEntry.getFlags(), &historicalInfo);
+                if (!mTrieMap.put(entry.key(), updatedEntry.encode(mHasHistoricalInfo),
+                        bitmapEntryIndex)) {
+                    return false;
+                }
+            } else {
+                // Remove the entry.
+                if (!mTrieMap.remove(entry.key(), bitmapEntryIndex)) {
+                    return false;
+                }
+                continue;
+            }
+        }
+        if (!probabilityEntry.representsBeginningOfSentence()) {
+            outEntryCounts[level] += 1;
+        }
+        if (!entry.hasNextLevelMap()) {
+            continue;
+        }
+        if (!updateAllProbabilityEntriesInner(entry.getNextLevelBitmapEntryIndex(), level + 1,
+                headerPolicy, outEntryCounts)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool LanguageModelDictContent::turncateEntriesInSpecifiedLevel(
+        const HeaderPolicy *const headerPolicy, const int maxEntryCount, const int targetLevel) {
+    std::vector<int> prevWordIds;
+    std::vector<EntryInfoToTurncate> entryInfoVector;
+    if (!getEntryInfo(headerPolicy, targetLevel, mTrieMap.getRootBitmapEntryIndex(),
+            &prevWordIds, &entryInfoVector)) {
+        return false;
+    }
+    if (static_cast<int>(entryInfoVector.size()) <= maxEntryCount) {
+        return true;
+    }
+    const int entryCountToRemove = static_cast<int>(entryInfoVector.size()) - maxEntryCount;
+    std::partial_sort(entryInfoVector.begin(), entryInfoVector.begin() + entryCountToRemove,
+            entryInfoVector.end(),
+            EntryInfoToTurncate::Comparator());
+    for (int i = 0; i < entryCountToRemove; ++i) {
+        const EntryInfoToTurncate &entryInfo = entryInfoVector[i];
+        if (!removeNgramProbabilityEntry(
+                WordIdArrayView(entryInfo.mPrevWordIds, entryInfo.mEntryLevel), entryInfo.mKey)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool LanguageModelDictContent::getEntryInfo(const HeaderPolicy *const headerPolicy,
+        const int targetLevel, const int bitmapEntryIndex,  std::vector<int> *const prevWordIds,
+        std::vector<EntryInfoToTurncate> *const outEntryInfo) const {
+    const int currentLevel = prevWordIds->size();
+    for (const auto &entry : mTrieMap.getEntriesInSpecifiedLevel(bitmapEntryIndex)) {
+        if (currentLevel < targetLevel) {
+            if (!entry.hasNextLevelMap()) {
+                continue;
+            }
+            prevWordIds->push_back(entry.key());
+            if (!getEntryInfo(headerPolicy, targetLevel, entry.getNextLevelBitmapEntryIndex(),
+                    prevWordIds, outEntryInfo)) {
+                return false;
+            }
+            prevWordIds->pop_back();
+            continue;
+        }
+        const ProbabilityEntry probabilityEntry =
+                ProbabilityEntry::decode(entry.value(), mHasHistoricalInfo);
+        const int probability = (mHasHistoricalInfo) ?
+                ForgettingCurveUtils::decodeProbability(probabilityEntry.getHistoricalInfo(),
+                        headerPolicy) : probabilityEntry.getProbability();
+        outEntryInfo->emplace_back(probability,
+                probabilityEntry.getHistoricalInfo()->getTimeStamp(),
+                entry.key(), targetLevel, prevWordIds->data());
+    }
+    return true;
+}
+
+bool LanguageModelDictContent::EntryInfoToTurncate::Comparator::operator()(
+        const EntryInfoToTurncate &left, const EntryInfoToTurncate &right) const {
+    if (left.mProbability != right.mProbability) {
+        return left.mProbability < right.mProbability;
+    }
+    if (left.mTimestamp != right.mTimestamp) {
+        return left.mTimestamp > right.mTimestamp;
+    }
+    if (left.mKey != right.mKey) {
+        return left.mKey < right.mKey;
+    }
+    if (left.mEntryLevel != right.mEntryLevel) {
+        return left.mEntryLevel > right.mEntryLevel;
+    }
+    for (int i = 0; i < left.mEntryLevel; ++i) {
+        if (left.mPrevWordIds[i] != right.mPrevWordIds[i]) {
+            return left.mPrevWordIds[i] < right.mPrevWordIds[i];
+        }
+    }
+    // left and rigth represent the same entry.
+    return false;
+}
+
+LanguageModelDictContent::EntryInfoToTurncate::EntryInfoToTurncate(const int probability,
+        const int timestamp, const int key, const int entryLevel, const int *const prevWordIds)
+        : mProbability(probability), mTimestamp(timestamp), mKey(key), mEntryLevel(entryLevel) {
+    memmove(mPrevWordIds, prevWordIds, mEntryLevel * sizeof(mPrevWordIds[0]));
+}
+
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h
index bd07f2f..43b2aab 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h
@@ -18,6 +18,7 @@
 #define LATINIME_LANGUAGE_MODEL_DICT_CONTENT_H
 
 #include <cstdio>
+#include <vector>
 
 #include "defines.h"
 #include "suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h"
@@ -29,6 +30,8 @@
 
 namespace latinime {
 
+class HeaderPolicy;
+
 /**
  * Class representing language model.
  *
@@ -73,9 +76,45 @@
 
     bool removeNgramProbabilityEntry(const WordIdArrayView prevWordIds, const int wordId);
 
+    bool updateAllProbabilityEntries(const HeaderPolicy *const headerPolicy,
+            int *const outEntryCounts) {
+        for (int i = 0; i <= MAX_PREV_WORD_COUNT_FOR_N_GRAM; ++i) {
+            outEntryCounts[i] = 0;
+        }
+        return updateAllProbabilityEntriesInner(mTrieMap.getRootBitmapEntryIndex(), 0 /* level */,
+                headerPolicy, outEntryCounts);
+    }
+
+    // entryCounts should be created by updateAllProbabilityEntries.
+    bool truncateEntries(const int *const entryCounts, const int *const maxEntryCounts,
+            const HeaderPolicy *const headerPolicy);
+
  private:
     DISALLOW_COPY_AND_ASSIGN(LanguageModelDictContent);
 
+    class EntryInfoToTurncate {
+     public:
+        class Comparator {
+         public:
+            bool operator()(const EntryInfoToTurncate &left,
+                    const EntryInfoToTurncate &right) const;
+         private:
+            DISALLOW_ASSIGNMENT_OPERATOR(Comparator);
+        };
+
+        EntryInfoToTurncate(const int probability, const int timestamp, const int key,
+                const int entryLevel, const int *const prevWordIds);
+
+        int mProbability;
+        int mTimestamp;
+        int mKey;
+        int mEntryLevel;
+        int mPrevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1];
+
+     private:
+        DISALLOW_DEFAULT_CONSTRUCTOR(EntryInfoToTurncate);
+    };
+
     TrieMap mTrieMap;
     const bool mHasHistoricalInfo;
 
@@ -84,6 +123,13 @@
             int *const outNgramCount);
     int createAndGetBitmapEntryIndex(const WordIdArrayView prevWordIds);
     int getBitmapEntryIndex(const WordIdArrayView prevWordIds) const;
+    bool updateAllProbabilityEntriesInner(const int bitmapEntryIndex, const int level,
+            const HeaderPolicy *const headerPolicy, int *const outEntryCounts);
+    bool turncateEntriesInSpecifiedLevel(const HeaderPolicy *const headerPolicy,
+            const int maxEntryCount, const int targetLevel);
+    bool getEntryInfo(const HeaderPolicy *const headerPolicy, const int targetLevel,
+            const int bitmapEntryIndex, std::vector<int> *const prevWordIds,
+            std::vector<EntryInfoToTurncate> *const outEntryInfo) const;
 };
 } // namespace latinime
 #endif /* LATINIME_LANGUAGE_MODEL_DICT_CONTENT_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
index fb6840b..b7c31bf 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
@@ -161,29 +161,15 @@
     const ProbabilityEntry originalProbabilityEntry =
             mBuffers->getLanguageModelDictContent()->getProbabilityEntry(
                     toBeUpdatedPtNodeParams->getTerminalId());
-    if (originalProbabilityEntry.hasHistoricalInfo()) {
-        const HistoricalInfo historicalInfo = ForgettingCurveUtils::createHistoricalInfoToSave(
-                originalProbabilityEntry.getHistoricalInfo(), mHeaderPolicy);
-        const ProbabilityEntry probabilityEntry(originalProbabilityEntry.getFlags(),
-                &historicalInfo);
-        if (!mBuffers->getMutableLanguageModelDictContent()->setProbabilityEntry(
-                toBeUpdatedPtNodeParams->getTerminalId(), &probabilityEntry)) {
-            AKLOGE("Cannot write updated probability entry. terminalId: %d",
-                    toBeUpdatedPtNodeParams->getTerminalId());
-            return false;
-        }
-        const bool isValid = ForgettingCurveUtils::needsToKeep(&historicalInfo, mHeaderPolicy);
-        if (!isValid) {
-            if (!markPtNodeAsWillBecomeNonTerminal(toBeUpdatedPtNodeParams)) {
-                AKLOGE("Cannot mark PtNode as willBecomeNonTerminal.");
-                return false;
-            }
-        }
-        *outNeedsToKeepPtNode = isValid;
-    } else {
-        // No need to update probability.
+    if (originalProbabilityEntry.isValid()) {
         *outNeedsToKeepPtNode = true;
+        return true;
     }
+    if (!markPtNodeAsWillBecomeNonTerminal(toBeUpdatedPtNodeParams)) {
+        AKLOGE("Cannot mark PtNode as willBecomeNonTerminal.");
+        return false;
+    }
+    *outNeedsToKeepPtNode = false;
     return true;
 }
 
@@ -380,6 +366,7 @@
             isTerminal, ptNodeParams->getCodePointCount() > 1 /* hasMultipleChars */);
 }
 
+// TODO: Move probability handling code to LanguageModelDictContent.
 const ProbabilityEntry Ver4PatriciaTrieNodeWriter::createUpdatedEntryFrom(
         const ProbabilityEntry *const originalProbabilityEntry,
         const ProbabilityEntry *const probabilityEntry) const {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
index 04e3018..2ea248e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
@@ -127,21 +127,28 @@
     if (ptNodePos == NOT_A_DICT_POS) {
         return NOT_A_PROBABILITY;
     }
-    const PtNodeParams ptNodeParams(mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos));
+    const PtNodeParams ptNodeParams = mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos);
     if (ptNodeParams.isDeleted() || ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord()) {
         return NOT_A_PROBABILITY;
     }
     if (prevWordsPtNodePos) {
-        const int bigramsPosition = getBigramsPositionOfPtNode(prevWordsPtNodePos[0]);
-        BinaryDictionaryBigramsIterator bigramsIt(&mBigramPolicy, bigramsPosition);
-        while (bigramsIt.hasNext()) {
-            bigramsIt.next();
-            if (bigramsIt.getBigramPos() == ptNodePos
-                    && bigramsIt.getProbability() != NOT_A_PROBABILITY) {
-                return getProbability(ptNodeParams.getProbability(), bigramsIt.getProbability());
-            }
+        // TODO: Support n-gram.
+        const PtNodeParams prevWordPtNodeParams =
+                mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(prevWordsPtNodePos[0]);
+        const int prevWordTerminalId = prevWordPtNodeParams.getTerminalId();
+        const ProbabilityEntry probabilityEntry =
+                mBuffers->getLanguageModelDictContent()->getNgramProbabilityEntry(
+                        IntArrayView::fromObject(&prevWordTerminalId),
+                        ptNodeParams.getTerminalId());
+        if (!probabilityEntry.isValid()) {
+            return NOT_A_PROBABILITY;
         }
-        return NOT_A_PROBABILITY;
+        if (mHeaderPolicy->hasHistoricalInfoOfWords()) {
+            return ForgettingCurveUtils::decodeProbability(probabilityEntry.getHistoricalInfo(),
+                    mHeaderPolicy);
+        } else {
+            return probabilityEntry.getProbability();
+        }
     }
     return getProbability(ptNodeParams.getProbability(), NOT_A_PROBABILITY);
 }
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
index 4220312..d53575a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
@@ -85,6 +85,27 @@
             mBuffers, headerPolicy, &ptNodeReader, &ptNodeArrayReader, &bigramPolicy,
             &shortcutPolicy);
 
+    int entryCountTable[MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1];
+    if (!mBuffers->getMutableLanguageModelDictContent()->updateAllProbabilityEntries(headerPolicy,
+            entryCountTable)) {
+        AKLOGE("Failed to update probabilities in language model dict content.");
+        return false;
+    }
+    if (headerPolicy->isDecayingDict()) {
+        int maxEntryCountTable[MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1];
+        maxEntryCountTable[0] = headerPolicy->getMaxUnigramCount();
+        maxEntryCountTable[1] = headerPolicy->getMaxBigramCount();
+        for (size_t i = 2; i < NELEMS(maxEntryCountTable); ++i) {
+            // TODO: Have max n-gram count.
+            maxEntryCountTable[i] = headerPolicy->getMaxBigramCount();
+        }
+        if (!mBuffers->getMutableLanguageModelDictContent()->truncateEntries(entryCountTable,
+                maxEntryCountTable,  headerPolicy)) {
+            AKLOGE("Failed to truncate entries in language model dict content.");
+            return false;
+        }
+    }
+
     DynamicPtReadingHelper readingHelper(&ptNodeReader, &ptNodeArrayReader);
     readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos);
     DynamicPtGcEventListeners
@@ -187,6 +208,7 @@
     return true;
 }
 
+// TODO: Remove.
 bool Ver4PatriciaTrieWritingHelper::truncateUnigrams(
         const Ver4PatriciaTrieNodeReader *const ptNodeReader,
         Ver4PatriciaTrieNodeWriter *const ptNodeWriter, const int maxUnigramCount) {
@@ -227,6 +249,7 @@
     return true;
 }
 
+// TODO: Remove.
 bool Ver4PatriciaTrieWritingHelper::truncateBigrams(const int maxBigramCount) {
     const TerminalPositionLookupTable *const terminalPosLookupTable =
             mBuffers->getTerminalPositionLookupTable();
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
index 833063c..ecbe792 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.cpp
@@ -31,7 +31,7 @@
 
 uint32_t BufferWithExtendableBuffer::readUintAndAdvancePosition(const int size,
         int *const pos) const {
-    const int value = readUint(size, *pos);
+    const uint32_t value = readUint(size, *pos);
     *pos += size;
     return value;
 }
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h
index c0a9fcb..4b3c989 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/byte_array_utils.h
@@ -114,7 +114,7 @@
         return buffer[(*pos)++];
     }
 
-    static AK_FORCE_INLINE int readUint(const uint8_t *const buffer,
+    static AK_FORCE_INLINE uint32_t readUint(const uint8_t *const buffer,
             const int size, const int pos) {
         // size must be in 1 to 4.
         ASSERT(size >= 1 && size <= 4);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h b/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h
index 6d91790..c2aeac2 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/trie_map.h
@@ -84,6 +84,10 @@
                 return mValue;
             }
 
+            AK_FORCE_INLINE int getNextLevelBitmapEntryIndex() const {
+                return mNextLevelBitmapEntryIndex;
+            }
+
          private:
             const TrieMap *const mTrieMap;
             const int mKey;
diff --git a/native/jni/tests/suggest/policyimpl/dictionary/utils/byte_array_utils_test.cpp b/native/jni/tests/suggest/policyimpl/dictionary/utils/byte_array_utils_test.cpp
new file mode 100644
index 0000000..a1c310d
--- /dev/null
+++ b/native/jni/tests/suggest/policyimpl/dictionary/utils/byte_array_utils_test.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
+
+#include <gtest/gtest.h>
+
+#include <cstdint>
+
+namespace latinime {
+namespace {
+
+TEST(ByteArrayUtilsTest, TestReadInt) {
+    const uint8_t buffer[] = { 0x1u, 0x8Au, 0x0u, 0xAAu };
+
+    EXPECT_EQ(0x01u, ByteArrayUtils::readUint8(buffer, 0));
+    EXPECT_EQ(0x8Au, ByteArrayUtils::readUint8(buffer, 1));
+    EXPECT_EQ(0x0u, ByteArrayUtils::readUint8(buffer, 2));
+    EXPECT_EQ(0xAAu, ByteArrayUtils::readUint8(buffer, 3));
+
+    EXPECT_EQ(0x018Au, ByteArrayUtils::readUint16(buffer, 0));
+    EXPECT_EQ(0x8A00u, ByteArrayUtils::readUint16(buffer, 1));
+    EXPECT_EQ(0xAAu, ByteArrayUtils::readUint16(buffer, 2));
+
+    EXPECT_EQ(0x18A00AAu, ByteArrayUtils::readUint32(buffer, 0));
+
+    int pos = 0;
+    EXPECT_EQ(0x18A00, ByteArrayUtils::readSint24AndAdvancePosition(buffer, &pos));
+    pos = 1;
+    EXPECT_EQ(-0xA00AA, ByteArrayUtils::readSint24AndAdvancePosition(buffer, &pos));
+}
+
+TEST(ByteArrayUtilsTest, TestWriteAndReadInt) {
+    uint8_t buffer[4];
+
+    int pos = 0;
+    const uint8_t data_1B = 0xC8;
+    ByteArrayUtils::writeUintAndAdvancePosition(buffer, data_1B, 1, &pos);
+    EXPECT_EQ(data_1B, ByteArrayUtils::readUint(buffer, 1, 0));
+
+    pos = 0;
+    const uint32_t data_4B = 0xABCD1234;
+    ByteArrayUtils::writeUintAndAdvancePosition(buffer, data_4B, 4, &pos);
+    EXPECT_EQ(data_4B, ByteArrayUtils::readUint(buffer, 4, 0));
+}
+
+TEST(ByteArrayUtilsTest, TestReadCodePoint) {
+    const uint8_t buffer[] = { 0x10, 0xFF, 0x00u, 0x20u, 0x41u, 0x1Fu, 0x60 };
+
+    EXPECT_EQ(0x10FF00, ByteArrayUtils::readCodePoint(buffer, 0));
+    EXPECT_EQ(0x20, ByteArrayUtils::readCodePoint(buffer, 3));
+    EXPECT_EQ(0x41, ByteArrayUtils::readCodePoint(buffer, 4));
+    EXPECT_EQ(NOT_A_CODE_POINT, ByteArrayUtils::readCodePoint(buffer, 5));
+
+    int pos = 0;
+    int codePointArray[3];
+    EXPECT_EQ(3, ByteArrayUtils::readStringAndAdvancePosition(buffer, MAX_WORD_LENGTH,
+            codePointArray, &pos));
+    EXPECT_EQ(0x10FF00, codePointArray[0]);
+    EXPECT_EQ(0x20, codePointArray[1]);
+    EXPECT_EQ(0x41, codePointArray[2]);
+    EXPECT_EQ(0x60, ByteArrayUtils::readCodePoint(buffer, pos));
+}
+
+TEST(ByteArrayUtilsTest, TestWriteAndReadCodePoint) {
+    uint8_t buffer[10];
+
+    const int codePointArray[] = { 0x10FF00, 0x20, 0x41 };
+    int pos = 0;
+    ByteArrayUtils::writeCodePointsAndAdvancePosition(buffer, codePointArray, 3,
+            true /* writesTerminator */, &pos);
+    EXPECT_EQ(0x10FF00, ByteArrayUtils::readCodePoint(buffer, 0));
+    EXPECT_EQ(0x20, ByteArrayUtils::readCodePoint(buffer, 3));
+    EXPECT_EQ(0x41, ByteArrayUtils::readCodePoint(buffer, 4));
+    EXPECT_EQ(NOT_A_CODE_POINT, ByteArrayUtils::readCodePoint(buffer, 5));
+}
+
+}  // namespace
+}  // namespace latinime
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
index cf884bf..0a76a9d 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
@@ -29,6 +29,7 @@
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
 import com.android.inputmethod.latin.utils.ResourceUtils;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
@@ -112,13 +113,13 @@
                 "Unknown subtype: locale=" + locale + " keyboardLayout=" + keyboardLayout);
     }
 
-    protected final KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+    protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
             final EditorInfo editorInfo) {
         return createKeyboardLayoutSet(subtype, editorInfo, false /* voiceInputKeyEnabled */,
                 false /* languageSwitchKeyEnabled */);
     }
 
-    protected final KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+    protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
             final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
             final boolean languageSwitchKeyEnabled) {
         final Context context = mThemeContext;
@@ -127,7 +128,7 @@
         final int keyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res);
         final Builder builder = new Builder(context, editorInfo);
         builder.setKeyboardGeometry(keyboardWidth, keyboardHeight)
-                .setSubtype(subtype)
+                .setSubtype(new RichInputMethodSubtype(subtype))
                 .setVoiceInputKeyEnabled(voiceInputKeyEnabled)
                 .setLanguageSwitchKeyEnabled(languageSwitchKeyEnabled);
         return builder.build();
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelperTests.java b/tests/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelperTests.java
index 6ea2758..e619801 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelperTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/LanguageOnSpacebarHelperTests.java
@@ -26,6 +26,7 @@
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 
@@ -40,14 +41,14 @@
 
     private RichInputMethodManager mRichImm;
 
-    InputMethodSubtype EN_US_QWERTY;
-    InputMethodSubtype EN_GB_QWERTY;
-    InputMethodSubtype FR_AZERTY;
-    InputMethodSubtype FR_CA_QWERTY;
-    InputMethodSubtype FR_CH_SWISS;
-    InputMethodSubtype FR_CH_QWERTY;
-    InputMethodSubtype FR_CH_QWERTZ;
-    InputMethodSubtype ZZ_QWERTY;
+    RichInputMethodSubtype EN_US_QWERTY;
+    RichInputMethodSubtype EN_GB_QWERTY;
+    RichInputMethodSubtype FR_AZERTY;
+    RichInputMethodSubtype FR_CA_QWERTY;
+    RichInputMethodSubtype FR_CH_SWISS;
+    RichInputMethodSubtype FR_CH_QWERTY;
+    RichInputMethodSubtype FR_CH_QWERTZ;
+    RichInputMethodSubtype ZZ_QWERTY;
 
     @Override
     protected void setUp() throws Exception {
@@ -57,22 +58,22 @@
         mRichImm = RichInputMethodManager.getInstance();
         SubtypeLocaleUtils.init(context);
 
-        EN_US_QWERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.US.toString(), "qwerty");
-        EN_GB_QWERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.UK.toString(), "qwerty");
-        FR_AZERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.FRENCH.toString(), "azerty");
-        FR_CA_QWERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.CANADA_FRENCH.toString(), "qwerty");
-        FR_CH_SWISS = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                "fr_CH", "swiss");
-        FR_CH_QWERTZ = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                "fr_CH", "qwertz");
-        FR_CH_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                "fr_CH", "qwerty");
-        ZZ_QWERTY = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                SubtypeLocaleUtils.NO_LANGUAGE, "qwerty");
+        EN_US_QWERTY = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.US.toString(), "qwerty"));
+        EN_GB_QWERTY = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.UK.toString(), "qwerty"));
+        FR_AZERTY = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.FRENCH.toString(), "azerty"));
+        FR_CA_QWERTY = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.CANADA_FRENCH.toString(), "qwerty"));
+        FR_CH_SWISS = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                "fr_CH", "swiss"));
+        FR_CH_QWERTZ = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype("fr_CH", "qwertz"));
+        FR_CH_QWERTY = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype("fr_CH", "qwerty"));
+        ZZ_QWERTY = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                SubtypeLocaleUtils.NO_LANGUAGE, "qwerty"));
     }
 
     private static List<InputMethodSubtype> asList(final InputMethodSubtype ... subtypes) {
@@ -80,14 +81,14 @@
     }
 
     public void testOneSubtype() {
-        mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(EN_US_QWERTY));
+        mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(EN_US_QWERTY.getRawSubtype()));
         mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(true /* isSame */);
         assertEquals("one same English (US)", FORMAT_TYPE_NONE,
                 mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_US_QWERTY));
         assertEquals("one same NoLanguage", FORMAT_TYPE_FULL_LOCALE,
                 mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(ZZ_QWERTY));
 
-        mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(FR_AZERTY));
+        mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(FR_AZERTY.getRawSubtype()));
         mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(false /* isSame */);
         assertEquals("one diff English (US)", FORMAT_TYPE_LANGUAGE_ONLY,
                 mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_US_QWERTY));
@@ -96,8 +97,8 @@
     }
 
     public void testTwoSubtypes() {
-        mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(EN_US_QWERTY, FR_AZERTY));
-
+        mLanguageOnSpacebarHelper.updateEnabledSubtypes(asList(EN_US_QWERTY.getRawSubtype(),
+                FR_AZERTY.getRawSubtype()));
         mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(true /* isSame */);
         assertEquals("two same English (US)", FORMAT_TYPE_LANGUAGE_ONLY,
                 mLanguageOnSpacebarHelper.getLanguageOnSpacebarFormatType(EN_US_QWERTY));
@@ -117,7 +118,8 @@
 
     public void testSameLanuageSubtypes() {
         mLanguageOnSpacebarHelper.updateEnabledSubtypes(
-                asList(EN_US_QWERTY, EN_GB_QWERTY, FR_AZERTY, ZZ_QWERTY));
+                asList(EN_US_QWERTY.getRawSubtype(), EN_GB_QWERTY.getRawSubtype(),
+                        FR_AZERTY.getRawSubtype(), ZZ_QWERTY.getRawSubtype()));
 
         mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(true /* isSame */);
         assertEquals("two same English (US)", FORMAT_TYPE_FULL_LOCALE,
@@ -138,7 +140,9 @@
 
     public void testMultiSameLanuageSubtypes() {
         mLanguageOnSpacebarHelper.updateEnabledSubtypes(
-                asList(FR_AZERTY, FR_CA_QWERTY, FR_CH_SWISS, FR_CH_QWERTY, FR_CH_QWERTZ));
+                asList(FR_AZERTY.getRawSubtype(), FR_CA_QWERTY.getRawSubtype(),
+                        FR_CH_SWISS.getRawSubtype(), FR_CH_QWERTY.getRawSubtype(),
+                        FR_CH_QWERTZ.getRawSubtype()));
 
         mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(true /* isSame */);
         assertEquals("multi same French", FORMAT_TYPE_LANGUAGE_ONLY,
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Arabic.java b/tests/src/com/android/inputmethod/keyboard/layout/Arabic.java
index fa81865..3f85e4b 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Arabic.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Arabic.java
@@ -78,8 +78,7 @@
             // U+061F: "؟" ARABIC QUESTION MARK
             // U+061B: "؛" ARABIC SEMICOLON
             return joinKeys(key("\u060C", joinMoreKeys(
-                    ":", "!", "\u061F", "\u061B", "-", "\"", "'", SETTINGS_KEY)),
-                    "_");
+                    ":", "!", "\u061F", "\u061B", "-", "\"", "'", SETTINGS_KEY)));
         }
 
         @Override
@@ -90,7 +89,7 @@
             // U+060C: "،" ARABIC COMMA
             // U+061F: "؟" ARABIC QUESTION MARK
             // U+061B: "؛" ARABIC SEMICOLON
-            return joinKeys("/", key(".", getPunctuationMoreKeys(isPhone)));
+            return joinKeys(key(".", getPunctuationMoreKeys(isPhone)));
         }
 
         @Override
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/ArmenianPhonetic.java b/tests/src/com/android/inputmethod/keyboard/layout/ArmenianPhonetic.java
index dba91b4..2cecedc 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/ArmenianPhonetic.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/ArmenianPhonetic.java
@@ -62,14 +62,14 @@
         public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
             // U+055D: "՝" ARMENIAN COMMA
             return isPhone ? joinKeys(key("\u055D", SETTINGS_KEY))
-                    : joinKeys(key("\u055D", SETTINGS_KEY), "_");
+                    : joinKeys(key("\u055D", SETTINGS_KEY));
         }
 
         @Override
         public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
             // U+0589: "։" ARMENIAN FULL STOP
             final ExpectedKey fullStopKey = key("\u0589", getPunctuationMoreKeys(isPhone));
-            return isPhone ? joinKeys(fullStopKey) : joinKeys("/", fullStopKey);
+            return joinKeys(fullStopKey);
         }
 
         @Override
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java b/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java
index e75cfd0..ba94c8d 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java
@@ -20,13 +20,14 @@
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKey.ExpectedAdditionalMoreKey;
+import com.android.inputmethod.latin.settings.CustomInputStyleSettingsFragment;
 
 import java.util.Locale;
 
 /**
- * The QWERTY alphabet keyboard.
+ * The Dvorak alphabet keyboard.
  */
-public final class Dvorak extends LayoutBase {
+public class Dvorak extends LayoutBase {
     private static final String LAYOUT_NAME = "dvorak";
 
     public Dvorak(final LayoutCustomizer customizer) {
@@ -51,17 +52,19 @@
 
         @Override
         public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
-            return isPhone ? joinKeys(key("q", SETTINGS_KEY)) :
-                joinKeys(SETTINGS_KEY, key("_", moreKey("-")));
+            // U+00A1: "¡" INVERTED EXCLAMATION MARK
+            return isPhone ? joinKeys(key("q", SETTINGS_KEY))
+                    : joinKeys(key("!", joinMoreKeys("\u00A1", SETTINGS_KEY)));
         }
 
         @Override
         public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
             final ExpectedAdditionalMoreKey[] punctuationMoreKeys =
                     convertToAdditionalMoreKeys(getPunctuationMoreKeys(isPhone));
+            // U+00BF: "¿" INVERTED QUESTION MARK
             return isPhone
                     ? joinKeys(key("z", punctuationMoreKeys))
-                    : joinKeys("/", key("?", moreKey("!")));
+                    : joinKeys(key("?", joinMoreKeys(punctuationMoreKeys, "\u00BF")));
         }
 
         private static ExpectedAdditionalMoreKey[] convertToAdditionalMoreKeys(
@@ -76,7 +79,33 @@
     }
 
     @Override
-    ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) { return ALPHABET_COMMON; }
+    public ExpectedKey[][] getCommonAlphabetLayout(final boolean isPhone) {
+        return ALPHABET_COMMON;
+    }
+
+    protected ExpectedKey getRow1_1Key(final boolean isPhone, final int elementId) {
+        if (elementId == KeyboardId.ELEMENT_ALPHABET
+                || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
+            return key("'", joinMoreKeys(additionalMoreKey("1"), "!", "\""));
+        }
+        return key("\"", additionalMoreKey("1"));
+    }
+
+    protected ExpectedKey getRow1_2Key(final boolean isPhone, final int elementId) {
+        if (elementId == KeyboardId.ELEMENT_ALPHABET
+                || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
+            return key(",", joinMoreKeys(additionalMoreKey("2"), "?", "<"));
+        }
+        return key("<", additionalMoreKey("2"));
+    }
+
+    protected ExpectedKey getRow1_3Key(final boolean isPhone, final int elementId) {
+        if (elementId == KeyboardId.ELEMENT_ALPHABET
+                || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
+            return key(".", joinMoreKeys(additionalMoreKey("3"), ">"));
+        }
+        return key(">", additionalMoreKey("3"));
+    }
 
     @Override
     public ExpectedKey[][] getLayout(final boolean isPhone, final int elementId) {
@@ -86,18 +115,9 @@
         }
         final ExpectedKeyboardBuilder builder = new ExpectedKeyboardBuilder(
                 getCommonAlphabetLayout(isPhone));
-        if (elementId == KeyboardId.ELEMENT_ALPHABET
-                || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
-            builder.addKeysOnTheLeftOfRow(1,
-                    key("'", joinMoreKeys(additionalMoreKey("1"), "!", "\"")),
-                    key(",", joinMoreKeys(additionalMoreKey("2"), "?", "<")),
-                    key(".", joinMoreKeys(additionalMoreKey("3"), ">")));
-        } else {
-            builder.addKeysOnTheLeftOfRow(1,
-                    key("\"", additionalMoreKey("1")),
-                    key("<", additionalMoreKey("2")),
-                    key(">", additionalMoreKey("3")));
-        }
+        builder.replaceKeyOfLabel(ROW1_1, getRow1_1Key(isPhone, elementId))
+                .replaceKeyOfLabel(ROW1_2, getRow1_2Key(isPhone, elementId))
+                .replaceKeyOfLabel(ROW1_3, getRow1_3Key(isPhone, elementId));
         convertCommonLayoutToKeyboard(builder, isPhone);
         getCustomizer().setAccentedLetters(builder);
         if (elementId != KeyboardId.ELEMENT_ALPHABET) {
@@ -107,8 +127,13 @@
         return builder.build();
     }
 
+    public static final String ROW1_1 = "ROW1_1";
+    public static final String ROW1_2 = "ROW1_2";
+    public static final String ROW1_3 = "ROW1_3";
+
     private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder()
             .setKeysOfRow(1,
+                    ROW1_1, ROW1_2, ROW1_3,
                     key("p", additionalMoreKey("4")),
                     key("y", additionalMoreKey("5")),
                     key("f", additionalMoreKey("6")),
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java b/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java
index a513740..7390457 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java
@@ -77,8 +77,7 @@
             // U+061B: "؛" ARABIC SEMICOLON
             return joinKeys(key("\u060C", joinMoreKeys(
                     ":", "!", "\u061F", "\u061B", "-", RtlSymbols.DOUBLE_ANGLE_QUOTES_LR_RTL,
-                    SETTINGS_KEY)),
-                    "_");
+                    SETTINGS_KEY)));
         }
 
         @Override
@@ -86,7 +85,7 @@
             if (isPhone) {
                 return super.getKeysRightToSpacebar(isPhone);
             }
-            return joinKeys("/", key(".", getPunctuationMoreKeys(isPhone)));
+            return joinKeys(key(".", getPunctuationMoreKeys(isPhone)));
         }
 
         @Override
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java b/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java
index 2b625c3..c2a15f3 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java
@@ -50,7 +50,7 @@
         public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
             // U+0964: "।" DEVANAGARI DANDA
             final ExpectedKey periodKey = key("\u0964", getPunctuationMoreKeys(isPhone));
-            return isPhone ? joinKeys(periodKey) : joinKeys("/", periodKey);
+            return joinKeys(periodKey);
         }
 
         @Override
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java b/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
index 0548a01..b05789b 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
@@ -149,6 +149,24 @@
         }
 
         /**
+         * Get the enter key.
+         * @param isPhone true if requesting phone's key.
+         * @return the array of {@link ExpectedKey} that should be placed as an enter key.
+         */
+        public ExpectedKey getEnterKey(final boolean isPhone) {
+            return isPhone ? key(ENTER_KEY, EMOJI_ACTION_KEY) : ENTER_KEY;
+        }
+
+        /**
+         * Get the emoji key.
+         * @param isPhone true if requesting phone's key.
+         * @return the array of {@link ExpectedKey} that should be placed as an emoji key.
+         */
+        public ExpectedKey getEmojiKey(final boolean isPhone) {
+            return EMOJI_NORMAL_KEY;
+        }
+
+        /**
          * Get the space keys.
          * @param isPhone true if requesting phone's keys.
          * @return the array of {@link ExpectedKey} that should be placed at the center of the
@@ -165,8 +183,7 @@
          */
         public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
             // U+002C: "," COMMA
-            return isPhone ? joinKeys(key("\u002C", SETTINGS_KEY))
-                    : joinKeys(key("\u002C", SETTINGS_KEY), "_");
+            return joinKeys(key("\u002C", SETTINGS_KEY));
         }
 
         /**
@@ -176,7 +193,7 @@
          */
         public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
             final ExpectedKey periodKey = key(".", getPunctuationMoreKeys(isPhone));
-            return isPhone ? joinKeys(periodKey) : joinKeys("/", periodKey);
+            return joinKeys(periodKey);
         }
 
         /**
@@ -241,7 +258,25 @@
      */
     public final LayoutCustomizer getCustomizer() { return mCustomizer; }
 
-    // Icon id.
+    // Icon ids.
+    private static final int ICON_DELETE = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_DELETE_KEY);
+    private static final int ICON_SPACE = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_SPACE_KEY);
+    private static final int ICON_TAB = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_TAB_KEY);
+    private static final int ICON_SHORTCUT = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_SHORTCUT_KEY);
+    private static final int ICON_SETTINGS = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_SETTINGS_KEY);
+    private static final int ICON_LANGUAGE_SWITCH = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_LANGUAGE_SWITCH_KEY);
+    private static final int ICON_ENTER = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_ENTER_KEY);
+    private static final int ICON_EMOJI_ACTION = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_EMOJI_ACTION_KEY);
+    private static final int ICON_EMOJI_NORMAL = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_EMOJI_NORMAL_KEY);
     private static final int ICON_SHIFT = KeyboardIconsSet.getIconId(
             KeyboardIconsSet.NAME_SHIFT_KEY);
     private static final int ICON_SHIFTED_SHIFT = KeyboardIconsSet.getIconId(
@@ -251,11 +286,21 @@
     private static final int ICON_ZWJ = KeyboardIconsSet.getIconId(
             KeyboardIconsSet.NAME_ZWJ_KEY);
 
-    // Functional key.
+    // Functional keys.
+    public static final ExpectedKey DELETE_KEY = key(ICON_DELETE, Constants.CODE_DELETE);
+    public static final ExpectedKey TAB_KEY = key(ICON_TAB, Constants.CODE_TAB);
+    public static final ExpectedKey SHORTCUT_KEY = key(ICON_SHORTCUT, Constants.CODE_SHORTCUT);
+    public static final ExpectedKey SETTINGS_KEY = key(ICON_SETTINGS, Constants.CODE_SETTINGS);
+    public static final ExpectedKey LANGUAGE_SWITCH_KEY = key(
+            ICON_LANGUAGE_SWITCH, Constants.CODE_LANGUAGE_SWITCH);
+    public static final ExpectedKey ENTER_KEY = key(ICON_ENTER, Constants.CODE_ENTER);
+    public static final ExpectedKey EMOJI_ACTION_KEY = key(ICON_EMOJI_ACTION, Constants.CODE_EMOJI);
+    public static final ExpectedKey EMOJI_NORMAL_KEY = key(ICON_EMOJI_NORMAL, Constants.CODE_EMOJI);
+    public static final ExpectedKey SPACE_KEY = key(ICON_SPACE, Constants.CODE_SPACE);
     static final ExpectedKey CAPSLOCK_MORE_KEY = key(" ", Constants.CODE_CAPSLOCK);
-    static final ExpectedKey SHIFT_KEY = key(ICON_SHIFT,
+    public static final ExpectedKey SHIFT_KEY = key(ICON_SHIFT,
             Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY);
-    static final ExpectedKey SHIFTED_SHIFT_KEY = key(ICON_SHIFTED_SHIFT,
+    public static final ExpectedKey SHIFTED_SHIFT_KEY = key(ICON_SHIFTED_SHIFT,
             Constants.CODE_SHIFT, CAPSLOCK_MORE_KEY);
     static final ExpectedKey ALPHABET_KEY = key("ABC", Constants.CODE_SWITCH_ALPHA_SYMBOL);
     static final ExpectedKey SYMBOLS_KEY = key("?123", Constants.CODE_SWITCH_ALPHA_SYMBOL);
@@ -271,6 +316,9 @@
     // U+200D: ZERO WIDTH JOINER
     static final ExpectedKey ZWNJ_KEY = key(ICON_ZWNJ, "\u200C");
     static final ExpectedKey ZWJ_KEY = key(ICON_ZWJ, "\u200D");
+    // Domain key
+    public static final ExpectedKey DOMAIN_KEY =
+            key(".com", joinMoreKeys(".net", ".org", ".gov", ".edu")).preserveCase();
 
     // Punctuation more keys for phone form factor.
     public static final ExpectedKey[] PHONE_PUNCTUATION_MORE_KEYS = joinKeys(
@@ -300,12 +348,12 @@
         if (isPhone) {
             builder.addKeysOnTheRightOfRow(numberOfRows - 1, DELETE_KEY)
                     .addKeysOnTheLeftOfRow(numberOfRows, customizer.getSymbolsKey())
-                    .addKeysOnTheRightOfRow(numberOfRows, key(ENTER_KEY, EMOJI_ACTION_KEY));
+                    .addKeysOnTheRightOfRow(numberOfRows, customizer.getEnterKey(isPhone));
         } else {
             builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
-                    .addKeysOnTheRightOfRow(numberOfRows - 2, ENTER_KEY)
+                    .addKeysOnTheRightOfRow(numberOfRows - 2, customizer.getEnterKey(isPhone))
                     .addKeysOnTheLeftOfRow(numberOfRows, customizer.getSymbolsKey())
-                    .addKeysOnTheRightOfRow(numberOfRows, EMOJI_NORMAL_KEY);
+                    .addKeysOnTheRightOfRow(numberOfRows, customizer.getEmojiKey(isPhone));
         }
         builder.addKeysOnTheLeftOfRow(
                 numberOfRows - 1, (Object[])customizer.getLeftShiftKeys(isPhone));
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Myanmar.java b/tests/src/com/android/inputmethod/keyboard/layout/Myanmar.java
index 15c74ed..3c70d32 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Myanmar.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Myanmar.java
@@ -55,14 +55,14 @@
             // U+002C: "," COMMA
             // U+104A: "၊" MYANMAR SIGN LITTLE SECTION
             return isPhone ? joinKeys(key("\u002C", SETTINGS_KEY))
-                    : joinKeys(key("\u104A", moreKey(","), SETTINGS_KEY), "_");
+                    : joinKeys(key("\u104A", moreKey(","), SETTINGS_KEY));
         }
 
         @Override
         public ExpectedKey[] getKeysRightToSpacebar(final boolean isPhone) {
             // U+104B: "။" MYANMAR SIGN SECTION
             final ExpectedKey periodKey = key("\u104B", getPunctuationMoreKeys(isPhone));
-            return isPhone ? joinKeys(periodKey) : joinKeys("/", periodKey);
+            return joinKeys(periodKey);
         }
 
         @Override
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java b/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java
index 2cee2d9..8030897 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Symbols.java
@@ -41,18 +41,18 @@
                 customizer.getSingleQuoteMoreKeys(), customizer.getSingleAngleQuoteKeys())));
         if (isPhone) {
             builder.addKeysOnTheLeftOfRow(3, customizer.getSymbolsShiftKey(isPhone))
-                    .addKeysOnTheRightOfRow(3, DELETE_KEY)
+                    .addKeysOnTheRightOfRow(3, LayoutBase.DELETE_KEY)
                     .addKeysOnTheLeftOfRow(4, customizer.getAlphabetKey())
-                    .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_ACTION_KEY));
+                    .addKeysOnTheRightOfRow(4, customizer.getEnterKey(isPhone));
         } else {
             // Tablet symbols keyboard has extra two keys at the left edge of the 3rd row.
             builder.addKeysOnTheLeftOfRow(3, (Object[])joinKeys("\\", "="));
-            builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
-                    .addKeysOnTheRightOfRow(2, ENTER_KEY)
+            builder.addKeysOnTheRightOfRow(1, LayoutBase.DELETE_KEY)
+                    .addKeysOnTheRightOfRow(2, customizer.getEnterKey(isPhone))
                     .addKeysOnTheLeftOfRow(3, customizer.getSymbolsShiftKey(isPhone))
                     .addKeysOnTheRightOfRow(3, customizer.getSymbolsShiftKey(isPhone))
                     .addKeysOnTheLeftOfRow(4, customizer.getAlphabetKey())
-                    .addKeysOnTheRightOfRow(4, EMOJI_NORMAL_KEY);
+                    .addKeysOnTheRightOfRow(4, customizer.getEmojiKey(isPhone));
         }
         return builder.build();
     }
@@ -167,7 +167,7 @@
                     // U+00BF: "¿" INVERTED QUESTION MARK
                     key("?", moreKey("\u00BF")))
             .setKeysOfRow(4,
-                    key(","), key("_"), SPACE_KEY, key("/"),
+                    key(","), key("_"), LayoutBase.SPACE_KEY, key("/"),
                     // U+2026: "…" HORIZONTAL ELLIPSIS
                     key(".", moreKey("\u2026")))
             .build();
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java b/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java
index 7ed103b..19cb607 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/SymbolsShifted.java
@@ -37,20 +37,20 @@
         builder.replaceKeyOfLabel(OTHER_CURRENCIES, (Object[])customizer.getOtherCurrencyKeys());
         if (isPhone) {
             builder.addKeysOnTheLeftOfRow(3, customizer.getBackToSymbolsKey())
-                    .addKeysOnTheRightOfRow(3, DELETE_KEY)
+                    .addKeysOnTheRightOfRow(3, LayoutBase.DELETE_KEY)
                     .addKeysOnTheLeftOfRow(4, customizer.getAlphabetKey())
-                    .addKeysOnTheRightOfRow(4, key(ENTER_KEY, EMOJI_ACTION_KEY));
+                    .addKeysOnTheRightOfRow(4, customizer.getEnterKey(isPhone));
         } else {
             // Tablet symbols shifted keyboard has extra two keys at the right edge of the 3rd row.
             // U+00BF: "¿" INVERTED QUESTION MARK
             // U+00A1: "¡" INVERTED EXCLAMATION MARK
             builder.addKeysOnTheRightOfRow(3, (Object[])joinKeys("\u00A1", "\u00BF"));
-            builder.addKeysOnTheRightOfRow(1, DELETE_KEY)
-                    .addKeysOnTheRightOfRow(2, ENTER_KEY)
+            builder.addKeysOnTheRightOfRow(1, LayoutBase.DELETE_KEY)
+                    .addKeysOnTheRightOfRow(2, customizer.getEnterKey(isPhone))
                     .addKeysOnTheLeftOfRow(3, customizer.getBackToSymbolsKey())
                     .addKeysOnTheRightOfRow(3, customizer.getBackToSymbolsKey())
                     .addKeysOnTheLeftOfRow(4, customizer.getAlphabetKey())
-                    .addKeysOnTheRightOfRow(4, EMOJI_NORMAL_KEY);
+                    .addKeysOnTheRightOfRow(4, customizer.getEmojiKey(isPhone));
         }
         return builder.build();
     }
@@ -122,7 +122,7 @@
                     // U+2264: "≤" LESS-THAN OR EQUAL TO
                     // U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
                     key("<", joinMoreKeys("\u2039", "\u2264", "\u00AB")),
-                    SPACE_KEY,
+                    LayoutBase.SPACE_KEY,
                     // U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
                     // U+2265: "≥" GREATER-THAN EQUAL TO
                     // U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
index 0f7bef2..3556cb4 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
@@ -16,9 +16,7 @@
 
 package com.android.inputmethod.keyboard.layout.expected;
 
-import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKey.ExpectedAdditionalMoreKey;
-import com.android.inputmethod.latin.Constants;
 
 /**
  * Base class to create an expected keyboard for unit test.
@@ -104,36 +102,4 @@
     public static ExpectedKey[] joinKeys(final Object ... keys) {
         return ExpectedKeyboardBuilder.joinKeys(keys);
     }
-
-    // Icon ids.
-    private static final int ICON_DELETE = KeyboardIconsSet.getIconId(
-            KeyboardIconsSet.NAME_DELETE_KEY);
-    private static final int ICON_SPACE = KeyboardIconsSet.getIconId(
-            KeyboardIconsSet.NAME_SPACE_KEY);
-    private static final int ICON_TAB = KeyboardIconsSet.getIconId(
-            KeyboardIconsSet.NAME_TAB_KEY);
-    private static final int ICON_SHORTCUT = KeyboardIconsSet.getIconId(
-            KeyboardIconsSet.NAME_SHORTCUT_KEY);
-    private static final int ICON_SETTINGS = KeyboardIconsSet.getIconId(
-            KeyboardIconsSet.NAME_SETTINGS_KEY);
-    private static final int ICON_LANGUAGE_SWITCH = KeyboardIconsSet.getIconId(
-            KeyboardIconsSet.NAME_LANGUAGE_SWITCH_KEY);
-    private static final int ICON_ENTER = KeyboardIconsSet.getIconId(
-            KeyboardIconsSet.NAME_ENTER_KEY);
-    private static final int ICON_EMOJI_ACTION = KeyboardIconsSet.getIconId(
-            KeyboardIconsSet.NAME_EMOJI_ACTION_KEY);
-    private static final int ICON_EMOJI_NORMAL = KeyboardIconsSet.getIconId(
-            KeyboardIconsSet.NAME_EMOJI_NORMAL_KEY);
-
-    // Functional keys.
-    public static final ExpectedKey DELETE_KEY = key(ICON_DELETE, Constants.CODE_DELETE);
-    public static final ExpectedKey TAB_KEY = key(ICON_TAB, Constants.CODE_TAB);
-    public static final ExpectedKey SHORTCUT_KEY = key(ICON_SHORTCUT, Constants.CODE_SHORTCUT);
-    public static final ExpectedKey SETTINGS_KEY = key(ICON_SETTINGS, Constants.CODE_SETTINGS);
-    public static final ExpectedKey LANGUAGE_SWITCH_KEY = key(
-            ICON_LANGUAGE_SWITCH, Constants.CODE_LANGUAGE_SWITCH);
-    public static final ExpectedKey ENTER_KEY = key(ICON_ENTER, Constants.CODE_ENTER);
-    public static final ExpectedKey EMOJI_ACTION_KEY = key(ICON_EMOJI_ACTION, Constants.CODE_EMOJI);
-    public static final ExpectedKey EMOJI_NORMAL_KEY = key(ICON_EMOJI_NORMAL, Constants.CODE_EMOJI);
-    public static final ExpectedKey SPACE_KEY = key(ICON_SPACE, Constants.CODE_SPACE);
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java
index 0e1c71c..2674a6a 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKey.java
@@ -148,6 +148,18 @@
         return newInstance(mVisual.toUpperCase(locale), mOutput.toUpperCase(locale));
     }
 
+    public ExpectedKey preserveCase() {
+        final ExpectedKey[] moreKeys = getMoreKeys();
+        final ExpectedKey[] casePreservedMoreKeys = new ExpectedKey[moreKeys.length];
+        for (int index = 0; index < moreKeys.length; index++) {
+            final ExpectedKey moreKey = moreKeys[index];
+            casePreservedMoreKeys[index] = newInstance(
+                    moreKey.getVisual().preserveCase(), moreKey.getOutput().preserveCase());
+        }
+        return newInstance(
+                getVisual().preserveCase(), getOutput().preserveCase(), casePreservedMoreKeys);
+    }
+
     public boolean equalsTo(final Key key) {
         // This key has no "more keys".
         return mVisual.equalsTo(key) && mOutput.equalsTo(key) && key.getMoreKeys() == null;
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java
index 1be51e6..737d169 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyOutput.java
@@ -42,6 +42,7 @@
     }
 
     abstract ExpectedKeyOutput toUpperCase(final Locale locale);
+    abstract ExpectedKeyOutput preserveCase();
     abstract boolean equalsTo(final String text);
     abstract boolean equalsTo(final Key key);
     abstract boolean equalsTo(final MoreKeySpec moreKeySpec);
@@ -69,6 +70,11 @@
         }
 
         @Override
+        ExpectedKeyOutput preserveCase() {
+            return new CasePreservedCode(mCode);
+        }
+
+        @Override
         boolean equalsTo(final String text) {
             return StringUtils.codePointCount(text) == 1 && text.codePointAt(0) == mCode;
         }
@@ -93,6 +99,16 @@
             return Constants.isLetterCode(mCode) ? StringUtils.newSingleCodePointString(mCode)
                     : Constants.printableCode(mCode);
         }
+
+        private static class CasePreservedCode extends Code {
+            CasePreservedCode(final int code) { super(code); }
+
+            @Override
+            ExpectedKeyOutput toUpperCase(final Locale locale) { return this; }
+
+            @Override
+            ExpectedKeyOutput preserveCase() { return this; }
+        }
     }
 
     /**
@@ -109,6 +125,11 @@
         }
 
         @Override
+        ExpectedKeyOutput preserveCase() {
+            return new CasePreservedText(mText);
+        }
+
+        @Override
         boolean equalsTo(final String text) {
             return text.equals(text);
         }
@@ -134,5 +155,15 @@
         public String toString() {
             return mText;
         }
+
+        private static class CasePreservedText extends Text {
+            CasePreservedText(final String text) { super(text); }
+
+            @Override
+            ExpectedKeyOutput toUpperCase(final Locale locale) { return this; }
+
+            @Override
+            ExpectedKeyOutput preserveCase() { return this; }
+        }
     }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java
index 0a0da32..facdf70 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyVisual.java
@@ -37,6 +37,7 @@
     }
 
     abstract ExpectedKeyVisual toUpperCase(final Locale locale);
+    abstract ExpectedKeyVisual preserveCase();
     abstract boolean equalsTo(final String text);
     abstract boolean equalsTo(final Key key);
     abstract boolean equalsTo(final MoreKeySpec moreKeySpec);
@@ -59,6 +60,11 @@
         }
 
         @Override
+        ExpectedKeyVisual preserveCase() {
+            return this;
+        }
+
+        @Override
         boolean equalsTo(final String text) {
             return false;
         }
@@ -103,6 +109,11 @@
         }
 
         @Override
+        ExpectedKeyVisual preserveCase() {
+            return new CasePreservedLabel(mLabel);
+        }
+
+        @Override
         boolean equalsTo(final String text) {
             return mLabel.equals(text);
         }
@@ -131,5 +142,15 @@
         public String toString() {
             return mLabel;
         }
+
+        private static class CasePreservedLabel extends Label {
+            CasePreservedLabel(final String label) { super(label); }
+
+            @Override
+            ExpectedKeyVisual toUpperCase(final Locale locale) { return this; }
+
+            @Override
+            ExpectedKeyVisual preserveCase() { return this; }
+        }
     }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakEmail.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakEmail.java
new file mode 100644
index 0000000..37ca092
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakEmail.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.InputType;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
+import com.android.inputmethod.keyboard.layout.Dvorak;
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+import com.android.inputmethod.keyboard.layout.tests.TestsEnglishDvorak.EnglishDvorakCustomizer;
+
+import java.util.Locale;
+
+/**
+ * en_US: English (United States)/dvorak, email input field.
+ */
+@SmallTest
+public class TestsDvorakEmail extends LayoutTestsBase {
+    private static final Locale LOCALE = new Locale("en", "US");
+    private static final LayoutBase LAYOUT = new DvorakEmail(new DvorakEmailCustomizer(LOCALE));
+
+    @Override
+    LayoutBase getLayout() { return LAYOUT; }
+
+    @Override
+    protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+            final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
+            final boolean languageSwitchKeyEnabled) {
+        final EditorInfo emailField = new EditorInfo();
+        emailField.inputType =
+                InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+        return super.createKeyboardLayoutSet(
+                subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled);
+    }
+
+    private static class DvorakEmailCustomizer extends EnglishDvorakCustomizer {
+        DvorakEmailCustomizer(final Locale locale) {
+            super(locale);
+        }
+
+        @Override
+        public ExpectedKey getEnterKey(final boolean isPhone) {
+            return isPhone ? LayoutBase.ENTER_KEY : super.getEnterKey(isPhone);
+        }
+
+        @Override
+        public ExpectedKey getEmojiKey(final boolean isPhone) {
+            return LayoutBase.DOMAIN_KEY;
+        }
+
+        @Override
+        public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
+            return isPhone ? super.getKeysLeftToSpacebar(isPhone)
+                    : joinKeys(key("@", LayoutBase.SETTINGS_KEY));
+        }
+    }
+
+    private static class DvorakEmail extends Dvorak {
+        public DvorakEmail(final LayoutCustomizer customizer) {
+            super(customizer);
+        }
+
+        @Override
+        protected ExpectedKey getRow1_1Key(final boolean isPhone, final int elementId) {
+            if (isPhone && (elementId == KeyboardId.ELEMENT_ALPHABET
+                    || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED)) {
+                return key("@", joinMoreKeys(additionalMoreKey("1")));
+            }
+            return super.getRow1_1Key(isPhone, elementId);
+        }
+    }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakUrl.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakUrl.java
new file mode 100644
index 0000000..3bcae0c
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsDvorakUrl.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.InputType;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
+import com.android.inputmethod.keyboard.layout.Dvorak;
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+import com.android.inputmethod.keyboard.layout.tests.TestsEnglishDvorak.EnglishDvorakCustomizer;
+
+import java.util.Locale;
+
+/**
+ * en_US: English (United States)/dvorak, URL input field.
+ */
+@SmallTest
+public class TestsDvorakUrl extends LayoutTestsBase {
+    private static final Locale LOCALE = new Locale("en", "US");
+    private static final LayoutBase LAYOUT = new DvorakEmail(new DvorakUrlCustomizer(LOCALE));
+
+    @Override
+    LayoutBase getLayout() { return LAYOUT; }
+
+    @Override
+    protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+            final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
+            final boolean languageSwitchKeyEnabled) {
+        final EditorInfo emailField = new EditorInfo();
+        emailField.inputType =
+                InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI;
+        return super.createKeyboardLayoutSet(
+                subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled);
+    }
+
+    private static class DvorakUrlCustomizer extends EnglishDvorakCustomizer {
+        DvorakUrlCustomizer(final Locale locale) {
+            super(locale);
+        }
+
+        @Override
+        public ExpectedKey getEnterKey(final boolean isPhone) {
+            return isPhone ? LayoutBase.ENTER_KEY : super.getEnterKey(isPhone);
+        }
+
+        @Override
+        public ExpectedKey getEmojiKey(final boolean isPhone) {
+            return LayoutBase.DOMAIN_KEY;
+        }
+
+        @Override
+        public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
+            return isPhone ? super.getKeysLeftToSpacebar(isPhone)
+                    : joinKeys(key("/", LayoutBase.SETTINGS_KEY));
+        }
+    }
+
+    private static class DvorakEmail extends Dvorak {
+        public DvorakEmail(final LayoutCustomizer customizer) {
+            super(customizer);
+        }
+
+        @Override
+        protected ExpectedKey getRow1_1Key(final boolean isPhone, final int elementId) {
+            if (isPhone && (elementId == KeyboardId.ELEMENT_ALPHABET
+                    || elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED)) {
+                return key("/", joinMoreKeys(additionalMoreKey("1")));
+            }
+            return super.getRow1_1Key(isPhone, elementId);
+        }
+    }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishDvorak.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishDvorak.java
index a052693..e647f8a 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishDvorak.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsEnglishDvorak.java
@@ -36,7 +36,7 @@
     @Override
     LayoutBase getLayout() { return LAYOUT; }
 
-    private static class EnglishDvorakCustomizer extends DvorakCustomizer {
+    public static class EnglishDvorakCustomizer extends DvorakCustomizer {
         private final EnglishCustomizer mEnglishCustomizer;
 
         EnglishDvorakCustomizer(final Locale locale) {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyEmail.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyEmail.java
new file mode 100644
index 0000000..8563d69
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyEmail.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.InputType;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.Qwerty;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+
+import java.util.Locale;
+
+/**
+ * en_US: English (United States)/qwerty, email input field.
+ */
+@SmallTest
+public class TestsQwertyEmail extends LayoutTestsBase {
+    private static final Locale LOCALE = new Locale("en", "US");
+    private static final LayoutBase LAYOUT = new Qwerty(new EnglishEmailCustomizer(LOCALE));
+
+    @Override
+    LayoutBase getLayout() { return LAYOUT; }
+
+    @Override
+    protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+            final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
+            final boolean languageSwitchKeyEnabled) {
+        final EditorInfo emailField = new EditorInfo();
+        emailField.inputType =
+                InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS;
+        return super.createKeyboardLayoutSet(
+                subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled);
+    }
+
+    private static class EnglishEmailCustomizer extends EnglishCustomizer {
+        EnglishEmailCustomizer(final Locale locale) {
+            super(locale);
+        }
+
+        @Override
+        public ExpectedKey getEnterKey(final boolean isPhone) {
+            return isPhone ? LayoutBase.ENTER_KEY : super.getEnterKey(isPhone);
+        }
+
+        @Override
+        public ExpectedKey getEmojiKey(final boolean isPhone) {
+            return LayoutBase.DOMAIN_KEY;
+        }
+
+        @Override
+        public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
+            return joinKeys(key("@", LayoutBase.SETTINGS_KEY));
+        }
+    }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyUrl.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyUrl.java
new file mode 100644
index 0000000..1c1a2bb
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsQwertyUrl.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.InputType;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.keyboard.KeyboardLayoutSet;
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.Qwerty;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+
+import java.util.Locale;
+
+/**
+ * en_US: English (United States)/qwerty, URL input field.
+ */
+@SmallTest
+public class TestsQwertyUrl extends LayoutTestsBase {
+    private static final Locale LOCALE = new Locale("en", "US");
+    private static final LayoutBase LAYOUT = new Qwerty(new EnglishUrlCustomizer(LOCALE));
+
+    @Override
+    LayoutBase getLayout() { return LAYOUT; }
+
+    @Override
+    protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
+            final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
+            final boolean languageSwitchKeyEnabled) {
+        final EditorInfo emailField = new EditorInfo();
+        emailField.inputType =
+                InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI;
+        return super.createKeyboardLayoutSet(
+                subtype, emailField, voiceInputKeyEnabled, languageSwitchKeyEnabled);
+    }
+
+    private static class EnglishUrlCustomizer extends EnglishCustomizer {
+        EnglishUrlCustomizer(final Locale locale) {
+            super(locale);
+        }
+
+        @Override
+        public ExpectedKey getEnterKey(final boolean isPhone) {
+            return isPhone ? LayoutBase.ENTER_KEY : super.getEnterKey(isPhone);
+        }
+
+        @Override
+        public ExpectedKey getEmojiKey(final boolean isPhone) {
+            return LayoutBase.DOMAIN_KEY;
+        }
+
+        @Override
+        public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
+            return joinKeys(key("/", LayoutBase.SETTINGS_KEY));
+        }
+    }
+}
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index 986fb10..d7a649a 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -36,6 +36,7 @@
 import android.widget.FrameLayout;
 
 import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
+import com.android.inputmethod.event.Event;
 import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
@@ -263,14 +264,16 @@
         // but keep them in mind if something breaks. Commenting them out as is should work.
         //mLatinIME.onPressKey(codePoint, 0 /* repeatCount */, true /* isSinglePointer */);
         final Key key = mKeyboard.getKey(codePoint);
+        final Event event;
         if (key == null) {
-            mLatinIME.onCodeInput(codePoint, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
-                    isKeyRepeat);
+            event = Event.createSoftwareKeypressEvent(codePoint, Event.NOT_A_KEY_CODE,
+                    Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, isKeyRepeat);
         } else {
             final int x = key.getX() + key.getWidth() / 2;
             final int y = key.getY() + key.getHeight() / 2;
-            mLatinIME.onCodeInput(codePoint, x, y, isKeyRepeat);
+            event = mLatinIME.createSoftwareKeypressEvent(codePoint, x, y, isKeyRepeat);
         }
+        mLatinIME.onEvent(event);
         // Also see the comment at the top of this function about onReleaseKey
         //mLatinIME.onReleaseKey(codePoint, false /* withSliding */);
     }
diff --git a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
index a5f20b5..2785dec 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
@@ -23,24 +23,49 @@
 
 import java.util.ArrayList;
 import java.util.Locale;
-import java.util.Random;
 
 @SmallTest
 public class SuggestedWordsTests extends AndroidTestCase {
+
+    /**
+     * Helper method to create a dummy {@link SuggestedWordInfo} with specifying
+     * {@link SuggestedWordInfo#KIND_TYPED}.
+     *
+     * @param word the word to be used to create {@link SuggestedWordInfo}.
+     * @return a new instance of {@link SuggestedWordInfo}.
+     */
+    private static SuggestedWordInfo createTypedWordInfo(final String word) {
+        // Use 100 as the frequency because the numerical value does not matter as
+        // long as it's > 1 and < INT_MAX.
+        return new SuggestedWordInfo(word, 100 /* score */,
+                SuggestedWordInfo.KIND_TYPED,
+                null /* sourceDict */,
+                SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                1 /* autoCommitFirstWordConfidence */);
+    }
+
+    /**
+     * Helper method to create a dummy {@link SuggestedWordInfo} with specifying
+     * {@link SuggestedWordInfo#KIND_CORRECTION}.
+     *
+     * @param word the word to be used to create {@link SuggestedWordInfo}.
+     * @return a new instance of {@link SuggestedWordInfo}.
+     */
+    private static SuggestedWordInfo createCorrectionWordInfo(final String word) {
+        return new SuggestedWordInfo(word, 1 /* score */,
+                SuggestedWordInfo.KIND_CORRECTION,
+                null /* sourceDict */,
+                SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
+    }
+
     public void testGetSuggestedWordsExcludingTypedWord() {
         final String TYPED_WORD = "typed";
-        final int TYPED_WORD_FREQ = 5;
         final int NUMBER_OF_ADDED_SUGGESTIONS = 5;
         final ArrayList<SuggestedWordInfo> list = new ArrayList<>();
-        list.add(new SuggestedWordInfo(TYPED_WORD, TYPED_WORD_FREQ,
-                SuggestedWordInfo.KIND_TYPED, null /* sourceDict */,
-                SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
-                SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
+        list.add(createTypedWordInfo(TYPED_WORD));
         for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) {
-            list.add(new SuggestedWordInfo("" + i, 1, SuggestedWordInfo.KIND_CORRECTION,
-                    null /* sourceDict */,
-                    SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
-                    SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
+            list.add(createCorrectionWordInfo(Integer.toString(i)));
         }
 
         final SuggestedWords words = new SuggestedWords(
@@ -66,19 +91,9 @@
     }
 
     // Helper for testGetTransformedWordInfo
-    private SuggestedWordInfo createWordInfo(final String s) {
-        // Use 100 as the frequency because the numerical value does not matter as
-        // long as it's > 1 and < INT_MAX.
-        return new SuggestedWordInfo(s, 100,
-                SuggestedWordInfo.KIND_TYPED, null /* sourceDict */,
-                SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
-                new Random().nextInt(1000000) /* autoCommitFirstWordConfidence */);
-    }
-
-    // Helper for testGetTransformedWordInfo
     private SuggestedWordInfo transformWordInfo(final String info,
             final int trailingSingleQuotesCount) {
-        final SuggestedWordInfo suggestedWordInfo = createWordInfo(info);
+        final SuggestedWordInfo suggestedWordInfo = createTypedWordInfo(info);
         final SuggestedWordInfo returnedWordInfo =
                 Suggest.getTransformedSuggestedWordInfo(suggestedWordInfo,
                 Locale.ENGLISH, false /* isAllUpperCase */, false /* isFirstCharCapitalized */,
@@ -102,4 +117,35 @@
         result = transformWordInfo("didn't", 3);
         assertEquals(result.mWord, "didn't''");
     }
+
+    public void testGetTypedWordInfoOrNull() {
+        final String TYPED_WORD = "typed";
+        final int NUMBER_OF_ADDED_SUGGESTIONS = 5;
+        final ArrayList<SuggestedWordInfo> list = new ArrayList<>();
+        list.add(createTypedWordInfo(TYPED_WORD));
+        for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) {
+            list.add(createCorrectionWordInfo(Integer.toString(i)));
+        }
+
+        // Make sure getTypedWordInfoOrNull() returns non-null object.
+        final SuggestedWords wordsWithTypedWord = new SuggestedWords(
+                list, null /* rawSuggestions */,
+                false /* typedWordValid */,
+                false /* willAutoCorrect */,
+                false /* isObsoleteSuggestions */,
+                false /* isPrediction*/,
+                SuggestedWords.INPUT_STYLE_NONE);
+        final SuggestedWordInfo typedWord = wordsWithTypedWord.getTypedWordInfoOrNull();
+        assertNotNull(typedWord);
+        assertEquals(TYPED_WORD, typedWord.mWord);
+
+        // Make sure getTypedWordInfoOrNull() returns null.
+        final SuggestedWords wordsWithoutTypedWord =
+                wordsWithTypedWord.getSuggestedWordsExcludingTypedWord(
+                        SuggestedWords.INPUT_STYLE_NONE);
+        assertNull(wordsWithoutTypedWord.getTypedWordInfoOrNull());
+
+        // Make sure getTypedWordInfoOrNull() returns null.
+        assertNull(SuggestedWords.EMPTY.getTypedWordInfoOrNull());
+    }
 }
diff --git a/tests/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelperTests.java b/tests/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelperTests.java
new file mode 100644
index 0000000..f3273a2
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelperTests.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.suggestions;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.inputmethod.latin.SuggestedWords;
+
+@SmallTest
+public class SuggestionStripLayoutHelperTests extends AndroidTestCase {
+    private static void confirmShowTypedWord(final String message, final int inputType) {
+        assertFalse(message, SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                inputType,
+                false /* gestureFloatingPreviewTextEnabled */,
+                false /* shouldShowUiToAcceptTypedWord */));
+        assertFalse(message, SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                inputType,
+                true /* gestureFloatingPreviewTextEnabled */,
+                false /* shouldShowUiToAcceptTypedWord */));
+        assertFalse(message, SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                inputType,
+                false /* gestureFloatingPreviewTextEnabled */,
+                true /* shouldShowUiToAcceptTypedWord */));
+        assertFalse(message, SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                inputType,
+                true /* gestureFloatingPreviewTextEnabled */,
+                true /* shouldShowUiToAcceptTypedWord */));
+    }
+
+    public void testShouldShowTypedWord() {
+        confirmShowTypedWord("no input style",
+                SuggestedWords.INPUT_STYLE_NONE);
+        confirmShowTypedWord("application specifed",
+                SuggestedWords.INPUT_STYLE_APPLICATION_SPECIFIED);
+        confirmShowTypedWord("recorrection",
+                SuggestedWords.INPUT_STYLE_RECORRECTION);
+    }
+
+    public void testshouldOmitTypedWordWhileTyping() {
+        assertFalse("typing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                SuggestedWords.INPUT_STYLE_TYPING,
+                false /* gestureFloatingPreviewTextEnabled */,
+                false /* shouldShowUiToAcceptTypedWord */));
+        assertFalse("typing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                SuggestedWords.INPUT_STYLE_TYPING,
+                true /* gestureFloatingPreviewTextEnabled */,
+                false /* shouldShowUiToAcceptTypedWord */));
+        assertTrue("typing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                SuggestedWords.INPUT_STYLE_TYPING,
+                false /* gestureFloatingPreviewTextEnabled */,
+                true /* shouldShowUiToAcceptTypedWord */));
+        assertTrue("typing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                SuggestedWords.INPUT_STYLE_TYPING,
+                true /* gestureFloatingPreviewTextEnabled */,
+                true /* shouldShowUiToAcceptTypedWord */));
+    }
+
+    public void testshouldOmitTypedWordWhileGesturing() {
+        assertFalse("gesturing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                SuggestedWords.INPUT_STYLE_UPDATE_BATCH,
+                false /* gestureFloatingPreviewTextEnabled */,
+                false /* shouldShowUiToAcceptTypedWord */));
+        assertFalse("gesturing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                SuggestedWords.INPUT_STYLE_UPDATE_BATCH,
+                true /* gestureFloatingPreviewTextEnabled */,
+                false /* shouldShowUiToAcceptTypedWord */));
+        assertFalse("gesturing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                SuggestedWords.INPUT_STYLE_UPDATE_BATCH,
+                false /* gestureFloatingPreviewTextEnabled */,
+                true /* shouldShowUiToAcceptTypedWord */));
+        assertTrue("gesturing", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                SuggestedWords.INPUT_STYLE_UPDATE_BATCH,
+                true /* gestureFloatingPreviewTextEnabled */,
+                true /* shouldShowUiToAcceptTypedWord */));
+    }
+
+    public void testshouldOmitTypedWordWhenGestured() {
+        assertFalse("gestured", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                SuggestedWords.INPUT_STYLE_TAIL_BATCH,
+                false /* gestureFloatingPreviewTextEnabled */,
+                false /* shouldShowUiToAcceptTypedWord */));
+        assertFalse("gestured", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                SuggestedWords.INPUT_STYLE_TAIL_BATCH,
+                true /* gestureFloatingPreviewTextEnabled */,
+                false /* shouldShowUiToAcceptTypedWord */));
+        assertTrue("gestured", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                SuggestedWords.INPUT_STYLE_TAIL_BATCH,
+                false /* gestureFloatingPreviewTextEnabled */,
+                true /* shouldShowUiToAcceptTypedWord */));
+        assertTrue("gestured", SuggestionStripLayoutHelper.shouldOmitTypedWord(
+                SuggestedWords.INPUT_STYLE_TAIL_BATCH,
+                true /* gestureFloatingPreviewTextEnabled */,
+                true /* shouldShowUiToAcceptTypedWord */));
+    }
+
+    // Note that this unit test assumes that the number of suggested words in the suggestion strip
+    // is 3.
+    private static final int POSITION_OMIT = -1;
+    private static final int POSITION_LEFT = 0;
+    private static final int POSITION_CENTER = 1;
+    private static final int POSITION_RIGHT = 2;
+
+    public void testGetPositionInSuggestionStrip() {
+        assertEquals("1st word without auto correction", POSITION_CENTER,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        SuggestedWords.INDEX_OF_TYPED_WORD /* indexInSuggestedWords */,
+                        false /* willAutoCorrect */,
+                        false /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+        assertEquals("2nd word without auto correction", POSITION_LEFT,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        SuggestedWords.INDEX_OF_AUTO_CORRECTION /* indexInSuggestedWords */,
+                        false /* willAutoCorrect */,
+                        false /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+        assertEquals("3rd word without auto correction", POSITION_RIGHT,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        2 /* indexInSuggestedWords */,
+                        false /* willAutoCorrect */,
+                        false /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+
+        assertEquals("typed word with auto correction", POSITION_LEFT,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        SuggestedWords.INDEX_OF_TYPED_WORD /* indexInSuggestedWords */,
+                        true /* willAutoCorrect */,
+                        false /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+        assertEquals("2nd word with auto correction", POSITION_CENTER,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        SuggestedWords.INDEX_OF_AUTO_CORRECTION /* indexInSuggestedWords */,
+                        true /* willAutoCorrect */,
+                        false /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+        assertEquals("3rd word with auto correction", POSITION_RIGHT,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        2 /* indexInSuggestedWords */,
+                        true /* willAutoCorrect */,
+                        false /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+
+        assertEquals("1st word without auto correction", POSITION_OMIT,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        SuggestedWords.INDEX_OF_TYPED_WORD /* indexInSuggestedWords */,
+                        false /* willAutoCorrect */,
+                        true /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+        assertEquals("2nd word without auto correction", POSITION_CENTER,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        SuggestedWords.INDEX_OF_AUTO_CORRECTION /* indexInSuggestedWords */,
+                        false /* willAutoCorrect */,
+                        true /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+        assertEquals("3rd word without auto correction", POSITION_LEFT,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        2 /* indexInSuggestedWords */,
+                        false /* willAutoCorrect */,
+                        true /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+        assertEquals("4th word without auto correction", POSITION_RIGHT,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        3 /* indexInSuggestedWords */,
+                        false /* willAutoCorrect */,
+                        true /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+
+        assertEquals("typed word with auto correction", POSITION_OMIT,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        SuggestedWords.INDEX_OF_TYPED_WORD /* indexInSuggestedWords */,
+                        true /* willAutoCorrect */,
+                        true /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+        assertEquals("2nd word with auto correction", POSITION_CENTER,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        SuggestedWords.INDEX_OF_AUTO_CORRECTION /* indexInSuggestedWords */,
+                        true /* willAutoCorrect */,
+                        true /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+        assertEquals("3rd word with auto correction", POSITION_LEFT,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        2 /* indexInSuggestedWords */,
+                        true /* willAutoCorrect */,
+                        true /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+        assertEquals("4th word with auto correction", POSITION_RIGHT,
+                SuggestionStripLayoutHelper.getPositionInSuggestionStrip(
+                        3 /* indexInSuggestedWords */,
+                        true /* willAutoCorrect */,
+                        true /* omitTypedWord */,
+                        POSITION_CENTER /* centerPositionInStrip */,
+                        POSITION_LEFT /* typedWordPositionWhenAutoCorrect */));
+    }
+}
diff --git a/tests/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtilsTests.java
index 91c9c37..66a12b9 100644
--- a/tests/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/AdditionalSubtypeUtilsTests.java
@@ -151,25 +151,25 @@
     }
 
     public void testRestorable() {
-        final InputMethodSubtype EN_UK_DVORAK =
+        final InputMethodSubtype EN_US_DVORAK =
                 AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
                         Locale.US.toString(), "dvorak");
         final InputMethodSubtype ZZ_AZERTY =
                 AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
                         SubtypeLocaleUtils.NO_LANGUAGE, "azerty");
-        assertEnUsDvorak(EN_UK_DVORAK);
+        assertEnUsDvorak(EN_US_DVORAK);
         assertAzerty(ZZ_AZERTY);
 
         // Make sure the subtype can be stored and restored in a deterministic manner.
-        final InputMethodSubtype[] subtypes = { EN_UK_DVORAK, ZZ_AZERTY };
+        final InputMethodSubtype[] subtypes = { EN_US_DVORAK, ZZ_AZERTY };
         final String prefSubtype = AdditionalSubtypeUtils.createPrefSubtypes(subtypes);
         final InputMethodSubtype[] restoredSubtypes =
                 AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefSubtype);
         assertEquals(2, restoredSubtypes.length);
-        final InputMethodSubtype restored_EN_UK_DVORAK = restoredSubtypes[0];
+        final InputMethodSubtype restored_EN_US_DVORAK = restoredSubtypes[0];
         final InputMethodSubtype restored_ZZ_AZERTY = restoredSubtypes[1];
 
-        assertEnUsDvorak(restored_EN_UK_DVORAK);
+        assertEnUsDvorak(restored_EN_US_DVORAK);
         assertAzerty(restored_ZZ_AZERTY);
     }
 }
diff --git a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java
index aef517c..b766ab2 100644
--- a/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/SpacebarLanguageUtilsTests.java
@@ -24,6 +24,7 @@
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 
 import java.util.ArrayList;
 import java.util.Locale;
@@ -31,28 +32,28 @@
 @SmallTest
 public class SpacebarLanguageUtilsTests extends AndroidTestCase {
     // All input method subtypes of LatinIME.
-    private final ArrayList<InputMethodSubtype> mSubtypesList = new ArrayList<>();
+    private final ArrayList<RichInputMethodSubtype> mSubtypesList = new ArrayList<>();
 
     private RichInputMethodManager mRichImm;
     private Resources mRes;
 
-    InputMethodSubtype EN_US;
-    InputMethodSubtype EN_GB;
-    InputMethodSubtype ES_US;
-    InputMethodSubtype FR;
-    InputMethodSubtype FR_CA;
-    InputMethodSubtype FR_CH;
-    InputMethodSubtype DE;
-    InputMethodSubtype DE_CH;
-    InputMethodSubtype HI_ZZ;
-    InputMethodSubtype ZZ;
-    InputMethodSubtype DE_QWERTY;
-    InputMethodSubtype FR_QWERTZ;
-    InputMethodSubtype EN_US_AZERTY;
-    InputMethodSubtype EN_UK_DVORAK;
-    InputMethodSubtype ES_US_COLEMAK;
-    InputMethodSubtype ZZ_AZERTY;
-    InputMethodSubtype ZZ_PC;
+    RichInputMethodSubtype EN_US;
+    RichInputMethodSubtype EN_GB;
+    RichInputMethodSubtype ES_US;
+    RichInputMethodSubtype FR;
+    RichInputMethodSubtype FR_CA;
+    RichInputMethodSubtype FR_CH;
+    RichInputMethodSubtype DE;
+    RichInputMethodSubtype DE_CH;
+    RichInputMethodSubtype HI_ZZ;
+    RichInputMethodSubtype ZZ;
+    RichInputMethodSubtype DE_QWERTY;
+    RichInputMethodSubtype FR_QWERTZ;
+    RichInputMethodSubtype EN_US_AZERTY;
+    RichInputMethodSubtype EN_UK_DVORAK;
+    RichInputMethodSubtype ES_US_COLEMAK;
+    RichInputMethodSubtype ZZ_AZERTY;
+    RichInputMethodSubtype ZZ_PC;
 
     @Override
     protected void setUp() throws Exception {
@@ -67,53 +68,60 @@
         final int subtypeCount = imi.getSubtypeCount();
         for (int index = 0; index < subtypeCount; index++) {
             final InputMethodSubtype subtype = imi.getSubtypeAt(index);
-            mSubtypesList.add(subtype);
+            mSubtypesList.add(new RichInputMethodSubtype(subtype));
         }
 
-        EN_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.US.toString(), "qwerty");
-        EN_GB = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.UK.toString(), "qwerty");
-        ES_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                "es_US", "spanish");
-        FR = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.FRENCH.toString(), "azerty");
-        FR_CA = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.CANADA_FRENCH.toString(), "qwerty");
-        FR_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                "fr_CH", "swiss");
-        DE = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                Locale.GERMAN.toString(), "qwertz");
-        DE_CH = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                "de_CH", "swiss");
-        HI_ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                "hi_ZZ", "qwerty");
-        ZZ = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
-                SubtypeLocaleUtils.NO_LANGUAGE, "qwerty");
-        DE_QWERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                Locale.GERMAN.toString(), "qwerty");
-        FR_QWERTZ = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                Locale.FRENCH.toString(), "qwertz");
-        EN_US_AZERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                Locale.US.toString(), "azerty");
-        EN_UK_DVORAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                Locale.UK.toString(), "dvorak");
-        ES_US_COLEMAK = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                "es_US", "colemak");
-        ZZ_AZERTY = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                SubtypeLocaleUtils.NO_LANGUAGE, "azerty");
-        ZZ_PC = AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
-                SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty");
+        EN_US = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.US.toString(), "qwerty"));
+        EN_GB = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.UK.toString(), "qwerty"));
+        ES_US = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                "es_US", "spanish"));
+        FR = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.FRENCH.toString(), "azerty"));
+        FR_CA = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.CANADA_FRENCH.toString(), "qwerty"));
+        FR_CH = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                "fr_CH", "swiss"));
+        DE = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                Locale.GERMAN.toString(), "qwertz"));
+        DE_CH = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                "de_CH", "swiss"));
+        HI_ZZ = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                "hi_ZZ", "qwerty"));
+        ZZ = new RichInputMethodSubtype(mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
+                SubtypeLocaleUtils.NO_LANGUAGE, "qwerty"));
+        DE_QWERTY = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    Locale.GERMAN.toString(), "qwerty"));
+        FR_QWERTZ = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    Locale.FRENCH.toString(), "qwertz"));
+        EN_US_AZERTY = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    Locale.US.toString(), "azerty"));
+        EN_UK_DVORAK = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    Locale.UK.toString(), "dvorak"));
+        ES_US_COLEMAK = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    "es_US", "colemak"));
+        ZZ_AZERTY = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    SubtypeLocaleUtils.NO_LANGUAGE, "azerty"));
+        ZZ_PC = new RichInputMethodSubtype(
+                AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+                    SubtypeLocaleUtils.NO_LANGUAGE, "pcqwerty"));
     }
 
     public void testAllFullDisplayNameForSpacebar() {
-        for (final InputMethodSubtype subtype : mSubtypesList) {
+        for (final RichInputMethodSubtype subtype : mSubtypesList) {
             final String subtypeName = SubtypeLocaleUtils
-                    .getSubtypeDisplayNameInSystemLocale(subtype);
-            final String spacebarText = SpacebarLanguageUtils.getFullDisplayName(subtype);
+                    .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype());
+            final String spacebarText = subtype.getFullDisplayName();
             final String languageName = SubtypeLocaleUtils
                     .getSubtypeLocaleDisplayName(subtype.getLocale());
-            if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
+            if (subtype.isNoLanguage()) {
                 assertFalse(subtypeName, spacebarText.contains(languageName));
             } else {
                 assertTrue(subtypeName, spacebarText.contains(languageName));
@@ -122,19 +130,19 @@
     }
 
    public void testAllMiddleDisplayNameForSpacebar() {
-        for (final InputMethodSubtype subtype : mSubtypesList) {
+        for (final RichInputMethodSubtype subtype : mSubtypesList) {
             final String subtypeName = SubtypeLocaleUtils
-                    .getSubtypeDisplayNameInSystemLocale(subtype);
+                    .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype());
             if (SubtypeLocaleUtils.sExceptionalLocaleDisplayedInRootLocale.contains(
                     subtype.getLocale())) {
                 // Skip test because the language part of this locale string doesn't represent
                 // the locale to be displayed on the spacebar (for example hi_ZZ and Hinglish).
                 continue;
             }
-            final String spacebarText = SpacebarLanguageUtils.getMiddleDisplayName(subtype);
-            if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
-                assertEquals(subtypeName,
-                        SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype), spacebarText);
+            final String spacebarText = subtype.getMiddleDisplayName();
+            if (subtype.isNoLanguage()) {
+                assertEquals(subtypeName, SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(
+                        subtype.getRawSubtype()), spacebarText);
             } else {
                 final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype);
                 assertEquals(subtypeName,
@@ -166,47 +174,27 @@
     private final RunInLocale<Void> testsPredefinedSubtypesForSpacebar = new RunInLocale<Void>() {
         @Override
         protected Void job(final Resources res) {
-            assertEquals("en_US", "English (US)",
-                    SpacebarLanguageUtils.getFullDisplayName(EN_US));
-            assertEquals("en_GB", "English (UK)",
-                    SpacebarLanguageUtils.getFullDisplayName(EN_GB));
-            assertEquals("es_US", "Español (EE.UU.)",
-                    SpacebarLanguageUtils.getFullDisplayName(ES_US));
-            assertEquals("fr", "Français",
-                    SpacebarLanguageUtils.getFullDisplayName(FR));
-            assertEquals("fr_CA", "Français (Canada)",
-                    SpacebarLanguageUtils.getFullDisplayName(FR_CA));
-            assertEquals("fr_CH", "Français (Suisse)",
-                    SpacebarLanguageUtils.getFullDisplayName(FR_CH));
-            assertEquals("de", "Deutsch",
-                    SpacebarLanguageUtils.getFullDisplayName(DE));
-            assertEquals("de_CH", "Deutsch (Schweiz)",
-                    SpacebarLanguageUtils.getFullDisplayName(DE_CH));
-            assertEquals("hi_ZZ", "Hinglish",
-                    SpacebarLanguageUtils.getFullDisplayName(HI_ZZ));
-            assertEquals("zz", "QWERTY",
-                    SpacebarLanguageUtils.getFullDisplayName(ZZ));
+            assertEquals("en_US", "English (US)", EN_US.getFullDisplayName());
+            assertEquals("en_GB", "English (UK)", EN_GB.getFullDisplayName());
+            assertEquals("es_US", "Español (EE.UU.)", ES_US.getFullDisplayName());
+            assertEquals("fr", "Français", FR.getFullDisplayName());
+            assertEquals("fr_CA", "Français (Canada)", FR_CA.getFullDisplayName());
+            assertEquals("fr_CH", "Français (Suisse)", FR_CH.getFullDisplayName());
+            assertEquals("de", "Deutsch", DE.getFullDisplayName());
+            assertEquals("de_CH", "Deutsch (Schweiz)", DE_CH.getFullDisplayName());
+            assertEquals("hi_ZZ", "Hinglish", HI_ZZ.getFullDisplayName());
+            assertEquals("zz", "QWERTY", ZZ.getFullDisplayName());
 
-            assertEquals("en_US", "English",
-                    SpacebarLanguageUtils.getMiddleDisplayName(EN_US));
-            assertEquals("en_GB", "English",
-                    SpacebarLanguageUtils.getMiddleDisplayName(EN_GB));
-            assertEquals("es_US", "Español",
-                    SpacebarLanguageUtils.getMiddleDisplayName(ES_US));
-            assertEquals("fr", "Français",
-                    SpacebarLanguageUtils.getMiddleDisplayName(FR));
-            assertEquals("fr_CA", "Français",
-                    SpacebarLanguageUtils.getMiddleDisplayName(FR_CA));
-            assertEquals("fr_CH", "Français",
-                    SpacebarLanguageUtils.getMiddleDisplayName(FR_CH));
-            assertEquals("de", "Deutsch",
-                    SpacebarLanguageUtils.getMiddleDisplayName(DE));
-            assertEquals("de_CH", "Deutsch",
-                    SpacebarLanguageUtils.getMiddleDisplayName(DE_CH));
-            assertEquals("hi_ZZ", "Hinglish",
-                    SpacebarLanguageUtils.getMiddleDisplayName(HI_ZZ));
-            assertEquals("zz", "QWERTY",
-                    SpacebarLanguageUtils.getMiddleDisplayName(ZZ));
+            assertEquals("en_US", "English", EN_US.getMiddleDisplayName());
+            assertEquals("en_GB", "English", EN_GB.getMiddleDisplayName());
+            assertEquals("es_US", "Español", ES_US.getMiddleDisplayName());
+            assertEquals("fr", "Français", FR.getMiddleDisplayName());
+            assertEquals("fr_CA", "Français", FR_CA.getMiddleDisplayName());
+            assertEquals("fr_CH", "Français", FR_CH.getMiddleDisplayName());
+            assertEquals("de", "Deutsch", DE.getMiddleDisplayName());
+            assertEquals("de_CH", "Deutsch", DE_CH.getMiddleDisplayName());
+            assertEquals("hi_ZZ", "Hinglish", HI_ZZ.getMiddleDisplayName());
+            assertEquals("zz", "QWERTY", ZZ.getMiddleDisplayName());
             return null;
         }
     };
@@ -214,35 +202,21 @@
     private final RunInLocale<Void> testsAdditionalSubtypesForSpacebar = new RunInLocale<Void>() {
         @Override
         protected Void job(final Resources res) {
-            assertEquals("fr qwertz", "Français",
-                    SpacebarLanguageUtils.getFullDisplayName(FR_QWERTZ));
-            assertEquals("de qwerty", "Deutsch",
-                    SpacebarLanguageUtils.getFullDisplayName(DE_QWERTY));
-            assertEquals("en_US azerty", "English (US)",
-                    SpacebarLanguageUtils.getFullDisplayName(EN_US_AZERTY));
-            assertEquals("en_UK dvorak", "English (UK)",
-                    SpacebarLanguageUtils.getFullDisplayName(EN_UK_DVORAK));
-            assertEquals("es_US colemak", "Español (EE.UU.)",
-                    SpacebarLanguageUtils.getFullDisplayName(ES_US_COLEMAK));
-            assertEquals("zz azerty", "AZERTY",
-                    SpacebarLanguageUtils.getFullDisplayName(ZZ_AZERTY));
-            assertEquals("zz pc", "PC",
-                    SpacebarLanguageUtils.getFullDisplayName(ZZ_PC));
+            assertEquals("fr qwertz", "Français", FR_QWERTZ.getFullDisplayName());
+            assertEquals("de qwerty", "Deutsch", DE_QWERTY.getFullDisplayName());
+            assertEquals("en_US azerty", "English (US)", EN_US_AZERTY.getFullDisplayName());
+            assertEquals("en_UK dvorak", "English (UK)", EN_UK_DVORAK.getFullDisplayName());
+            assertEquals("es_US colemak", "Español (EE.UU.)", ES_US_COLEMAK.getFullDisplayName());
+            assertEquals("zz azerty", "AZERTY", ZZ_AZERTY.getFullDisplayName());
+            assertEquals("zz pc", "PC", ZZ_PC.getFullDisplayName());
 
-            assertEquals("fr qwertz", "Français",
-                    SpacebarLanguageUtils.getMiddleDisplayName(FR_QWERTZ));
-            assertEquals("de qwerty", "Deutsch",
-                    SpacebarLanguageUtils.getMiddleDisplayName(DE_QWERTY));
-            assertEquals("en_US azerty", "English",
-                    SpacebarLanguageUtils.getMiddleDisplayName(EN_US_AZERTY));
-            assertEquals("en_UK dvorak", "English",
-                    SpacebarLanguageUtils.getMiddleDisplayName(EN_UK_DVORAK));
-            assertEquals("es_US colemak", "Español",
-                    SpacebarLanguageUtils.getMiddleDisplayName(ES_US_COLEMAK));
-            assertEquals("zz azerty", "AZERTY",
-                    SpacebarLanguageUtils.getMiddleDisplayName(ZZ_AZERTY));
-            assertEquals("zz pc", "PC",
-                    SpacebarLanguageUtils.getMiddleDisplayName(ZZ_PC));
+            assertEquals("fr qwertz", "Français", FR_QWERTZ.getMiddleDisplayName());
+            assertEquals("de qwerty", "Deutsch", DE_QWERTY.getMiddleDisplayName());
+            assertEquals("en_US azerty", "English", EN_US_AZERTY.getMiddleDisplayName());
+            assertEquals("en_UK dvorak", "English", EN_UK_DVORAK.getMiddleDisplayName());
+            assertEquals("es_US colemak", "Español", ES_US_COLEMAK.getMiddleDisplayName());
+            assertEquals("zz azerty", "AZERTY", ZZ_AZERTY.getMiddleDisplayName());
+            assertEquals("zz pc", "PC", ZZ_PC.getMiddleDisplayName());
             return null;
         }
     };
diff --git a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
index 4f0b3cc..5afbbbe 100644
--- a/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtilsTests.java
@@ -24,6 +24,7 @@
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.RichInputMethodSubtype;
 
 import java.util.ArrayList;
 import java.util.Locale;
@@ -31,7 +32,7 @@
 @SmallTest
 public class SubtypeLocaleUtilsTests extends AndroidTestCase {
     // All input method subtypes of LatinIME.
-    private final ArrayList<InputMethodSubtype> mSubtypesList = new ArrayList<>();
+    private final ArrayList<RichInputMethodSubtype> mSubtypesList = new ArrayList<>();
 
     private RichInputMethodManager mRichImm;
     private Resources mRes;
@@ -67,7 +68,7 @@
         final int subtypeCount = imi.getSubtypeCount();
         for (int index = 0; index < subtypeCount; index++) {
             final InputMethodSubtype subtype = imi.getSubtypeAt(index);
-            mSubtypesList.add(subtype);
+            mSubtypesList.add(new RichInputMethodSubtype(subtype));
         }
 
         EN_US = mRichImm.findSubtypeByLocaleAndKeyboardLayoutSet(
@@ -107,12 +108,12 @@
     }
 
     public void testAllFullDisplayName() {
-        for (final InputMethodSubtype subtype : mSubtypesList) {
+        for (final RichInputMethodSubtype subtype : mSubtypesList) {
             final String subtypeName = SubtypeLocaleUtils
-                    .getSubtypeDisplayNameInSystemLocale(subtype);
-            if (SubtypeLocaleUtils.isNoLanguage(subtype)) {
+                    .getSubtypeDisplayNameInSystemLocale(subtype.getRawSubtype());
+            if (subtype.isNoLanguage()) {
                 final String layoutName = SubtypeLocaleUtils
-                        .getKeyboardLayoutSetDisplayName(subtype);
+                        .getKeyboardLayoutSetDisplayName(subtype.getRawSubtype());
                 assertTrue(subtypeName, subtypeName.contains(layoutName));
             } else {
                 final String languageName = SubtypeLocaleUtils
@@ -308,10 +309,12 @@
                 .findSubtypeByLocaleAndKeyboardLayoutSet("iw", "hebrew");
         assertNotNull("Hebrew", HEBREW);
 
-        for (final InputMethodSubtype subtype : mSubtypesList) {
+        for (final RichInputMethodSubtype subtype : mSubtypesList) {
+            final InputMethodSubtype rawSubtype = subtype.getRawSubtype();
             final String subtypeName = SubtypeLocaleUtils
-                    .getSubtypeDisplayNameInSystemLocale(subtype);
-            if (subtype.equals(ARABIC) || subtype.equals(FARSI) || subtype.equals(HEBREW)) {
+                    .getSubtypeDisplayNameInSystemLocale(rawSubtype);
+            if (rawSubtype.equals(ARABIC) || rawSubtype.equals(FARSI)
+                    || rawSubtype.equals(HEBREW)) {
                 assertTrue(subtypeName, SubtypeLocaleUtils.isRtlLanguage(subtype));
             } else {
                 assertFalse(subtypeName, SubtypeLocaleUtils.isRtlLanguage(subtype));