Merge "Trigger haptic feedback at touch down on the EmojiPalettesView"
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
index d11d0f0..92f2466 100644
--- a/java/res/values-af/strings.xml
+++ b/java/res/values-af/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"tyd"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Steminvoerinstellings"</string>
+    <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Geen steminvoermetodes geaktiveer nie. Gaan taal- en invoerinstellings na."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Stel invoermetodes op"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Invoertale"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Stuur terugvoer"</string>
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
index 9b32cb3..3a248a8 100644
--- a/java/res/values-am/strings.xml
+++ b/java/res/values-am/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"ጊዜ"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"ዩ አር ኤል"</string>
     <string name="voice_input" msgid="3583258583521397548">"የድምፅ ግቤት ቁልፍ"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"ግቤት ሜተዶችን አዋቀር"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"ቋንቋዎች አግቤት"</string>
     <string name="send_feedback" msgid="1780431884109392046">"ግብረ-መልስ ላክ"</string>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index 845ea1c..fa9309f 100644
--- a/java/res/values-ar/strings.xml
+++ b/java/res/values-ar/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"الوقت"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"‏عنوان URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"مفتاح الإدخال الصوتي"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"إرسال تعليقات"</string>
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
index 2dfdb46..d4a1d91 100644
--- a/java/res/values-bg/strings.xml
+++ b/java/res/values-bg/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"часа"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL адреси"</string>
     <string name="voice_input" msgid="3583258583521397548">"Клавиш за гласово въвеждане"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"Конфигуриране на въвеждането"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Входни езици"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Изпращане на отзиви"</string>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
index bec13cb..9aff403 100644
--- a/java/res/values-ca/strings.xml
+++ b/java/res/values-ca/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Tecla d\'entrada de veu"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Envia comentaris"</string>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index 34f5fc1..77bae55 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"čas"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"adresy URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Klávesa hlasového vstupu"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Odeslat zpětnou vazbu"</string>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
index a190e9a..cd3a667 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"klokkeslæt"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"Webadresse"</string>
     <string name="voice_input" msgid="3583258583521397548">"Nøgle til stemmeinput"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Send feedback"</string>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
index d1d5225..1d0a549 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"Zeit"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Taste für Spracheingabe"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Feedback geben"</string>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index 9be2a70..c9086fd 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"ώρα"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"διεύθυνση URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Κλειδί φωνητικής εξόδου"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Αποστολή σχολίων"</string>
diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
index 2fbbd89..f344e73 100644
--- a/java/res/values-en-rGB/strings.xml
+++ b/java/res/values-en-rGB/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"time"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Voice input key"</string>
+    <string name="voice_input_disabled_summary" msgid="8141750303464726129">"No voice input methods enabled. Check Language &amp; input settings."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configure input methods"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Input languages"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Send feedback"</string>
diff --git a/java/res/values-en-rIN/strings.xml b/java/res/values-en-rIN/strings.xml
index 2fbbd89..f344e73 100644
--- a/java/res/values-en-rIN/strings.xml
+++ b/java/res/values-en-rIN/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"time"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Voice input key"</string>
+    <string name="voice_input_disabled_summary" msgid="8141750303464726129">"No voice input methods enabled. Check Language &amp; input settings."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configure input methods"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Input languages"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Send feedback"</string>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index 8d3cb60..0cbadc3 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Tecla de entrada por voz"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Enviar comentarios"</string>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
index d5f5c39..5427349 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Tecla de entrada de voz"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Danos tu opinión"</string>
diff --git a/java/res/values-et-rEE/strings.xml b/java/res/values-et-rEE/strings.xml
index 6a1336d..2c94c77 100644
--- a/java/res/values-et-rEE/strings.xml
+++ b/java/res/values-et-rEE/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"aeg"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Häälesisendi klahv"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Saatke tagasisidet"</string>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
index cfd2a4d..18c8222 100644
--- a/java/res/values-fa/strings.xml
+++ b/java/res/values-fa/strings.xml
@@ -123,6 +123,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"زمان"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"نشانی اینترنتی"</string>
     <string name="voice_input" msgid="3583258583521397548">"کلید ورودی صدا"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"پیکربندی روش‌های ورودی"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"زبان‌های ورودی"</string>
     <string name="send_feedback" msgid="1780431884109392046">"ارسال بازخورد"</string>
diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml
index fb8d70b..b729c2b 100644
--- a/java/res/values-fi/strings.xml
+++ b/java/res/values-fi/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"aika"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL-osoite"</string>
     <string name="voice_input" msgid="3583258583521397548">"Äänisyöteavain"</string>
+    <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Äänen syöttötapoja ei ole otettu käyttöön. Tarkista Kieli ja syöttötapa -asetukset."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Määritä syöttötavat"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Syöttökielet"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Lähetä palautetta"</string>
diff --git a/java/res/values-fr-rCA/strings.xml b/java/res/values-fr-rCA/strings.xml
index 553d482..d767165 100644
--- a/java/res/values-fr-rCA/strings.xml
+++ b/java/res/values-fr-rCA/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"Heure"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Touche de saisie vocale"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Envoyer des commentaires"</string>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index c8ef31a..43242e4 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"Heure"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Touche de saisie vocale"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"Configurer les modes de saisie"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Langues de saisie"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Envoyer des commentaires"</string>
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index aa14543..7b9cbfa 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"समय"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"ध्‍वनि‍ इनपुट कुंजी"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"सुझाव भेजें"</string>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index 65d077c..cb8dda1 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"vrijeme"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Tipka za glasovni unos"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Slanje povratnih informacija"</string>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
index a55f9d4..2948826 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"idő"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Hangbeviteli gomb"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Visszajelzés küldése"</string>
diff --git a/java/res/values-hy-rAM/strings.xml b/java/res/values-hy-rAM/strings.xml
index cad324c..68d44fb 100644
--- a/java/res/values-hy-rAM/strings.xml
+++ b/java/res/values-hy-rAM/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"ժամանակ"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Ձայնային մուտքագրման ստեղն"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"Կարգավորել մուտքագրման մեթոդները"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Մուտքագրման լեզուներ"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Արձագանքել"</string>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
index 4ab155c..96fa1f8 100644
--- a/java/res/values-in/strings.xml
+++ b/java/res/values-in/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"waktu"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Tombol masukan suara"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Kirim masukan"</string>
diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml
index bdbb112..ea8bf02 100644
--- a/java/res/values-it/strings.xml
+++ b/java/res/values-it/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"ora"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Tasto input vocale"</string>
+    <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nessun metodo di immissione vocale abilitato. Controlla le impostazioni Lingua e input."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configura metodi di immissione"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Lingue comandi"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Invia feedback"</string>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index ce8fa32..8899cec 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"זמן"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"כתובות אתרים"</string>
     <string name="voice_input" msgid="3583258583521397548">"מקש קלט קולי"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"שלח משוב"</string>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index 82b3876..40d55c8 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"時刻"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"音声入力キー"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"入力方法を設定"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"入力言語"</string>
     <string name="send_feedback" msgid="1780431884109392046">"フィードバックを送信"</string>
diff --git a/java/res/values-ka-rGE/strings.xml b/java/res/values-ka-rGE/strings.xml
index 2bdbfc6..587304f 100644
--- a/java/res/values-ka-rGE/strings.xml
+++ b/java/res/values-ka-rGE/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"დრო"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"ხმოვანი შეყვანის კლავიში"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"შეყვანის მეთოდების კონფიგურაცია"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"შეყვანის ენები"</string>
     <string name="send_feedback" msgid="1780431884109392046">"უკუკავშირის გაგზავნა"</string>
diff --git a/java/res/values-km-rKH/strings.xml b/java/res/values-km-rKH/strings.xml
index 6c8a36a..4fdb7d2 100644
--- a/java/res/values-km-rKH/strings.xml
+++ b/java/res/values-km-rKH/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"ពេលវេលា"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"គ្រាប់​ចុច​បញ្ចូល​​សំឡេង"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"ផ្ញើ​មតិ​អ្នក​ប្រើ"</string>
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
index 9fdd79a..207742c 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"시간"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"음성 입력 키"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"입력 방법 설정"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"입력 언어"</string>
     <string name="send_feedback" msgid="1780431884109392046">"의견 보내기"</string>
diff --git a/java/res/values-lo-rLA/strings.xml b/java/res/values-lo-rLA/strings.xml
index c043491..531fec7 100644
--- a/java/res/values-lo-rLA/strings.xml
+++ b/java/res/values-lo-rLA/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"ເວລາ"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"ປຸ່ມປ້ອນຂໍ້ມູນດ້ວຍສຽງ"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"ຕັ້ງຄ່າຮູບແບບການປ້ອນຂໍ້ມູນ"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"ພາສາການປ້ອນຂໍ້ມູນ"</string>
     <string name="send_feedback" msgid="1780431884109392046">"ສົ່ງຄຳຕິຊົມ"</string>
diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml
index 4830ebf..62460b2 100644
--- a/java/res/values-lt/strings.xml
+++ b/java/res/values-lt/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"laiko"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Įvesties balsu klavišas"</string>
+    <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Nėra jokių įgalintų įvesties balsu metodų. Patikrinkite kalbos ir įvesties nustatymus."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Konfigūruoti įvesties metodus"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Įvesties kalbos"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Siųsti atsiliepimą"</string>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
index 760258b..25c0de4 100644
--- a/java/res/values-lv/strings.xml
+++ b/java/res/values-lv/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"laiks"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Balss ievades atslēga"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"Ievades metožu konfigurēšana"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Ievades valodas"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Sūtīt atsauksmes"</string>
diff --git a/java/res/values-mn-rMN/strings.xml b/java/res/values-mn-rMN/strings.xml
index 338e6da..e015752 100644
--- a/java/res/values-mn-rMN/strings.xml
+++ b/java/res/values-mn-rMN/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"цаг"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Дуун оруулгын товч"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Санал хүсэлт илгээх"</string>
diff --git a/java/res/values-ms-rMY/strings.xml b/java/res/values-ms-rMY/strings.xml
index 3fd0b7b..13d3875 100644
--- a/java/res/values-ms-rMY/strings.xml
+++ b/java/res/values-ms-rMY/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"masa"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Kunci input suara"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurasikan kaedah input"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Bahasa input"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Hantar maklum balas"</string>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
index 52a83a2..ed85364 100644
--- a/java/res/values-nb/strings.xml
+++ b/java/res/values-nb/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"tid"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"Nettadresse"</string>
     <string name="voice_input" msgid="3583258583521397548">"Tast for taleinndata"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Send tilbakemelding"</string>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
index 7d38cc5..57511f9 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"tijd"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Toets voor spraakinvoer"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Feedback verzenden"</string>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
index a35f11e..257fc2a 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -33,7 +33,7 @@
     <string name="misc_category" msgid="6894192814868233453">"Inne opcje"</string>
     <string name="advanced_settings" msgid="362895144495591463">"Ustawienia zaawansowane"</string>
     <string name="advanced_settings_summary" msgid="4487980456152830271">"Opcje dla ekspertów"</string>
-    <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Włącz inne metody wprowadzania"</string>
+    <string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"Inne metody wprowadzania"</string>
     <string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"Klawisz zmiany języka obejmuje też inne metody wprowadzania"</string>
     <string name="show_language_switch_key" msgid="5915478828318774384">"Klawisz zmiany języka"</string>
     <string name="show_language_switch_key_summary" msgid="7343403647474265713">"Pokaż, gdy włączonych jest kilka języków wprowadzania"</string>
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"godzina"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Klawisz rozpoznawania mowy"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Prześlij opinię"</string>
@@ -158,9 +159,9 @@
     <string name="not_now" msgid="6172462888202790482">"Nie teraz"</string>
     <string name="custom_input_style_already_exists" msgid="8008728952215449707">"Taki styl wprowadzania już istnieje: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
     <string name="prefs_usability_study_mode" msgid="1261130555134595254">"Tryb badania przydatności"</string>
-    <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Opóźn. przy przytrzym. przycisku"</string>
-    <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Czas wibr. przy naciśn. przycisku"</string>
-    <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Głośność przy naciśn. przycisku"</string>
+    <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Opóźnienie przy długim naciśnięciu"</string>
+    <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Wibracja przy naciśniętym klawiszu"</string>
+    <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Głośność przy naciśniętym klawiszu"</string>
     <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Odczyt zewnętrznego pliku słownika"</string>
     <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"Brak plików słownika w folderze Pobrane pliki"</string>
     <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Wybierz plik słownika do zainstalowania"</string>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index df5118f..de4bada 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URLs"</string>
     <string name="voice_input" msgid="3583258583521397548">"Chave de entrada de voz"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Enviar comentários"</string>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index 45cbb4e..50d7975 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"hora"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Chave de entrada de texto por voz"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"Configurar métodos de entrada"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomas de entrada"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Enviar comentários"</string>
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index 924286c..4890f26 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"ore"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"adrese URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Tastă pentru intrarea vocală"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"Configuraţi metodele de intrare"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Selectaţi limba"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Trimiteți feedback"</string>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index 2fb1515..38303df 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"ввода времени"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"ввода URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Кнопка голосового ввода"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"Настройка способов ввода"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Языки ввода"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Отправить отзыв"</string>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
index bb1ac6e..729afbd 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"čas"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"Adresa URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Kľúč hlasového vstupu"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"Konfigurovať metódy vstupu"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Jazyky vstupu"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Odoslať spätnú väzbu"</string>
@@ -162,7 +164,7 @@
     <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Trvanie vibrov. pri stlač. kl."</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Hlasitosť pri stlačení klávesu"</string>
     <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"Čítať súbor externého slovníka"</string>
-    <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"V priečinku Preberanie nie sú žiadne súbory slovníka"</string>
+    <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"V priečinku Sťahovanie nie sú žiadne súbory slovníka"</string>
     <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"Vyberte súbor slovníka, ktorý chcete nainštalovať"</string>
     <string name="read_external_dictionary_confirm_install_message" msgid="6898610163768980870">"Chcete nainštalovať tento súbor pre jazyk <xliff:g id="LOCALE_NAME">%s</xliff:g>?"</string>
     <string name="error" msgid="8940763624668513648">"Vyskytla sa chyba"</string>
@@ -195,7 +197,7 @@
     <string name="user_dictionaries" msgid="3582332055892252845">"Používateľské slovníky"</string>
     <string name="default_user_dict_pref_name" msgid="1625055720489280530">"Používateľský slovník"</string>
     <string name="dictionary_available" msgid="4728975345815214218">"K dispozícii je slovník"</string>
-    <string name="dictionary_downloading" msgid="2982650524622620983">"Aktuálne sa preberá"</string>
+    <string name="dictionary_downloading" msgid="2982650524622620983">"Aktuálne sa sťahuje"</string>
     <string name="dictionary_installed" msgid="8081558343559342962">"Nainštalované"</string>
     <string name="dictionary_disabled" msgid="8950383219564621762">"Nainštalovaný, zakázaný"</string>
     <string name="cannot_connect_to_dict_service" msgid="9216933695765732398">"Probl. s prip. k sl."</string>
@@ -209,12 +211,12 @@
     <string name="install_dict" msgid="180852772562189365">"Inštalovať"</string>
     <string name="cancel_download_dict" msgid="7843340278507019303">"Zrušiť"</string>
     <string name="delete_dict" msgid="756853268088330054">"Odstrániť"</string>
-    <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Pre vybratý jazyk mobilného zariadenia je k dispozícii slovník.&lt;br/&gt; Slovník jazyka <xliff:g id="LANGUAGE">%1$s</xliff:g> vám odporúčame &lt;b&gt;prevziať&lt;/b&gt;. Pomôže vám pri zadávaní textu.&lt;br/&gt; &lt;br/&gt; V sieti 3G môže preberanie chvíľu trvať. Ak nemáte &lt;b&gt;neobmedzený dátový program&lt;/b&gt;, môžu sa účtovať poplatky.&lt;br/&gt; Ak s určitosťou neviete aký dátový program používate, vyhľadajte pripojenie k sieti Wi-Fi a preberanie sa spustí automaticky.&lt;br/&gt; &lt;br/&gt; Tip: Slovníky môžete v mobilnom zariadení preberať a odstraňovať v časti &lt;b&gt;Jazyk a vstup&lt;/b&gt; ponuky &lt;b&gt;Nastavenia&lt;/b&gt;."</string>
-    <string name="download_over_metered" msgid="1643065851159409546">"Prevziať (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string>
-    <string name="do_not_download_over_metered" msgid="2176209579313941583">"Prevziať cez sieť Wi-Fi"</string>
+    <string name="should_download_over_metered_prompt" msgid="2878629598667658845">"Pre vybratý jazyk mobilného zariadenia je k dispozícii slovník.&lt;br/&gt; Slovník jazyka <xliff:g id="LANGUAGE">%1$s</xliff:g> vám odporúčame &lt;b&gt;stiahnuť&lt;/b&gt;. Pomôže vám pri zadávaní textu.&lt;br/&gt; &lt;br/&gt; V sieti 3G môže sťahovanie chvíľu trvať. Ak nemáte &lt;b&gt;neobmedzený dátový program&lt;/b&gt;, môžu sa účtovať poplatky.&lt;br/&gt; Ak s určitosťou neviete aký dátový program používate, vyhľadajte pripojenie k sieti Wi-Fi a sťahovanie sa spustí automaticky.&lt;br/&gt; &lt;br/&gt; Tip: Slovníky môžete v mobilnom zariadení sťahovať a odstraňovať v časti &lt;b&gt;Jazyk a vstup&lt;/b&gt; ponuky &lt;b&gt;Nastavenia&lt;/b&gt;."</string>
+    <string name="download_over_metered" msgid="1643065851159409546">"Stiahnuť (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> MB)"</string>
+    <string name="do_not_download_over_metered" msgid="2176209579313941583">"Stiahnuť cez sieť Wi-Fi"</string>
     <string name="dict_available_notification_title" msgid="6514288591959117288">"K dispozícii je slovník pre jazyk <xliff:g id="LANGUAGE">%1$s</xliff:g>"</string>
     <string name="dict_available_notification_description" msgid="1075194169443163487">"Stlačením skontrolujete a prevezmete"</string>
-    <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Preberanie: návrhy pre jazyk <xliff:g id="LANGUAGE">%1$s</xliff:g> budú čoskoro k dispozícii."</string>
+    <string name="toast_downloading_suggestions" msgid="1313027353588566660">"Sťahovanie: návrhy pre jazyk <xliff:g id="LANGUAGE">%1$s</xliff:g> budú čoskoro k dispozícii."</string>
     <string name="version_text" msgid="2715354215568469385">"Verzia <xliff:g id="VERSION_NUMBER">%1$s</xliff:g>"</string>
     <string name="user_dict_settings_add_menu_title" msgid="1254195365689387076">"Pridať"</string>
     <string name="user_dict_settings_add_dialog_title" msgid="4096700390211748168">"Pridať do slovníka"</string>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index 7454504..cbbf758 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"ura"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Tipka za glasovni vnos"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Pošljite povratne informacije"</string>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index b8311d0..00f0031 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"време"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Тастер за гласовни унос"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Пошаљи повратне информације"</string>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
index 4dbe497..6a16d33 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"klockslag"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"webbadresser"</string>
     <string name="voice_input" msgid="3583258583521397548">"Röstinmatningsknapp"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Skicka feedback"</string>
diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml
index 6dcfda7..d3ab95a 100644
--- a/java/res/values-sw/strings.xml
+++ b/java/res/values-sw/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"wakati"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Kibao cha kuweka data kwa kutamka"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"Sanidi mbinu za uingizaji"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Lugha za uingizaji"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Tuma maoni"</string>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
index d2c0803..2fbe63d 100644
--- a/java/res/values-th/strings.xml
+++ b/java/res/values-th/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"เวลา"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"แป้นการป้อนข้อมูลด้วยเสียง"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"กำหนดค่าวิธีการป้อนข้อมูล"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"ภาษาในการป้อนข้อมูล"</string>
     <string name="send_feedback" msgid="1780431884109392046">"ส่งข้อเสนอแนะ"</string>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
index 165f6f9..2a0e40c 100644
--- a/java/res/values-tl/strings.xml
+++ b/java/res/values-tl/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"oras"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Voice input key"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <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>
     <string name="send_feedback" msgid="1780431884109392046">"Magpadala ng feedback"</string>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index 0aa06be..26facee 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"saat"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Ses girişi tuşu"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"Giriş yöntemlerini yapılandır"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Giriş dilleri"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Geri bildirim gönder"</string>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
index abbd5f0..3463004 100644
--- a/java/res/values-uk/strings.xml
+++ b/java/res/values-uk/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"час"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL-адреси"</string>
     <string name="voice_input" msgid="3583258583521397548">"Ключ голосового вводу"</string>
+    <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>
     <string name="send_feedback" msgid="1780431884109392046">"Надіслати відгук"</string>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
index 1785d2a..b1cabed 100644
--- a/java/res/values-vi/strings.xml
+++ b/java/res/values-vi/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"giờ"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Khóa nhập giọng nói"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <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>
     <string name="send_feedback" msgid="1780431884109392046">"Gửi phản hồi"</string>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index b192050..e5a576c 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"时间"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"网址"</string>
     <string name="voice_input" msgid="3583258583521397548">"语音输入键"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"配置输入法"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"输入语言"</string>
     <string name="send_feedback" msgid="1780431884109392046">"发送反馈"</string>
diff --git a/java/res/values-zh-rHK/strings.xml b/java/res/values-zh-rHK/strings.xml
index ab789f1..534a1b1 100644
--- a/java/res/values-zh-rHK/strings.xml
+++ b/java/res/values-zh-rHK/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"時間"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"網址"</string>
     <string name="voice_input" msgid="3583258583521397548">"語音輸入鍵"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"設定輸入法"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"輸入語言"</string>
     <string name="send_feedback" msgid="1780431884109392046">"傳送意見"</string>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index afb3e61..b7b94ee 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -119,6 +119,8 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"時間"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"網址"</string>
     <string name="voice_input" msgid="3583258583521397548">"語音輸入按鍵"</string>
+    <!-- no translation found for voice_input_disabled_summary (8141750303464726129) -->
+    <skip />
     <string name="configure_input_method" msgid="373356270290742459">"設定輸入法"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"輸入語言"</string>
     <string name="send_feedback" msgid="1780431884109392046">"提供意見"</string>
diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml
index f5b083e..0afb3b9 100644
--- a/java/res/values-zu/strings.xml
+++ b/java/res/values-zu/strings.xml
@@ -119,6 +119,7 @@
     <string name="keyboard_mode_time" msgid="4381856885582143277">"isikhathi"</string>
     <string name="keyboard_mode_url" msgid="1519819835514911218">"I-URL"</string>
     <string name="voice_input" msgid="3583258583521397548">"Inkinobho yokufaka izwi"</string>
+    <string name="voice_input_disabled_summary" msgid="8141750303464726129">"Azikho izindlela zokufaka zezwi ezinikwe amandla. Hlola izilungiselelo zolimi kanye nezokufaka."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Misa izindlela zokufakwayo"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Izilimi zokufakwayo"</string>
     <string name="send_feedback" msgid="1780431884109392046">"Thumela impendulo"</string>
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index e1c841d..810bd91 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -424,8 +424,8 @@
      */
     @Override
     public void setKeyboard(final Keyboard keyboard) {
-        // Remove any pending messages.
-        mKeyTimerHandler.cancelAllKeyTimers();
+        // Remove any pending messages, except dismissing preview and key repeat.
+        mKeyTimerHandler.cancelLongPressTimers();
         super.setKeyboard(keyboard);
         mKeyDetector.setKeyboard(
                 keyboard, -getPaddingLeft(), -getPaddingTop() + getVerticalCorrection());
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingPoints.java b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingPoints.java
index 7618682..7d09e9d 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingPoints.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureStrokeDrawingPoints.java
@@ -157,19 +157,19 @@
             for (int i = 1; i < segments; i++) {
                 final float t = i / (float)segments;
                 mInterpolator.interpolate(t);
-                eventTimes.add(d1, (int)(dt * t) + t1);
-                xCoords.add(d1, (int)mInterpolator.mInterpolatedX);
-                yCoords.add(d1, (int)mInterpolator.mInterpolatedY);
+                eventTimes.addAt(d1, (int)(dt * t) + t1);
+                xCoords.addAt(d1, (int)mInterpolator.mInterpolatedX);
+                yCoords.addAt(d1, (int)mInterpolator.mInterpolatedY);
                 if (GestureTrailDrawingPoints.DEBUG_SHOW_POINTS) {
-                    types.add(d1, GestureTrailDrawingPoints.POINT_TYPE_INTERPOLATED);
+                    types.addAt(d1, GestureTrailDrawingPoints.POINT_TYPE_INTERPOLATED);
                 }
                 d1++;
             }
-            eventTimes.add(d1, pt[p2]);
-            xCoords.add(d1, px[p2]);
-            yCoords.add(d1, py[p2]);
+            eventTimes.addAt(d1, pt[p2]);
+            xCoords.addAt(d1, px[p2]);
+            yCoords.addAt(d1, py[p2]);
             if (GestureTrailDrawingPoints.DEBUG_SHOW_POINTS) {
-                types.add(d1, GestureTrailDrawingPoints.POINT_TYPE_SAMPLED);
+                types.addAt(d1, GestureTrailDrawingPoints.POINT_TYPE_SAMPLED);
             }
         }
         return lastInterpolatedDrawIndex;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java b/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java
index 3298a3f..ec7b9b0 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java
@@ -126,7 +126,7 @@
         removeMessages(MSG_LONGPRESS_SHIFT_KEY);
     }
 
-    private void cancelLongPressTimers() {
+    public void cancelLongPressTimers() {
         removeMessages(MSG_LONGPRESS_KEY);
         removeMessages(MSG_LONGPRESS_SHIFT_KEY);
     }
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
index c9bcfe3..aa8bb2c 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
@@ -36,6 +36,7 @@
 import java.util.Locale;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 // TODO: Consolidate dictionaries in native code.
@@ -55,8 +56,7 @@
     private UserHistoryDictionary mUserHistoryDictionary;
     private PersonalizationDictionary mPersonalizationDictionary;
 
-    @UsedForTesting
-    private boolean mIsCurrentlyWaitingForMainDictionary = false;
+    private final CountDownLatch mLatchForWaitingLoadingMainDictionary;
 
     public interface DictionaryInitializationListener {
         public void onUpdateMainDictionaryAvailability(boolean isMainDictionaryAvailable);
@@ -77,13 +77,41 @@
             final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) {
         mContext = context;
         mLocale = locale;
+        mLatchForWaitingLoadingMainDictionary = new CountDownLatch(1);
         initForDebug(settingsValues);
-        reloadMainDict(context, locale, listener);
+        loadMainDict(context, locale, listener);
         setUserDictionary(new UserBinaryDictionary(context, locale));
         resetAdditionalDictionaries(oldDictionaryFacilitator, settingsValues);
     }
 
     /**
+     * Creates instance for reloading the main dict.
+     *
+     * @param listener the listener
+     * @param oldDictionaryFacilitator the instance having old dictionaries. This must not be null.
+     */
+    public DictionaryFacilitatorForSuggest(final DictionaryInitializationListener listener,
+            final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) {
+        mContext = oldDictionaryFacilitator.mContext;
+        mLocale = oldDictionaryFacilitator.mLocale;
+        mDictionarySubsetForDebug = oldDictionaryFacilitator.mDictionarySubsetForDebug;
+        mLatchForWaitingLoadingMainDictionary = new CountDownLatch(1);
+        loadMainDict(mContext, mLocale, listener);
+        // Transfer user dictionary.
+        setUserDictionary(oldDictionaryFacilitator.mUserDictionary);
+        oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_USER);
+        // Transfer contacts dictionary.
+        setContactsDictionary(oldDictionaryFacilitator.mContactsDictionary);
+        oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_CONTACTS);
+        // Transfer user history dictionary.
+        setUserHistoryDictionary(oldDictionaryFacilitator.mUserHistoryDictionary);
+        oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_USER_HISTORY);
+        // Transfer personalization dictionary.
+        setPersonalizationDictionary(oldDictionaryFacilitator.mPersonalizationDictionary);
+        oldDictionaryFacilitator.removeDictionary(Dictionary.TYPE_PERSONALIZATION);
+    }
+
+    /**
      * Creates instance for when the settings values have been changed.
      *
      * @param settingsValues the new settings values
@@ -94,6 +122,7 @@
             final DictionaryFacilitatorForSuggest oldDictionaryFacilitator) {
         mContext = oldDictionaryFacilitator.mContext;
         mLocale = oldDictionaryFacilitator.mLocale;
+        mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0);
         initForDebug(settingsValues);
         // Transfer main dictionary.
         setMainDictionary(oldDictionaryFacilitator.mMainDictionary);
@@ -110,6 +139,7 @@
             final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles) {
         mContext = context;
         mLocale = locale;
+        mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0);
         for (final String dictType : dictionaryTypes) {
             if (dictType.equals(Dictionary.TYPE_MAIN)) {
                 final DictionaryCollection mainDictionary =
@@ -167,9 +197,8 @@
         }
     }
 
-    public void reloadMainDict(final Context context, final Locale locale,
+    private void loadMainDict(final Context context, final Locale locale,
             final DictionaryInitializationListener listener) {
-        mIsCurrentlyWaitingForMainDictionary = true;
         mMainDictionary = null;
         if (listener != null) {
             listener.onUpdateMainDictionaryAvailability(hasMainDictionary());
@@ -183,7 +212,7 @@
                 if (listener != null) {
                     listener.onUpdateMainDictionaryAvailability(hasMainDictionary());
                 }
-                mIsCurrentlyWaitingForMainDictionary = false;
+                mLatchForWaitingLoadingMainDictionary.countDown();
             }
         }.start();
     }
@@ -194,9 +223,9 @@
         return null != mMainDictionary && mMainDictionary.isInitialized();
     }
 
-    @UsedForTesting
-    public boolean isCurrentlyWaitingForMainDictionary() {
-        return mIsCurrentlyWaitingForMainDictionary;
+    public void waitForLoadingMainDictionary(final long timeout, final TimeUnit unit)
+            throws InterruptedException {
+        mLatchForWaitingLoadingMainDictionary.await(timeout, unit);
     }
 
     private void setMainDictionary(final Dictionary mainDictionary) {
diff --git a/java/src/com/android/inputmethod/latin/InputPointers.java b/java/src/com/android/inputmethod/latin/InputPointers.java
index 2e638aa..c3bcf37 100644
--- a/java/src/com/android/inputmethod/latin/InputPointers.java
+++ b/java/src/com/android/inputmethod/latin/InputPointers.java
@@ -16,14 +16,16 @@
 
 package com.android.inputmethod.latin;
 
+import android.util.Log;
+
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.latin.utils.ResizableIntArray;
 
-import android.util.Log;
-
 // TODO: This class is not thread-safe.
 public final class InputPointers {
     private static final String TAG = InputPointers.class.getSimpleName();
+    private static final boolean DEBUG_TIME = false;
+
     private final int mDefaultCapacity;
     private final ResizableIntArray mXCoordinates;
     private final ResizableIntArray mYCoordinates;
@@ -38,11 +40,29 @@
         mTimes = new ResizableIntArray(defaultCapacity);
     }
 
-    public void addPointer(int index, int x, int y, int pointerId, int time) {
-        mXCoordinates.add(index, x);
-        mYCoordinates.add(index, y);
-        mPointerIds.add(index, pointerId);
-        mTimes.add(index, time);
+    private void fillWithLastTimeUntil(final int index) {
+        final int fromIndex = mTimes.getLength();
+        // Fill the gap with the latest time.
+        // See {@link #getTime(int)} and {@link #isValidTimeStamps()}.
+        if (fromIndex <= 0) {
+            return;
+        }
+        final int fillLength = index - fromIndex + 1;
+        if (fillLength <= 0) {
+            return;
+        }
+        final int lastTime = mTimes.get(fromIndex - 1);
+        mTimes.fill(lastTime, fromIndex, fillLength);
+    }
+
+    public void addPointerAt(int index, int x, int y, int pointerId, int time) {
+        mXCoordinates.addAt(index, x);
+        mYCoordinates.addAt(index, y);
+        mPointerIds.addAt(index, pointerId);
+        if (LatinImeLogger.sDBG || DEBUG_TIME) {
+            fillWithLastTimeUntil(index);
+        }
+        mTimes.addAt(index, time);
     }
 
     @UsedForTesting
@@ -68,23 +88,6 @@
     }
 
     /**
-     * Append the pointers in the specified {@link InputPointers} to the end of this.
-     * @param src the source {@link InputPointers} to read the data from.
-     * @param startPos the starting index of the pointers in {@code src}.
-     * @param length the number of pointers to be appended.
-     */
-    @UsedForTesting
-    void append(InputPointers src, int startPos, int length) {
-        if (length == 0) {
-            return;
-        }
-        mXCoordinates.append(src.mXCoordinates, startPos, length);
-        mYCoordinates.append(src.mYCoordinates, startPos, length);
-        mPointerIds.append(src.mPointerIds, startPos, length);
-        mTimes.append(src.mTimes, startPos, length);
-    }
-
-    /**
      * Append the times, x-coordinates and y-coordinates in the specified {@link ResizableIntArray}
      * to the end of this.
      * @param pointerId the pointer id of the source.
@@ -141,7 +144,7 @@
     }
 
     public int[] getTimes() {
-        if (LatinImeLogger.sDBG) {
+        if (LatinImeLogger.sDBG || DEBUG_TIME) {
             if (!isValidTimeStamps()) {
                 throw new RuntimeException("Time stamps are invalid.");
             }
@@ -157,10 +160,11 @@
 
     private boolean isValidTimeStamps() {
         final int[] times = mTimes.getPrimitiveArray();
-        for (int i = 1; i < getPointerSize(); ++i) {
+        final int size = getPointerSize();
+        for (int i = 1; i < size; ++i) {
             if (times[i] < times[i - 1]) {
                 // dump
-                for (int j = 0; j < times.length; ++j) {
+                for (int j = 0; j < size; ++j) {
                     Log.d(TAG, "--- (" + j + ") " + times[j]);
                 }
                 return false;
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5a5674f..aadb651 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -89,6 +89,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Locale;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Input method implementation for Qwerty'ish keyboard.
@@ -519,11 +520,22 @@
                     new DictionaryFacilitatorForSuggest(currentSettingsValues,
                             oldDictionaryFacilitator);
             // Create Suggest instance with the new dictionary facilitator.
-            mInputLogic.mSuggest = new Suggest(suggest /* oldSuggest */, dictionaryFacilitator);
-            suggest.close();
+            resetSuggest(new Suggest(suggest /* oldSuggest */, dictionaryFacilitator));
+        } else if (suggest == null) {
+            initSuggestForLocale(locale);
         }
-        if (currentSettingsValues.mUsePersonalizedDicts) {
-            PersonalizationDictionarySessionRegistrar.init(this);
+    }
+
+    private void refreshPersonalizationDictionarySession() {
+        if (mSettings.getCurrent().mUsePersonalizedDicts) {
+            if (mSubtypeSwitcher.isSystemLocaleSameAsLocaleOfAllEnabledSubtypes()) {
+                final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+                        (mInputLogic.mSuggest == null) ?
+                                null : mInputLogic.mSuggest.mDictionaryFacilitator;
+                PersonalizationDictionarySessionRegistrar.init(this, dictionaryFacilitator);
+            } else {
+                PersonalizationDictionarySessionRegistrar.close(this);
+            }
         } else {
             PersonalizationHelper.removeAllPersonalizedDictionaries(this);
             PersonalizationDictionarySessionRegistrar.resetAll(this);
@@ -555,31 +567,41 @@
         } else {
             subtypeLocale = switcherSubtypeLocale;
         }
+        initSuggestForLocale(subtypeLocale);
+    }
 
+    private void initSuggestForLocale(final Locale locale) {
         final SettingsValues settingsValues = mSettings.getCurrent();
         final DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
                 (mInputLogic.mSuggest == null) ? null : mInputLogic.mSuggest.mDictionaryFacilitator;
         // Creates new dictionary facilitator for the new locale.
         final DictionaryFacilitatorForSuggest dictionaryFacilitator =
-                new DictionaryFacilitatorForSuggest(this /* context */, subtypeLocale,
+                new DictionaryFacilitatorForSuggest(this /* context */, locale,
                         settingsValues, this /* DictionaryInitializationListener */,
                         oldDictionaryFacilitator);
-        final Suggest newSuggest = new Suggest(subtypeLocale, dictionaryFacilitator);
+        final Suggest newSuggest = new Suggest(locale, dictionaryFacilitator);
         if (settingsValues.mCorrectionEnabled) {
             newSuggest.setAutoCorrectionThreshold(settingsValues.mAutoCorrectionThreshold);
         }
+        resetSuggest(newSuggest);
+    }
+
+    /* package private */ void resetSuggestMainDict() {
+        final DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
+                mInputLogic.mSuggest.mDictionaryFacilitator;
+        final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+                new DictionaryFacilitatorForSuggest(this /* listener */, oldDictionaryFacilitator);
+        resetSuggest(new Suggest(mInputLogic.mSuggest /* oldSuggest */, dictionaryFacilitator));
+    }
+
+    private void resetSuggest(final Suggest newSuggest) {
         if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
             ResearchLogger.getInstance().initDictionary(newSuggest.mDictionaryFacilitator);
         }
         final Suggest oldSuggest = mInputLogic.mSuggest;
         mInputLogic.mSuggest = newSuggest;
         if (oldSuggest != null) oldSuggest.close();
-    }
-
-    /* package private */ void resetSuggestMainDict() {
-        final Locale subtypeLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
-        mInputLogic.mSuggest.mDictionaryFacilitator.reloadMainDict(this, subtypeLocale,
-                this /* SuggestInitializationListener */);
+        refreshPersonalizationDictionarySession();
     }
 
     @Override
@@ -595,7 +617,7 @@
             ResearchLogger.getInstance().onDestroy();
         }
         unregisterReceiver(mDictionaryPackInstallReceiver);
-        PersonalizationDictionarySessionRegistrar.onDestroy(this);
+        PersonalizationDictionarySessionRegistrar.close(this);
         LatinImeLogger.commit();
         LatinImeLogger.onDestroy();
         super.onDestroy();
@@ -615,7 +637,8 @@
                 mOptionsDialog.dismiss();
             }
         }
-        PersonalizationDictionarySessionRegistrar.onConfigurationChanged(this, conf);
+        PersonalizationDictionarySessionRegistrar.onConfigurationChanged(this, conf,
+                mInputLogic.mSuggest.mDictionaryFacilitator);
         super.onConfigurationChanged(conf);
     }
 
@@ -1291,7 +1314,8 @@
     @UsedForTesting
     public boolean isShowingPunctuationList() {
         if (mInputLogic.mSuggestedWords == null) return false;
-        return mSettings.getCurrent().mSuggestPuncList == mInputLogic.mSuggestedWords;
+        return mSettings.getCurrent().mSpacingAndPunctuations.mSuggestPuncList
+                == mInputLogic.mSuggestedWords;
     }
 
     // TODO[IL]: Define a clear interface for this
@@ -1407,7 +1431,8 @@
 
     private SuggestedWords getOlderSuggestions(final String typedWord) {
         SuggestedWords previousSuggestedWords = mInputLogic.mSuggestedWords;
-        if (previousSuggestedWords == mSettings.getCurrent().mSuggestPuncList) {
+        if (previousSuggestedWords
+                == mSettings.getCurrent().mSpacingAndPunctuations.mSuggestPuncList) {
             previousSuggestedWords = SuggestedWords.EMPTY;
         }
         if (typedWord == null) {
@@ -1560,7 +1585,7 @@
         if (currentSettings.mBigramPredictionEnabled) {
             clearSuggestionStrip();
         } else {
-            setSuggestedWords(currentSettings.mSuggestPuncList);
+            setSuggestedWords(currentSettings.mSpacingAndPunctuations.mSuggestPuncList);
         }
         setAutoCorrectionIndicator(false);
         setSuggestionStripShown(isSuggestionsStripVisible());
@@ -1777,14 +1802,20 @@
 
     // DO NOT USE THIS for any other purpose than testing. This is information private to LatinIME.
     @UsedForTesting
-    /* package for test */ boolean isCurrentlyWaitingForMainDictionary() {
-        return mInputLogic.mSuggest.mDictionaryFacilitator.isCurrentlyWaitingForMainDictionary();
+    /* package for test */ void waitForMainDictionary(final long timeout, final TimeUnit unit)
+            throws InterruptedException {
+        mInputLogic.mSuggest.mDictionaryFacilitator.waitForLoadingMainDictionary(timeout, unit);
     }
 
     // DO NOT USE THIS for any other purpose than testing. This can break the keyboard badly.
     @UsedForTesting
-    /* package for test */ void replaceMainDictionaryForTest(final Locale locale) {
-        mInputLogic.mSuggest.mDictionaryFacilitator.reloadMainDict(this, locale, null);
+    /* package for test */ void replaceDictionariesForTest(final Locale locale) {
+        final DictionaryFacilitatorForSuggest oldDictionaryFacilitator =
+                mInputLogic.mSuggest.mDictionaryFacilitator;
+        final DictionaryFacilitatorForSuggest dictionaryFacilitator =
+                new DictionaryFacilitatorForSuggest(this, locale, mSettings.getCurrent(),
+                        this /* listener */, oldDictionaryFacilitator);
+        resetSuggest(new Suggest(locale, dictionaryFacilitator));
     }
 
     public void debugDumpStateAndCrashWithException(final String context) {
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 4d174dd..7cf64a3 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -685,6 +685,10 @@
                 && !settingsValues.isWordConnector(codePointBeforeCursor)) {
             return true;
         }
+        return isCursorFollowedByWordCharacter(settingsValues);
+    }
+
+    public boolean isCursorFollowedByWordCharacter(final SettingsValues settingsValues) {
         final CharSequence after = getTextAfterCursor(1, 0);
         if (!TextUtils.isEmpty(after) && !settingsValues.isWordSeparator(after.charAt(0))
                 && !settingsValues.isWordConnector(after.charAt(0))) {
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index b0ab603..860575a 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -273,6 +273,18 @@
         return mNeedsToDisplayLanguage.getValue();
     }
 
+    public boolean isSystemLocaleSameAsLocaleOfAllEnabledSubtypes() {
+        final Locale systemLocale = mResources.getConfiguration().locale;
+        final List<InputMethodSubtype> enabledSubtypesOfThisIme =
+                mRichImm.getMyEnabledInputMethodSubtypeList(true);
+        for (final InputMethodSubtype subtype : enabledSubtypesOfThisIme) {
+            if (!systemLocale.equals(SubtypeLocaleUtils.getSubtypeLocale(subtype))) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private static InputMethodSubtype sForcedSubtypeForTesting = null;
     @UsedForTesting
     void forceSubtype(final InputMethodSubtype subtype) {
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index f078c73..b4f2d1a 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -186,7 +186,7 @@
             // (See {@link #setBatchInputWord}).
             if (!mIsBatchMode) {
                 // TODO: Set correct pointer id and time
-                mInputPointers.addPointer(newIndex, keyX, keyY, 0, 0);
+                mInputPointers.addPointerAt(newIndex, keyX, keyY, 0, 0);
             }
         }
         mIsFirstCharCapitalized = isFirstCharCapitalized(
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index b365003..968129a 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -529,7 +529,7 @@
         // In languages with spaces, we only start composing a word when we are not already
         // touching a word. In languages without spaces, the above conditions are sufficient.
                 (!mConnection.isCursorTouchingWord(settingsValues)
-                        || !settingsValues.mCurrentLanguageHasSpaces)) {
+                        || !settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces)) {
             // Reset entirely the composing state anyway, then start composing a new word unless
             // the character is a single quote or a dash. The idea here is, single quote and dash
             // are not separators and they should be treated as normal characters, except in the
@@ -594,7 +594,7 @@
         boolean didAutoCorrect = false;
         // We avoid sending spaces in languages without spaces if we were composing.
         final boolean shouldAvoidSendingCode = Constants.CODE_SPACE == codePoint
-                && !settingsValues.mCurrentLanguageHasSpaces
+                && !settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
                 && mWordComposer.isComposingWord();
         if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
             // If we are in the middle of a recorrection, we need to commit the recorrection
@@ -813,7 +813,8 @@
                 }
             }
             if (settingsValues.isSuggestionStripVisible()
-                    && settingsValues.mCurrentLanguageHasSpaces) {
+                    && settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
+                    && !mConnection.isCursorFollowedByWordCharacter(settingsValues)) {
                 restartSuggestionsOnWordTouchedByCursor(settingsValues,
                         deleteCountAtStart - mDeleteCount /* offset */,
                         true /* includeResumedWordInSuggestions */, keyboardSwitcher);
@@ -911,8 +912,8 @@
         if (canBeFollowedByDoubleSpacePeriod(firstCodePoint)) {
             handler.cancelDoubleSpacePeriodTimer();
             mConnection.deleteSurroundingText(2, 0);
-            final String textToInsert = new String(
-                    new int[] { settingsValues.mSentenceSeparator, Constants.CODE_SPACE }, 0, 2);
+            final String textToInsert =
+                    settingsValues.mSpacingAndPunctuations.mSentenceSeparatorAndSpace;
             mConnection.commitText(textToInsert, 1);
             if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
                 ResearchLogger.latinIME_maybeDoubleSpacePeriod(textToInsert,
@@ -966,7 +967,7 @@
             if (TextUtils.isEmpty(selectedText)) return; // Race condition with the input connection
             mRecapitalizeStatus.initialize(mLastSelectionStart, mLastSelectionEnd,
                     selectedText.toString(),
-                    settingsValues.mLocale, settingsValues.mWordSeparators);
+                    settingsValues.mLocale, settingsValues.mSpacingAndPunctuations.mWordSeparators);
             // We trim leading and trailing whitespace.
             mRecapitalizeStatus.trim();
             // Trimming the object may have changed the length of the string, and we need to
@@ -1065,7 +1066,7 @@
         if (!mLatinIME.isSuggestionsStripVisible()) return;
         // Recorrection is not supported in languages without spaces because we don't know
         // how to segment them yet.
-        if (!settingsValues.mCurrentLanguageHasSpaces) return;
+        if (!settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) return;
         // If the cursor is not touching a word, or if there is a selection, return right away.
         if (mLastSelectionStart != mLastSelectionEnd) return;
         // If we don't know the cursor location, return.
@@ -1073,7 +1074,8 @@
         final int expectedCursorPosition = mLastSelectionStart + offset; // We know Start == End
         if (!mConnection.isCursorTouchingWord(settingsValues)) return;
         final TextRange range = mConnection.getWordRangeAtCursor(
-                settingsValues.mWordSeparators, 0 /* additionalPrecedingWordsCount */);
+                settingsValues.mSpacingAndPunctuations.mWordSeparators,
+                0 /* additionalPrecedingWordsCount */);
         if (null == range) return; // Happens if we don't have an input connection at all
         if (range.length() <= 0) return; // Race condition. No text to resume on, so bail out.
         // If for some strange reason (editor bug or so) we measure the text before the cursor as
@@ -1113,8 +1115,19 @@
                 keyboardSwitcher.getKeyboard());
         mWordComposer.setCursorPositionWithinWord(
                 typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor));
-        mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor,
+        // TODO: Change these lines to setComposingRegion(cursorPosition,
+        //         cursorPosition + range.getNumberOfCharsInWordAfterCursor());
+        if (0 != offset) {
+            // Backspace was pressed. We are at the end of a word, and we don't know the cursor
+            // position for sure, so use relative methods.
+            mConnection.deleteSurroundingText(numberOfCharsInWordBeforeCursor, 0);
+            mConnection.setComposingText(typedWord, 1);
+        } else {
+            // This is recorrection. The cursor position is reasonably reliable, and the cursor
+            // may be in the middle of a word so use setComposingRegion.
+            mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor,
                 expectedCursorPosition + range.getNumberOfCharsInWordAfterCursor());
+        }
         if (suggestions.isEmpty()) {
             // We come here if there weren't any suggestion spans on this word. We will try to
             // compute suggestions for it instead.
@@ -1195,7 +1208,7 @@
             }
         }
         final String stringToCommit = originallyTypedWord + mLastComposedWord.mSeparatorString;
-        if (settingsValues.mCurrentLanguageHasSpaces) {
+        if (settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) {
             // For languages with spaces, we revert to the typed string, but the cursor is still
             // after the separator so we don't resume suggestions. If the user wants to correct
             // the word, they have to press backspace again.
@@ -1295,7 +1308,7 @@
     // TODO: Make this private
     public String getNthPreviousWordForSuggestion(final SettingsValues currentSettings,
             final int nthPreviousWord) {
-        if (currentSettings.mCurrentLanguageHasSpaces) {
+        if (currentSettings.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) {
             // If we are typing in a language with spaces we can just look up the previous
             // word from textview.
             return mConnection.getNthPreviousWord(currentSettings, nthPreviousWord);
@@ -1386,7 +1399,7 @@
         if (settingsValues.mBigramPredictionEnabled) {
             mLatinIME.clearSuggestionStrip();
         } else {
-            mLatinIME.setSuggestedWords(settingsValues.mSuggestPuncList);
+            mLatinIME.setSuggestedWords(settingsValues.mSpacingAndPunctuations.mSuggestPuncList);
         }
         mConnection.resetCachesUponCursorMoveAndReturnSuccess(newSelStart, newSelEnd,
                 shouldFinishComposition);
@@ -1495,7 +1508,7 @@
     // TODO: Make this private.
     public void promotePhantomSpace(final SettingsValues settingsValues) {
         if (settingsValues.shouldInsertSpacesAutomatically()
-                && settingsValues.mCurrentLanguageHasSpaces
+                && settingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces
                 && !mConnection.textBeforeCursorLooksLikeURL()) {
             if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
                 ResearchLogger.latinIME_promotePhantomSpace();
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegistrar.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegistrar.java
index 7696511..d6c0dc0 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegistrar.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionarySessionRegistrar.java
@@ -19,11 +19,15 @@
 import android.content.Context;
 import android.content.res.Configuration;
 
+import com.android.inputmethod.latin.DictionaryFacilitatorForSuggest;
+
 public class PersonalizationDictionarySessionRegistrar {
-    public static void init(final Context context) {
+    public static void init(final Context context,
+            final DictionaryFacilitatorForSuggest dictionaryFacilitator) {
     }
 
-    public static void onConfigurationChanged(final Context context, final Configuration conf) {
+    public static void onConfigurationChanged(final Context context, final Configuration conf,
+            final DictionaryFacilitatorForSuggest dictionaryFacilitator) {
     }
 
     public static void onUpdateData(final Context context, final String type) {
@@ -35,6 +39,6 @@
     public static void resetAll(final Context context) {
     }
 
-    public static void onDestroy(final Context context) {
+    public static void close(final Context context) {
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index 75c7258..84ba722 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -176,7 +176,7 @@
     }
 
     public String getWordSeparators() {
-        return mSettingsValues.mWordSeparators;
+        return mSettingsValues.mSpacingAndPunctuations.mWordSeparators;
     }
 
     public boolean isWordSeparator(final int code) {
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index a07a0ce..3fa686b 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -26,20 +26,12 @@
 
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.compat.AppWorkaroundsUtils;
-import com.android.inputmethod.keyboard.internal.KeySpecParser;
-import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.Dictionary;
 import com.android.inputmethod.latin.InputAttributes;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.RichInputMethodManager;
-import com.android.inputmethod.latin.SuggestedWords;
-import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
 import com.android.inputmethod.latin.utils.AsyncResultHolder;
-import com.android.inputmethod.latin.utils.CollectionUtils;
-import com.android.inputmethod.latin.utils.StringUtils;
 import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask;
 
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Locale;
 
@@ -56,15 +48,9 @@
     private static final int TIMEOUT_TO_GET_TARGET_PACKAGE = 5; // seconds
 
     // From resources:
+    public final SpacingAndPunctuations mSpacingAndPunctuations;
     public final int mDelayUpdateOldSuggestions;
-    public final int[] mSymbolsPrecededBySpace;
-    public final int[] mSymbolsFollowedBySpace;
-    public final int[] mWordConnectors;
-    public final SuggestedWords mSuggestPuncList;
-    public final String mWordSeparators;
-    public final int mSentenceSeparator;
     public final CharSequence mHintToSaveText;
-    public final boolean mCurrentLanguageHasSpaces;
 
     // From preferences, in the same order as xml/prefs.xml:
     public final boolean mAutoCap;
@@ -115,22 +101,8 @@
         mLocale = locale;
         // Get the resources
         mDelayUpdateOldSuggestions = res.getInteger(R.integer.config_delay_update_old_suggestions);
-        mSymbolsPrecededBySpace =
-                StringUtils.toCodePointArray(res.getString(R.string.symbols_preceded_by_space));
-        Arrays.sort(mSymbolsPrecededBySpace);
-        mSymbolsFollowedBySpace =
-                StringUtils.toCodePointArray(res.getString(R.string.symbols_followed_by_space));
-        Arrays.sort(mSymbolsFollowedBySpace);
-        mWordConnectors =
-                StringUtils.toCodePointArray(res.getString(R.string.symbols_word_connectors));
-        Arrays.sort(mWordConnectors);
-        final String[] suggestPuncsSpec = KeySpecParser.splitKeySpecs(res.getString(
-                R.string.suggested_punctuations));
-        mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
-        mWordSeparators = res.getString(R.string.symbols_word_separators);
-        mSentenceSeparator = res.getInteger(R.integer.sentence_separator);
+        mSpacingAndPunctuations = new SpacingAndPunctuations(res);
         mHintToSaveText = res.getText(R.string.hint_add_to_dictionary);
-        mCurrentLanguageHasSpaces = res.getBoolean(R.bool.current_language_has_spaces);
 
         // Store the input attributes
         if (null == inputAttributes) {
@@ -199,18 +171,8 @@
         // TODO: locale is saved, but not used yet. May have to change this if tests require.
         mLocale = locale;
         mDelayUpdateOldSuggestions = 0;
-        mSymbolsPrecededBySpace = new int[] { '(', '[', '{', '&' };
-        Arrays.sort(mSymbolsPrecededBySpace);
-        mSymbolsFollowedBySpace = new int[] { '.', ',', ';', ':', '!', '?', ')', ']', '}', '&' };
-        Arrays.sort(mSymbolsFollowedBySpace);
-        mWordConnectors = new int[] { '\'', '-' };
-        Arrays.sort(mWordConnectors);
-        mSentenceSeparator = Constants.CODE_PERIOD;
-        final String[] suggestPuncsSpec = new String[] { "!", "?", ",", ":", ";" };
-        mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
-        mWordSeparators = "&\t \n()[]{}*&<>+=|.,;:!?/_\"";
+        mSpacingAndPunctuations = SpacingAndPunctuations.DEFAULT;
         mHintToSaveText = "Touch again to save";
-        mCurrentLanguageHasSpaces = true;
         mInputAttributes = new InputAttributes(null, false /* isFullscreenMode */);
         mAutoCap = true;
         mVibrateOn = true;
@@ -265,11 +227,11 @@
     }
 
     public boolean isWordSeparator(final int code) {
-        return mWordSeparators.contains(String.valueOf((char)code));
+        return mSpacingAndPunctuations.isWordSeparator(code);
     }
 
     public boolean isWordConnector(final int code) {
-        return Arrays.binarySearch(mWordConnectors, code) >= 0;
+        return mSpacingAndPunctuations.isWordConnector(code);
     }
 
     public boolean isWordCodePoint(final int code) {
@@ -277,11 +239,11 @@
     }
 
     public boolean isUsuallyPrecededBySpace(final int code) {
-        return Arrays.binarySearch(mSymbolsPrecededBySpace, code) >= 0;
+        return mSpacingAndPunctuations.isUsuallyPrecededBySpace(code);
     }
 
     public boolean isUsuallyFollowedBySpace(final int code) {
-        return Arrays.binarySearch(mSymbolsFollowedBySpace, code) >= 0;
+        return mSpacingAndPunctuations.isUsuallyFollowedBySpace(code);
     }
 
     public boolean shouldInsertSpacesAutomatically() {
@@ -320,27 +282,6 @@
         return null == appWorkaroundUtils ? false : appWorkaroundUtils.isBrokenByRecorrection();
     }
 
-    // Helper functions to create member values.
-    private static SuggestedWords createSuggestPuncList(final String[] puncs) {
-        final ArrayList<SuggestedWordInfo> puncList = CollectionUtils.newArrayList();
-        if (puncs != null) {
-            for (final String puncSpec : puncs) {
-                // TODO: Stop using KeySpceParser.getLabel().
-                puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec),
-                        SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED,
-                        Dictionary.DICTIONARY_HARDCODED,
-                        SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
-                        SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
-            }
-        }
-        return new SuggestedWords(puncList,
-                false /* typedWordValid */,
-                false /* hasAutoCorrectionCandidate */,
-                true /* isPunctuationSuggestions */,
-                false /* isObsoleteSuggestions */,
-                false /* isPrediction */);
-    }
-
     private static final int SUGGESTION_VISIBILITY_SHOW_VALUE =
             R.string.prefs_suggestion_visibility_show_value;
     private static final int SUGGESTION_VISIBILITY_SHOW_ONLY_PORTRAIT_VALUE =
diff --git a/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
new file mode 100644
index 0000000..0500f4a
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/SpacingAndPunctuations.java
@@ -0,0 +1,124 @@
+/*
+ * 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.settings;
+
+import android.content.res.Resources;
+
+import com.android.inputmethod.keyboard.internal.KeySpecParser;
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.Dictionary;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SuggestedWords;
+import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public final class SpacingAndPunctuations {
+    private final int[] mSymbolsPrecededBySpace;
+    private final int[] mSymbolsFollowedBySpace;
+    private final int[] mWordConnectors;
+    public final SuggestedWords mSuggestPuncList;
+    public final String mWordSeparators;
+    private final int mSentenceSeparator;
+    public final String mSentenceSeparatorAndSpace;
+    public final boolean mCurrentLanguageHasSpaces;
+
+    public static final SpacingAndPunctuations DEFAULT = new SpacingAndPunctuations();
+
+    private SpacingAndPunctuations() {
+        mSymbolsPrecededBySpace = new int[] { '(', '[', '{', '&' };
+        Arrays.sort(mSymbolsPrecededBySpace);
+        mSymbolsFollowedBySpace = new int[] { '.', ',', ';', ':', '!', '?', ')', ']', '}', '&' };
+        Arrays.sort(mSymbolsFollowedBySpace);
+        mWordConnectors = new int[] { '\'', '-' };
+        Arrays.sort(mWordConnectors);
+        mSentenceSeparator = Constants.CODE_PERIOD;
+        mSentenceSeparatorAndSpace = ". ";
+        final String[] suggestPuncsSpec = new String[] { "!", "?", ",", ":", ";" };
+        mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
+        mWordSeparators = "&\t \n()[]{}*&<>+=|.,;:!?/_\"";
+        mCurrentLanguageHasSpaces = true;
+    }
+
+    public SpacingAndPunctuations(final Resources res) {
+        mSymbolsPrecededBySpace =
+                StringUtils.toCodePointArray(res.getString(R.string.symbols_preceded_by_space));
+        Arrays.sort(mSymbolsPrecededBySpace);
+        mSymbolsFollowedBySpace =
+                StringUtils.toCodePointArray(res.getString(R.string.symbols_followed_by_space));
+        Arrays.sort(mSymbolsFollowedBySpace);
+        mWordConnectors =
+                StringUtils.toCodePointArray(res.getString(R.string.symbols_word_connectors));
+        Arrays.sort(mWordConnectors);
+        final String[] suggestPuncsSpec = KeySpecParser.splitKeySpecs(res.getString(
+                R.string.suggested_punctuations));
+        mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec);
+        mWordSeparators = res.getString(R.string.symbols_word_separators);
+        mSentenceSeparator = res.getInteger(R.integer.sentence_separator);
+        mSentenceSeparatorAndSpace = new String(new int[] {
+                mSentenceSeparator, Constants.CODE_SPACE }, 0, 2);
+        mCurrentLanguageHasSpaces = res.getBoolean(R.bool.current_language_has_spaces);
+    }
+
+    // Helper functions to create member values.
+    private static SuggestedWords createSuggestPuncList(final String[] puncs) {
+        final ArrayList<SuggestedWordInfo> puncList = CollectionUtils.newArrayList();
+        if (puncs != null) {
+            for (final String puncSpec : puncs) {
+                // TODO: Stop using KeySpceParser.getLabel().
+                puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec),
+                        SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED,
+                        Dictionary.DICTIONARY_HARDCODED,
+                        SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                        SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
+            }
+        }
+        return new SuggestedWords(puncList,
+                false /* typedWordValid */,
+                false /* hasAutoCorrectionCandidate */,
+                true /* isPunctuationSuggestions */,
+                false /* isObsoleteSuggestions */,
+                false /* isPrediction */);
+    }
+
+    public boolean isWordSeparator(final int code) {
+        return mWordSeparators.contains(String.valueOf((char)code));
+    }
+
+    public boolean isWordConnector(final int code) {
+        return Arrays.binarySearch(mWordConnectors, code) >= 0;
+    }
+
+    public boolean isWordCodePoint(final int code) {
+        return Character.isLetter(code) || isWordConnector(code);
+    }
+
+    public boolean isUsuallyPrecededBySpace(final int code) {
+        return Arrays.binarySearch(mSymbolsPrecededBySpace, code) >= 0;
+    }
+
+    public boolean isUsuallyFollowedBySpace(final int code) {
+        return Arrays.binarySearch(mSymbolsFollowedBySpace, code) >= 0;
+    }
+
+    public boolean isSentenceSeparator(final int code) {
+        return code == mSentenceSeparator;
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
index 3d4404a..6ad5c77 100644
--- a/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CapsModeUtils.java
@@ -191,7 +191,7 @@
         if (c == Constants.CODE_QUESTION_MARK || c == Constants.CODE_EXCLAMATION_MARK) {
             return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_SENTENCES) & reqModes;
         }
-        if (settingsValues.mSentenceSeparator != c || j <= 0) {
+        if (!settingsValues.mSpacingAndPunctuations.isSentenceSeparator(c) || j <= 0) {
             return (TextUtils.CAP_MODE_CHARACTERS | TextUtils.CAP_MODE_WORDS) & reqModes;
         }
 
@@ -241,7 +241,7 @@
             case WORD:
                 if (Character.isLetter(c)) {
                     state = WORD;
-                } else if (settingsValues.mSentenceSeparator == c) {
+                } else if (settingsValues.mSpacingAndPunctuations.isSentenceSeparator(c)) {
                     state = PERIOD;
                 } else {
                     return caps;
@@ -257,7 +257,7 @@
             case LETTER:
                 if (Character.isLetter(c)) {
                     state = LETTER;
-                } else if (settingsValues.mSentenceSeparator == c) {
+                } else if (settingsValues.mSpacingAndPunctuations.isSentenceSeparator(c)) {
                     state = PERIOD;
                 } else {
                     return noCaps;
diff --git a/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java b/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java
index 7c6fe93..64c9e2c 100644
--- a/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java
+++ b/java/src/com/android/inputmethod/latin/utils/ResizableIntArray.java
@@ -34,7 +34,7 @@
         throw new ArrayIndexOutOfBoundsException("length=" + mLength + "; index=" + index);
     }
 
-    public void add(final int index, final int val) {
+    public void addAt(final int index, final int val) {
         if (index < mLength) {
             mArray[index] = val;
         } else {
diff --git a/tests/src/com/android/inputmethod/latin/InputPointersTests.java b/tests/src/com/android/inputmethod/latin/InputPointersTests.java
index 5095f96..1a47cdd 100644
--- a/tests/src/com/android/inputmethod/latin/InputPointersTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputPointersTests.java
@@ -55,14 +55,22 @@
         final InputPointers src = new InputPointers(DEFAULT_CAPACITY);
         final int limit = src.getXCoordinates().length * 2 + 10;
         for (int i = 0; i < limit; i++) {
-            src.addPointer(i, i * 2, i * 3, i * 4);
+            final int x = i;
+            final int y = i * 2;
+            final int pointerId = i * 3;
+            final int time = i * 4;
+            src.addPointer(x, y, pointerId, time);
             assertEquals("size after add " + i, i + 1, src.getPointerSize());
         }
         for (int i = 0; i < limit; i++) {
-            assertEquals("xCoordinates at " + i, i, src.getXCoordinates()[i]);
-            assertEquals("yCoordinates at " + i, i * 2, src.getYCoordinates()[i]);
-            assertEquals("pointerIds at " + i, i * 3, src.getPointerIds()[i]);
-            assertEquals("times at " + i, i * 4, src.getTimes()[i]);
+            final int x = i;
+            final int y = i * 2;
+            final int pointerId = i * 3;
+            final int time = i * 4;
+            assertEquals("xCoordinates at " + i, x, src.getXCoordinates()[i]);
+            assertEquals("yCoordinates at " + i, y, src.getYCoordinates()[i]);
+            assertEquals("pointerIds at " + i, pointerId, src.getPointerIds()[i]);
+            assertEquals("times at " + i, time, src.getTimes()[i]);
         }
     }
 
@@ -70,14 +78,22 @@
         final InputPointers src = new InputPointers(DEFAULT_CAPACITY);
         final int limit = 1000, step = 100;
         for (int i = 0; i < limit; i += step) {
-            src.addPointer(i, i, i * 2, i * 3, i * 4);
+            final int x = i;
+            final int y = i * 2;
+            final int pointerId = i * 3;
+            final int time = i * 4;
+            src.addPointerAt(i, x, y, pointerId, time);
             assertEquals("size after add at " + i, i + 1, src.getPointerSize());
         }
         for (int i = 0; i < limit; i += step) {
-            assertEquals("xCoordinates at " + i, i, src.getXCoordinates()[i]);
-            assertEquals("yCoordinates at " + i, i * 2, src.getYCoordinates()[i]);
-            assertEquals("pointerIds at " + i, i * 3, src.getPointerIds()[i]);
-            assertEquals("times at " + i, i * 4, src.getTimes()[i]);
+            final int x = i;
+            final int y = i * 2;
+            final int pointerId = i * 3;
+            final int time = i * 4;
+            assertEquals("xCoordinates at " + i, x, src.getXCoordinates()[i]);
+            assertEquals("yCoordinates at " + i, y, src.getYCoordinates()[i]);
+            assertEquals("pointerIds at " + i, pointerId, src.getPointerIds()[i]);
+            assertEquals("times at " + i, time, src.getTimes()[i]);
         }
     }
 
@@ -85,7 +101,11 @@
         final InputPointers src = new InputPointers(DEFAULT_CAPACITY);
         final int limit = src.getXCoordinates().length * 2 + 10;
         for (int i = 0; i < limit; i++) {
-            src.addPointer(i, i * 2, i * 3, i * 4);
+            final int x = i;
+            final int y = i * 2;
+            final int pointerId = i * 3;
+            final int time = i * 4;
+            src.addPointer(x, y, pointerId, time);
         }
         final InputPointers dst = new InputPointers(DEFAULT_CAPACITY);
         dst.set(src);
@@ -100,7 +120,11 @@
         final InputPointers src = new InputPointers(DEFAULT_CAPACITY);
         final int limit = 100;
         for (int i = 0; i < limit; i++) {
-            src.addPointer(i, i * 2, i * 3, i * 4);
+            final int x = i;
+            final int y = i * 2;
+            final int pointerId = i * 3;
+            final int time = i * 4;
+            src.addPointer(x, y, pointerId, time);
         }
         final InputPointers dst = new InputPointers(DEFAULT_CAPACITY);
         dst.copy(src);
@@ -121,106 +145,135 @@
     }
 
     public void testAppend() {
-        final InputPointers src = new InputPointers(DEFAULT_CAPACITY);
-        final int srcLen = 100;
-        for (int i = 0; i < srcLen; i++) {
-            src.addPointer(i, i * 2, i * 3, i * 4);
-        }
-        final int dstLen = 50;
+        final int dstLength = 50;
         final InputPointers dst = new InputPointers(DEFAULT_CAPACITY);
-        for (int i = 0; i < dstLen; i++) {
-            final int value = -i - 1;
-            dst.addPointer(value * 4, value * 3, value * 2, value);
+        for (int i = 0; i < dstLength; i++) {
+            final int x = i * 4;
+            final int y = i * 3;
+            final int pointerId = i * 2;
+            final int time = i;
+            dst.addPointer(x, y, pointerId, time);
         }
         final InputPointers dstCopy = new InputPointers(DEFAULT_CAPACITY);
         dstCopy.copy(dst);
 
-        dst.append(src, 0, 0);
-        assertEquals("size after append zero", dstLen, dst.getPointerSize());
-        assertIntArrayEquals("xCoordinates after append zero",
-                dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLen);
-        assertIntArrayEquals("yCoordinates after append zero",
-                dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLen);
-        assertIntArrayEquals("pointerIds after append zero",
-                dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLen);
-        assertIntArrayEquals("times after append zero",
-                dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLen);
+        final ResizableIntArray srcXCoords = new ResizableIntArray(DEFAULT_CAPACITY);
+        final ResizableIntArray srcYCoords = new ResizableIntArray(DEFAULT_CAPACITY);
+        final ResizableIntArray srcPointerIds = new ResizableIntArray(DEFAULT_CAPACITY);
+        final ResizableIntArray srcTimes = new ResizableIntArray(DEFAULT_CAPACITY);
+        final int srcLength = 100;
+        final int srcPointerId = 10;
+        for (int i = 0; i < srcLength; i++) {
+            final int x = i;
+            final int y = i * 2;
+            // The time value must be larger than <code>dst</code>.
+            final int time = i * 4 + dstLength;
+            srcXCoords.add(x);
+            srcYCoords.add(y);
+            srcPointerIds.add(srcPointerId);
+            srcTimes.add(time);
+        }
 
-        dst.append(src, 0, srcLen);
-        assertEquals("size after append", dstLen + srcLen, dst.getPointerSize());
+        final int startPos = 0;
+        dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords,
+                startPos, 0 /* length */);
+        assertEquals("size after append zero", dstLength, dst.getPointerSize());
+        assertIntArrayEquals("xCoordinates after append zero",
+                dstCopy.getXCoordinates(), startPos, dst.getXCoordinates(), startPos, dstLength);
+        assertIntArrayEquals("yCoordinates after append zero",
+                dstCopy.getYCoordinates(), startPos, dst.getYCoordinates(), startPos, dstLength);
+        assertIntArrayEquals("pointerIds after append zero",
+                dstCopy.getPointerIds(), startPos, dst.getPointerIds(), startPos, dstLength);
+        assertIntArrayEquals("times after append zero",
+                dstCopy.getTimes(), startPos, dst.getTimes(), startPos, dstLength);
+
+        dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords,
+                startPos, srcLength);
+        assertEquals("size after append", dstLength + srcLength, dst.getPointerSize());
         assertTrue("primitive length after append",
-                dst.getPointerIds().length >= dstLen + srcLen);
+                dst.getPointerIds().length >= dstLength + srcLength);
         assertIntArrayEquals("original xCoordinates values after append",
-                dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLen);
+                dstCopy.getXCoordinates(), startPos, dst.getXCoordinates(), startPos, dstLength);
         assertIntArrayEquals("original yCoordinates values after append",
-                dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLen);
+                dstCopy.getYCoordinates(), startPos, dst.getYCoordinates(), startPos, dstLength);
         assertIntArrayEquals("original pointerIds values after append",
-                dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLen);
+                dstCopy.getPointerIds(), startPos, dst.getPointerIds(), startPos, dstLength);
         assertIntArrayEquals("original times values after append",
-                dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLen);
+                dstCopy.getTimes(), startPos, dst.getTimes(), startPos, dstLength);
         assertIntArrayEquals("appended xCoordinates values after append",
-                src.getXCoordinates(), 0, dst.getXCoordinates(), dstLen, srcLen);
+                srcXCoords.getPrimitiveArray(), startPos, dst.getXCoordinates(),
+                dstLength, srcLength);
         assertIntArrayEquals("appended yCoordinates values after append",
-                src.getYCoordinates(), 0, dst.getYCoordinates(), dstLen, srcLen);
+                srcYCoords.getPrimitiveArray(), startPos, dst.getYCoordinates(),
+                dstLength, srcLength);
         assertIntArrayEquals("appended pointerIds values after append",
-                src.getPointerIds(), 0, dst.getPointerIds(), dstLen, srcLen);
+                srcPointerIds.getPrimitiveArray(), startPos, dst.getPointerIds(),
+                dstLength, srcLength);
         assertIntArrayEquals("appended times values after append",
-                src.getTimes(), 0, dst.getTimes(), dstLen, srcLen);
+                srcTimes.getPrimitiveArray(), startPos, dst.getTimes(), dstLength, srcLength);
     }
 
     public void testAppendResizableIntArray() {
-        final int srcLen = 100;
+        final int dstLength = 50;
+        final InputPointers dst = new InputPointers(DEFAULT_CAPACITY);
+        for (int i = 0; i < dstLength; i++) {
+            final int x = i * 4;
+            final int y = i * 3;
+            final int pointerId = i * 2;
+            final int time = i;
+            dst.addPointer(x, y, pointerId, time);
+        }
+        final InputPointers dstCopy = new InputPointers(DEFAULT_CAPACITY);
+        dstCopy.copy(dst);
+
+        final int srcLength = 100;
         final int srcPointerId = 1;
-        final int[] srcPointerIds = new int[srcLen];
+        final int[] srcPointerIds = new int[srcLength];
         Arrays.fill(srcPointerIds, srcPointerId);
         final ResizableIntArray srcTimes = new ResizableIntArray(DEFAULT_CAPACITY);
         final ResizableIntArray srcXCoords = new ResizableIntArray(DEFAULT_CAPACITY);
         final ResizableIntArray srcYCoords= new ResizableIntArray(DEFAULT_CAPACITY);
-        for (int i = 0; i < srcLen; i++) {
-            srcTimes.add(i * 2);
-            srcXCoords.add(i * 3);
-            srcYCoords.add(i * 4);
+        for (int i = 0; i < srcLength; i++) {
+            // The time value must be larger than <code>dst</code>.
+            final int time = i * 2 + dstLength;
+            final int x = i * 3;
+            final int y = i * 4;
+            srcTimes.add(time);
+            srcXCoords.add(x);
+            srcYCoords.add(y);
         }
-        final int dstLen = 50;
-        final InputPointers dst = new InputPointers(DEFAULT_CAPACITY);
-        for (int i = 0; i < dstLen; i++) {
-            final int value = -i - 1;
-            dst.addPointer(value * 4, value * 3, value * 2, value);
-        }
-        final InputPointers dstCopy = new InputPointers(DEFAULT_CAPACITY);
-        dstCopy.copy(dst);
 
         dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, 0, 0);
-        assertEquals("size after append zero", dstLen, dst.getPointerSize());
+        assertEquals("size after append zero", dstLength, dst.getPointerSize());
         assertIntArrayEquals("xCoordinates after append zero",
-                dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLen);
+                dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLength);
         assertIntArrayEquals("yCoordinates after append zero",
-                dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLen);
+                dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLength);
         assertIntArrayEquals("pointerIds after append zero",
-                dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLen);
+                dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLength);
         assertIntArrayEquals("times after append zero",
-                dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLen);
+                dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLength);
 
-        dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, 0, srcLen);
-        assertEquals("size after append", dstLen + srcLen, dst.getPointerSize());
+        dst.append(srcPointerId, srcTimes, srcXCoords, srcYCoords, 0, srcLength);
+        assertEquals("size after append", dstLength + srcLength, dst.getPointerSize());
         assertTrue("primitive length after append",
-                dst.getPointerIds().length >= dstLen + srcLen);
+                dst.getPointerIds().length >= dstLength + srcLength);
         assertIntArrayEquals("original xCoordinates values after append",
-                dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLen);
+                dstCopy.getXCoordinates(), 0, dst.getXCoordinates(), 0, dstLength);
         assertIntArrayEquals("original yCoordinates values after append",
-                dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLen);
+                dstCopy.getYCoordinates(), 0, dst.getYCoordinates(), 0, dstLength);
         assertIntArrayEquals("original pointerIds values after append",
-                dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLen);
+                dstCopy.getPointerIds(), 0, dst.getPointerIds(), 0, dstLength);
         assertIntArrayEquals("original times values after append",
-                dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLen);
+                dstCopy.getTimes(), 0, dst.getTimes(), 0, dstLength);
         assertIntArrayEquals("appended xCoordinates values after append",
-                srcXCoords.getPrimitiveArray(), 0, dst.getXCoordinates(), dstLen, srcLen);
+                srcXCoords.getPrimitiveArray(), 0, dst.getXCoordinates(), dstLength, srcLength);
         assertIntArrayEquals("appended yCoordinates values after append",
-                srcYCoords.getPrimitiveArray(), 0, dst.getYCoordinates(), dstLen, srcLen);
+                srcYCoords.getPrimitiveArray(), 0, dst.getYCoordinates(), dstLength, srcLength);
         assertIntArrayEquals("appended pointerIds values after append",
-                srcPointerIds, 0, dst.getPointerIds(), dstLen, srcLen);
+                srcPointerIds, 0, dst.getPointerIds(), dstLength, srcLength);
         assertIntArrayEquals("appended times values after append",
-                srcTimes.getPrimitiveArray(), 0, dst.getTimes(), dstLen, srcLen);
+                srcTimes.getPrimitiveArray(), 0, dst.getTimes(), dstLength, srcLength);
     }
 
     // TODO: Consolidate this method with
@@ -250,14 +303,24 @@
         final int limit = 100;
         final int shiftAmount = 20;
         for (int i = 0; i < limit; i++) {
-            src.addPointer(i, i * 2, i * 3, i * 4);
+            final int x = i;
+            final int y = i * 2;
+            final int pointerId = i * 3;
+            final int time = i * 4;
+            src.addPointer(x, y, pointerId, time);
         }
         src.shift(shiftAmount);
+        assertEquals("length after shift", src.getPointerSize(), limit - shiftAmount);
         for (int i = 0; i < limit - shiftAmount; ++i) {
-            assertEquals("xCoordinates at " + i, i + shiftAmount, src.getXCoordinates()[i]);
-            assertEquals("yCoordinates at " + i, (i + shiftAmount) * 2, src.getYCoordinates()[i]);
-            assertEquals("pointerIds at " + i, (i + shiftAmount) * 3, src.getPointerIds()[i]);
-            assertEquals("times at " + i, (i + shiftAmount) * 4, src.getTimes()[i]);
+            final int oldIndex = i + shiftAmount;
+            final int x = oldIndex;
+            final int y = oldIndex * 2;
+            final int pointerId = oldIndex * 3;
+            final int time = oldIndex * 4;
+            assertEquals("xCoordinates at " + i, x, src.getXCoordinates()[i]);
+            assertEquals("yCoordinates at " + i, y, src.getYCoordinates()[i]);
+            assertEquals("pointerIds at " + i, pointerId, src.getPointerIds()[i]);
+            assertEquals("times at " + i, time, src.getTimes()[i]);
         }
     }
 }
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index cee73c9..84e8a86 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -25,6 +25,7 @@
 import android.text.SpannableStringBuilder;
 import android.text.style.CharacterStyle;
 import android.text.style.SuggestionSpan;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -41,8 +42,10 @@
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 
 import java.util.Locale;
+import java.util.concurrent.TimeUnit;
 
 public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
+    private static final String TAG = InputTestsBase.class.getSimpleName();
 
     private static final String PREF_DEBUG_MODE = "debug_mode";
     private static final String PREF_AUTO_CORRECTION_THRESHOLD = "auto_correction_threshold";
@@ -54,6 +57,7 @@
     protected static final int DELAY_TO_WAIT_FOR_UNDERLINE = 500;
     // The message that sets predictions is posted with a 200 ms delay
     protected static final int DELAY_TO_WAIT_FOR_PREDICTIONS = 200;
+    private final int TIMEOUT_TO_WAIT_FOR_LOADING_MAIN_DICTIONARY_IN_SECONDS = 60;
 
     protected LatinIME mLatinIME;
     protected Keyboard mKeyboard;
@@ -260,15 +264,11 @@
     }
 
     protected void waitForDictionaryToBeLoaded() {
-        int remainingAttempts = 300;
-        while (remainingAttempts > 0 && mLatinIME.isCurrentlyWaitingForMainDictionary()) {
-            try {
-                Thread.sleep(200);
-            } catch (InterruptedException e) {
-                // Don't do much
-            } finally {
-                --remainingAttempts;
-            }
+        try {
+            mLatinIME.waitForMainDictionary(
+                    TIMEOUT_TO_WAIT_FOR_LOADING_MAIN_DICTIONARY_IN_SECONDS, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            Log.e(TAG, "Interrupted during waiting for loading main dictionary.", e);
         }
     }
 
@@ -300,8 +300,7 @@
             final String dictLocale) {
         changeLanguage(keyboardLocale);
         if (!keyboardLocale.equals(dictLocale)) {
-            mLatinIME.replaceMainDictionaryForTest(
-                    LocaleUtils.constructLocaleFromString(dictLocale));
+            mLatinIME.replaceDictionariesForTest(LocaleUtils.constructLocaleFromString(dictLocale));
         }
         waitForDictionaryToBeLoaded();
     }
diff --git a/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java b/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java
index cad80d5..8f58e68 100644
--- a/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/ResizableIntArrayTests.java
@@ -39,7 +39,8 @@
         int[] array2 = null, array3 = null;
         final int limit = DEFAULT_CAPACITY * 2 + 10;
         for (int i = 0; i < limit; i++) {
-            src.add(i);
+            final int value = i;
+            src.add(value);
             assertEquals("length after add " + i, i + 1, src.getLength());
             if (i == DEFAULT_CAPACITY) {
                 array2 = src.getPrimitiveArray();
@@ -56,7 +57,8 @@
             }
         }
         for (int i = 0; i < limit; i++) {
-            assertEquals("value at " + i, i, src.get(i));
+            final int value = i;
+            assertEquals("value at " + i, value, src.get(i));
         }
     }
 
@@ -64,11 +66,13 @@
         final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY);
         final int limit = DEFAULT_CAPACITY * 10, step = DEFAULT_CAPACITY * 2;
         for (int i = 0; i < limit; i += step) {
-            src.add(i, i);
+            final int value = i;
+            src.addAt(i, value);
             assertEquals("length after add at " + i, i + 1, src.getLength());
         }
         for (int i = 0; i < limit; i += step) {
-            assertEquals("value at " + i, i, src.get(i));
+            final int value = i;
+            assertEquals("value at " + i, value, src.get(i));
         }
     }
 
@@ -88,9 +92,10 @@
         }
 
         final int index = DEFAULT_CAPACITY / 2;
-        src.add(index, 100);
+        final int valueAddAt = 100;
+        src.addAt(index, valueAddAt);
         assertEquals("legth after add at " + index, index + 1, src.getLength());
-        assertEquals("value after add at " + index, 100, src.get(index));
+        assertEquals("value after add at " + index, valueAddAt, src.get(index));
         assertEquals("value after add at 0", 0, src.get(0));
         try {
             final int value = src.get(src.getLength());
@@ -104,7 +109,8 @@
         final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY);
         final int[] array = src.getPrimitiveArray();
         for (int i = 0; i < DEFAULT_CAPACITY; i++) {
-            src.add(i);
+            final int value = i;
+            src.add(value);
             assertEquals("length after add " + i, i + 1, src.getLength());
         }
 
@@ -116,7 +122,8 @@
 
         int[] array3 = null;
         for (int i = 0; i < DEFAULT_CAPACITY; i++) {
-            src.add(i);
+            final int value = i;
+            src.add(value);
             assertEquals("length after add " + i, i + 1, src.getLength());
             if (i == smallerLength) {
                 array3 = src.getPrimitiveArray();
@@ -133,7 +140,8 @@
         final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY);
         final int[] array = src.getPrimitiveArray();
         for (int i = 0; i < DEFAULT_CAPACITY; i++) {
-            src.add(i);
+            final int value = i;
+            src.add(value);
             assertEquals("length after add " + i, i + 1, src.getLength());
         }
 
@@ -144,11 +152,11 @@
         assertNotSame("array after larger setLength", array, array2);
         assertEquals("array length after larger setLength", largerLength, array2.length);
         for (int i = 0; i < largerLength; i++) {
-            final int v = src.get(i);
+            final int value = i;
             if (i < DEFAULT_CAPACITY) {
-                assertEquals("value at " + i, i, v);
+                assertEquals("value at " + i, value, src.get(i));
             } else {
-                assertEquals("value at " + i, 0, v);
+                assertEquals("value at " + i, 0, src.get(i));
             }
         }
 
@@ -159,7 +167,8 @@
         assertSame("array after smaller setLength", array2, array3);
         assertEquals("array length after smaller setLength", largerLength, array3.length);
         for (int i = 0; i < smallerLength; i++) {
-            assertEquals("value at " + i, i, src.get(i));
+            final int value = i;
+            assertEquals("value at " + i, value, src.get(i));
         }
     }
 
@@ -167,7 +176,8 @@
         final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY);
         final int limit = DEFAULT_CAPACITY * 2 + 10;
         for (int i = 0; i < limit; i++) {
-            src.add(i);
+            final int value = i;
+            src.add(value);
         }
 
         final ResizableIntArray dst = new ResizableIntArray(DEFAULT_CAPACITY);
@@ -179,7 +189,8 @@
     public void testCopy() {
         final ResizableIntArray src = new ResizableIntArray(DEFAULT_CAPACITY);
         for (int i = 0; i < DEFAULT_CAPACITY; i++) {
-            src.add(i);
+            final int value =  i;
+            src.add(value);
         }
 
         final ResizableIntArray dst = new ResizableIntArray(DEFAULT_CAPACITY);
@@ -204,119 +215,126 @@
     }
 
     public void testAppend() {
-        final int srcLen = DEFAULT_CAPACITY;
-        final ResizableIntArray src = new ResizableIntArray(srcLen);
-        for (int i = 0; i < srcLen; i++) {
-            src.add(i);
+        final int srcLength = DEFAULT_CAPACITY;
+        final ResizableIntArray src = new ResizableIntArray(srcLength);
+        for (int i = 0; i < srcLength; i++) {
+            final int value = i;
+            src.add(value);
         }
         final ResizableIntArray dst = new ResizableIntArray(DEFAULT_CAPACITY * 2);
         final int[] array = dst.getPrimitiveArray();
-        final int dstLen = DEFAULT_CAPACITY / 2;
-        for (int i = 0; i < dstLen; i++) {
+        final int dstLength = DEFAULT_CAPACITY / 2;
+        for (int i = 0; i < dstLength; i++) {
             final int value = -i - 1;
             dst.add(value);
         }
         final ResizableIntArray dstCopy = new ResizableIntArray(dst.getLength());
         dstCopy.copy(dst);
 
-        dst.append(src, 0, 0);
-        assertEquals("length after append zero", dstLen, dst.getLength());
+        final int startPos = 0;
+        dst.append(src, startPos, 0 /* length */);
+        assertEquals("length after append zero", dstLength, dst.getLength());
         assertSame("array after append zero", array, dst.getPrimitiveArray());
-        assertIntArrayEquals("values after append zero",
-                dstCopy.getPrimitiveArray(), 0, dst.getPrimitiveArray(), 0, dstLen);
+        assertIntArrayEquals("values after append zero", dstCopy.getPrimitiveArray(), startPos,
+                dst.getPrimitiveArray(), startPos, dstLength);
 
-        dst.append(src, 0, srcLen);
-        assertEquals("length after append", dstLen + srcLen, dst.getLength());
+        dst.append(src, startPos, srcLength);
+        assertEquals("length after append", dstLength + srcLength, dst.getLength());
         assertSame("array after append", array, dst.getPrimitiveArray());
         assertTrue("primitive length after append",
-                dst.getPrimitiveArray().length >= dstLen + srcLen);
-        assertIntArrayEquals("original values after append",
-                dstCopy.getPrimitiveArray(), 0, dst.getPrimitiveArray(), 0, dstLen);
-        assertIntArrayEquals("appended values after append",
-                src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen, srcLen);
+                dst.getPrimitiveArray().length >= dstLength + srcLength);
+        assertIntArrayEquals("original values after append", dstCopy.getPrimitiveArray(), startPos,
+                dst.getPrimitiveArray(), startPos, dstLength);
+        assertIntArrayEquals("appended values after append", src.getPrimitiveArray(), startPos,
+                dst.getPrimitiveArray(), dstLength, srcLength);
 
-        dst.append(src, 0, srcLen);
-        assertEquals("length after 2nd append", dstLen + srcLen * 2, dst.getLength());
+        dst.append(src, startPos, srcLength);
+        assertEquals("length after 2nd append", dstLength + srcLength * 2, dst.getLength());
         assertNotSame("array after 2nd append", array, dst.getPrimitiveArray());
         assertTrue("primitive length after 2nd append",
-                dst.getPrimitiveArray().length >= dstLen + srcLen * 2);
+                dst.getPrimitiveArray().length >= dstLength + srcLength * 2);
         assertIntArrayEquals("original values after 2nd append",
-                dstCopy.getPrimitiveArray(), 0, dst.getPrimitiveArray(), 0, dstLen);
+                dstCopy.getPrimitiveArray(), startPos, dst.getPrimitiveArray(), startPos,
+                dstLength);
         assertIntArrayEquals("appended values after 2nd append",
-                src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen, srcLen);
+                src.getPrimitiveArray(), startPos, dst.getPrimitiveArray(), dstLength,
+                srcLength);
         assertIntArrayEquals("appended values after 2nd append",
-                src.getPrimitiveArray(), 0, dst.getPrimitiveArray(), dstLen + srcLen, srcLen);
+                src.getPrimitiveArray(), startPos, dst.getPrimitiveArray(), dstLength + srcLength,
+                srcLength);
     }
 
     public void testFill() {
-        final int srcLen = DEFAULT_CAPACITY;
-        final ResizableIntArray src = new ResizableIntArray(srcLen);
-        for (int i = 0; i < srcLen; i++) {
-            src.add(i);
+        final int srcLength = DEFAULT_CAPACITY;
+        final ResizableIntArray src = new ResizableIntArray(srcLength);
+        for (int i = 0; i < srcLength; i++) {
+            final int value = i;
+            src.add(value);
         }
         final int[] array = src.getPrimitiveArray();
 
-        final int startPos = srcLen / 3;
-        final int length = srcLen / 3;
+        final int startPos = srcLength / 3;
+        final int length = srcLength / 3;
         final int endPos = startPos + length;
         assertTrue(startPos >= 1);
-        final int value = 123;
+        final int fillValue = 123;
         try {
-            src.fill(value, -1, length);
+            src.fill(fillValue, -1 /* startPos */, length);
             fail("fill from -1 shouldn't succeed");
         } catch (IllegalArgumentException e) {
             // success
         }
         try {
-            src.fill(value, startPos, -1);
+            src.fill(fillValue, startPos, -1 /* length */);
             fail("fill negative length shouldn't succeed");
         } catch (IllegalArgumentException e) {
             // success
         }
 
-        src.fill(value, startPos, length);
-        assertEquals("length after fill", srcLen, src.getLength());
+        src.fill(fillValue, startPos, length);
+        assertEquals("length after fill", srcLength, src.getLength());
         assertSame("array after fill", array, src.getPrimitiveArray());
-        for (int i = 0; i < srcLen; i++) {
-            final int v = src.get(i);
+        for (int i = 0; i < srcLength; i++) {
+            final int value = i;
             if (i >= startPos && i < endPos) {
-                assertEquals("new values after fill at " + i, value, v);
+                assertEquals("new values after fill at " + i, fillValue, src.get(i));
             } else {
-                assertEquals("unmodified values after fill at " + i, i, v);
+                assertEquals("unmodified values after fill at " + i, value, src.get(i));
             }
         }
 
-        final int length2 = srcLen * 2 - startPos;
+        final int length2 = srcLength * 2 - startPos;
         final int largeEnd = startPos + length2;
-        assertTrue(largeEnd > srcLen);
-        final int value2 = 456;
-        src.fill(value2, startPos, length2);
+        assertTrue(largeEnd > srcLength);
+        final int fillValue2 = 456;
+        src.fill(fillValue2, startPos, length2);
         assertEquals("length after large fill", largeEnd, src.getLength());
         assertNotSame("array after large fill", array, src.getPrimitiveArray());
         for (int i = 0; i < largeEnd; i++) {
-            final int v = src.get(i);
+            final int value = i;
             if (i >= startPos && i < largeEnd) {
-                assertEquals("new values after large fill at " + i, value2, v);
+                assertEquals("new values after large fill at " + i, fillValue2, src.get(i));
             } else {
-                assertEquals("unmodified values after large fill at " + i, i, v);
+                assertEquals("unmodified values after large fill at " + i, value, src.get(i));
             }
         }
 
         final int startPos2 = largeEnd + length2;
         final int endPos2 = startPos2 + length2;
-        final int value3 = 789;
-        src.fill(value3, startPos2, length2);
+        final int fillValue3 = 789;
+        src.fill(fillValue3, startPos2, length2);
         assertEquals("length after disjoint fill", endPos2, src.getLength());
         for (int i = 0; i < endPos2; i++) {
-            final int v = src.get(i);
+            final int value = i;
             if (i >= startPos2 && i < endPos2) {
-                assertEquals("new values after disjoint fill at " + i, value3, v);
+                assertEquals("new values after disjoint fill at " + i, fillValue3, src.get(i));
             } else if (i >= startPos && i < largeEnd) {
-                assertEquals("unmodified values after disjoint fill at " + i, value2, v);
+                assertEquals("unmodified values after disjoint fill at " + i,
+                        fillValue2, src.get(i));
             } else if (i < startPos) {
-                assertEquals("unmodified values after disjoint fill at " + i, i, v);
+                assertEquals("unmodified values after disjoint fill at " + i, value, src.get(i));
             } else {
-                assertEquals("gap values after disjoint fill at " + i, 0, v);
+                assertEquals("gap values after disjoint fill at " + i, 0, src.get(i));
             }
         }
     }
@@ -346,12 +364,14 @@
         final int limit = DEFAULT_CAPACITY * 10;
         final int shiftAmount = 20;
         for (int i = 0; i < limit; ++i) {
-            src.add(i, i);
+            final int value = i;
+            src.addAt(i, value);
             assertEquals("length after add at " + i, i + 1, src.getLength());
         }
         src.shift(shiftAmount);
         for (int i = 0; i < limit - shiftAmount; ++i) {
-            assertEquals("value at " + i, i + shiftAmount, src.get(i));
+            final int oldValue = i + shiftAmount;
+            assertEquals("value at " + i, oldValue, src.get(i));
         }
     }
 }