Merge "No logging of passwords."
diff --git a/java/res/layout/more_suggestions.xml b/java/res/layout/more_suggestions.xml
index 49a00c6..b41bb8a 100644
--- a/java/res/layout/more_suggestions.xml
+++ b/java/res/layout/more_suggestions.xml
@@ -29,6 +29,7 @@
             android:id="@+id/more_suggestions_view"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
+            latin:keyLetterSize="@dimen/suggestion_text_size"
             latin:keyLabelSize="@dimen/suggestion_text_size"
             latin:keyHintLetterRatio="@fraction/more_suggestions_info_ratio"
             latin:keyHintLetterColor="@android:color/white"
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
index ccc0643..22543ef 100644
--- a/java/res/values-af/strings.xml
+++ b/java/res/values-af/strings.xml
@@ -112,12 +112,12 @@
     <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Steminvoer is gedeaktiveer"</string>
     <string name="configure_input_method" msgid="373356270290742459">"Stel invoermetodes op"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Invoertale"</string>
-    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"Let wel: plaas tydstempel in loglêer"</string>
+    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"let op die tydstempel in die loglêer"</string>
     <string name="notify_recorded_timestamp" msgid="8036429032449612051">"Aangetekende tydstempel"</string>
     <string name="do_not_log_this_session" msgid="413762473641146336">"Moenie hierdie sessie aanteken nie"</string>
-    <string name="notify_session_log_deleting" msgid="3299507647764414623">"Sessie se loglêer geskrap"</string>
-    <string name="notify_session_log_deleted" msgid="8687927130100934686">"Sessie se loglêer geskrap"</string>
-    <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"Sessie se loglêer NIE geskrap nie"</string>
+    <string name="notify_session_log_deleting" msgid="3299507647764414623">"Sessie se loglêer uitgevee"</string>
+    <string name="notify_session_log_deleted" msgid="8687927130100934686">"Sessie se loglêer uitgevee"</string>
+    <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"Sessie se loglêer NIE uitgevee nie"</string>
     <string name="select_language" msgid="3693815588777926848">"Invoertale"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Raak weer om te stoor"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Woordeboek beskikbaar"</string>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index b3cb298..2a22074 100644
--- a/java/res/values-ar/strings.xml
+++ b/java/res/values-ar/strings.xml
@@ -112,7 +112,7 @@
     <string name="voice_input_modes_summary_off" msgid="63875609591897607">"الإدخال الصوتي مُعطل"</string>
     <string name="configure_input_method" msgid="373356270290742459">"تهيئة طرق الإدخال"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"لغات الإدخال"</string>
-    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"ملاحظة الطابع الزمني في السجل"</string>
+    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"ملاحظة طابع زمني في سجل"</string>
     <string name="notify_recorded_timestamp" msgid="8036429032449612051">"تم تسجيل الطابع الزمني"</string>
     <string name="do_not_log_this_session" msgid="413762473641146336">"عدم تسجيل هذه الجلسة"</string>
     <string name="notify_session_log_deleting" msgid="3299507647764414623">"جارٍ حذف سجل الجلسة"</string>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
index dd2c568..1b7cfc2 100644
--- a/java/res/values-ca/strings.xml
+++ b/java/res/values-ca/strings.xml
@@ -24,7 +24,7 @@
     <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Teclat d\'Android (AOSP)"</string>
     <string name="english_ime_settings" msgid="6661589557206947774">"Configuració del teclat d\'Android"</string>
     <string name="english_ime_input_options" msgid="3909945612939668554">"Opcions d\'entrada"</string>
-    <string name="english_ime_research_log" msgid="8492602295696577851">"Recerca d\'ordres de registre"</string>
+    <string name="english_ime_research_log" msgid="8492602295696577851">"Recerca d\'ordres de reg."</string>
     <string name="spell_checker_service_name" msgid="7338064335159755926">"Corrector ortogràfic d\'Android"</string>
     <string name="aosp_spell_checker_service_name" msgid="6985142605330377819">"Corrector ortogràfic d\'Android (AOSP)"</string>
     <string name="android_spell_checker_settings" msgid="5822324635435443689">"Configuració de la correcció ortogràfica"</string>
@@ -112,12 +112,12 @@
     <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Entr. veu desactiv."</string>
     <string name="configure_input_method" msgid="373356270290742459">"Configura mètodes d\'entrada"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Idiomes d\'entrada"</string>
-    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"Indica la marca horària al registre"</string>
-    <string name="notify_recorded_timestamp" msgid="8036429032449612051">"S\'ha enregistrat la marca horària"</string>
-    <string name="do_not_log_this_session" msgid="413762473641146336">"No registris aquesta sessió"</string>
-    <string name="notify_session_log_deleting" msgid="3299507647764414623">"S\'està suprimint el registre de la sessió"</string>
-    <string name="notify_session_log_deleted" msgid="8687927130100934686">"S\'ha suprimit el registre de la sessió"</string>
-    <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"El registre d\'aquesta sessió NO s\'ha suprimit"</string>
+    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"Indica m. horària al reg."</string>
+    <string name="notify_recorded_timestamp" msgid="8036429032449612051">"Marca horària enregistrada"</string>
+    <string name="do_not_log_this_session" msgid="413762473641146336">"No enregistris la sessió"</string>
+    <string name="notify_session_log_deleting" msgid="3299507647764414623">"Suprimint registre de ses."</string>
+    <string name="notify_session_log_deleted" msgid="8687927130100934686">"Registre de ses. suprimit"</string>
+    <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"Registre de ses. NO sup."</string>
     <string name="select_language" msgid="3693815588777926848">"Idiomes d\'entrada"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Torna a tocar per desar"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Diccionari disponible"</string>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index 5ce2d57..ffe2b2b 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -24,7 +24,7 @@
     <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Klávesnice Android (AOSP)"</string>
     <string name="english_ime_settings" msgid="6661589557206947774">"Nastavení klávesnice Android"</string>
     <string name="english_ime_input_options" msgid="3909945612939668554">"Možnosti zadávání textu a dat"</string>
-    <string name="english_ime_research_log" msgid="8492602295696577851">"Příkazy pro protokol"</string>
+    <string name="english_ime_research_log" msgid="8492602295696577851">"Příkazy vývoj. protokolu"</string>
     <string name="spell_checker_service_name" msgid="7338064335159755926">"Kontrola pravopisu Android"</string>
     <string name="aosp_spell_checker_service_name" msgid="6985142605330377819">"Kontrola pravopisu Android (AOSP)"</string>
     <string name="android_spell_checker_settings" msgid="5822324635435443689">"Nastavení kontroly pravopisu"</string>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index 1939e69..5dcbf43 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -24,7 +24,7 @@
     <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Πληκτρολόγιο Android (AOSP)"</string>
     <string name="english_ime_settings" msgid="6661589557206947774">"Ρυθμίσεις πληκτρολογίου Android"</string>
     <string name="english_ime_input_options" msgid="3909945612939668554">"Επιλογές εισόδου"</string>
-    <string name="english_ime_research_log" msgid="8492602295696577851">"Αναζ.εντολ.αρχ.καταγρ."</string>
+    <string name="english_ime_research_log" msgid="8492602295696577851">"Έρευνα εντολών καταγραφής"</string>
     <string name="spell_checker_service_name" msgid="7338064335159755926">"Ορθογραφικός έλεγχος Android"</string>
     <string name="aosp_spell_checker_service_name" msgid="6985142605330377819">"Ορθογραφικός έλεγχος Android (AOSP)"</string>
     <string name="android_spell_checker_settings" msgid="5822324635435443689">"Ρυθμίσεις ορθογραφικού ελέγχου"</string>
@@ -112,12 +112,12 @@
     <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Απεν. φωνητ. είσοδος"</string>
     <string name="configure_input_method" msgid="373356270290742459">"Διαμόρφωση μεθόδων εισαγωγής"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Γλώσσες εισόδου"</string>
-    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"Χρον.σήμ. στο αρχ. κατ."</string>
-    <string name="notify_recorded_timestamp" msgid="8036429032449612051">"Καταγεγ. χρον. σήμ."</string>
-    <string name="do_not_log_this_session" msgid="413762473641146336">"Περ.συνδ.χωρίς αρχ.κατ."</string>
-    <string name="notify_session_log_deleting" msgid="3299507647764414623">"Διαγ.αρχ.κατ.περ.συνδ."</string>
-    <string name="notify_session_log_deleted" msgid="8687927130100934686">"Το αρχ.κατ.περ.συν.διαγρ."</string>
-    <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"Το αρχ.κατ.περ.συν.ΔΕΝ διαγ."</string>
+    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"Χρόνος στο αρχείο καταγρ."</string>
+    <string name="notify_recorded_timestamp" msgid="8036429032449612051">"Καταγεγραμμένος χρόνος"</string>
+    <string name="do_not_log_this_session" msgid="413762473641146336">"Χωρίς αρχείο καταγραφής"</string>
+    <string name="notify_session_log_deleting" msgid="3299507647764414623">"Διαγραφή αρχείου σύνδεσης"</string>
+    <string name="notify_session_log_deleted" msgid="8687927130100934686">"Αρχείο καταγρ. διαγράφηκε"</string>
+    <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"Αρχείο καταγρ. ΔΕΝ διαγρ."</string>
     <string name="select_language" msgid="3693815588777926848">"Γλώσσες εισόδου"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Αγγίξτε ξανά για αποθήκευση"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Λεξικό διαθέσιμο"</string>
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index 9d06a41..c131e12 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -114,7 +114,7 @@
     <string name="language_selection_title" msgid="1651299598555326750">"इनपुट भाषा"</string>
     <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"लॉग में टाइमस्‍टैम्‍प नोट करें"</string>
     <string name="notify_recorded_timestamp" msgid="8036429032449612051">"रिकॉर्ड किया गया टाइमस्टैम्प"</string>
-    <string name="do_not_log_this_session" msgid="413762473641146336">"इस सत्र को लॉग नहीं करें"</string>
+    <string name="do_not_log_this_session" msgid="413762473641146336">"इस सत्र को लॉग न करें"</string>
     <string name="notify_session_log_deleting" msgid="3299507647764414623">"सत्र लॉग हटाया जा रहा है"</string>
     <string name="notify_session_log_deleted" msgid="8687927130100934686">"सत्र लॉग हटाया गया"</string>
     <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"सत्र लॉग हटाया नहीं गया"</string>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index 94e8d8c..f8a198d 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -115,7 +115,7 @@
     <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"Zabilježi razdoblje u dnevniku"</string>
     <string name="notify_recorded_timestamp" msgid="8036429032449612051">"Zabilježeno razdoblje"</string>
     <string name="do_not_log_this_session" msgid="413762473641146336">"Ne bilježi ovu sesiju"</string>
-    <string name="notify_session_log_deleting" msgid="3299507647764414623">"Brisanje dnevnik sesije"</string>
+    <string name="notify_session_log_deleting" msgid="3299507647764414623">"Brisanje dnevnika sesije"</string>
     <string name="notify_session_log_deleted" msgid="8687927130100934686">"Izbrisan dnevnik sesije"</string>
     <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"Dnevnik sesije NIJE izbrisan"</string>
     <string name="select_language" msgid="3693815588777926848">"Jezici unosa"</string>
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index 680362e..523a855 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -115,8 +115,8 @@
     <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"Înreg. marc. temp. jurnal"</string>
     <string name="notify_recorded_timestamp" msgid="8036429032449612051">"Marcaj temporal înregis."</string>
     <string name="do_not_log_this_session" msgid="413762473641146336">"Nu înregistraţi sesiunea"</string>
-    <string name="notify_session_log_deleting" msgid="3299507647764414623">"Ştergere jurnal sesiune"</string>
-    <string name="notify_session_log_deleted" msgid="8687927130100934686">"Jurnal sesiune eliminat"</string>
+    <string name="notify_session_log_deleting" msgid="3299507647764414623">"Se șterge jurnal sesiune"</string>
+    <string name="notify_session_log_deleted" msgid="8687927130100934686">"Jurnal de sesiune șters"</string>
     <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"Jurnal sesiune neşters"</string>
     <string name="select_language" msgid="3693815588777926848">"Limbi de intrare"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"Atingeţi din nou pentru a salva"</string>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index 6096a6f..f18de78 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -112,7 +112,7 @@
     <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Glas. vnos je onem."</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="note_timestamp_for_researchlog" msgid="1889446857977976026">"V dnevniku zabeleži časovni žig"</string>
+    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"V dnev. zabeleži čas. žig"</string>
     <string name="notify_recorded_timestamp" msgid="8036429032449612051">"Časovni žig zabeležen"</string>
     <string name="do_not_log_this_session" msgid="413762473641146336">"Brez dnevnika za to sejo"</string>
     <string name="notify_session_log_deleting" msgid="3299507647764414623">"Brisanje seje dnevnika"</string>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
index 21a43cc..c2e743b 100644
--- a/java/res/values-uk/strings.xml
+++ b/java/res/values-uk/strings.xml
@@ -24,7 +24,7 @@
     <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Клавіатура Android (AOSP)"</string>
     <string name="english_ime_settings" msgid="6661589557206947774">"Налашт-ня клавіат. Android"</string>
     <string name="english_ime_input_options" msgid="3909945612939668554">"Парам. введення"</string>
-    <string name="english_ime_research_log" msgid="8492602295696577851">"Команди для журн.дослідж."</string>
+    <string name="english_ime_research_log" msgid="8492602295696577851">"Команди журналу дослідж."</string>
     <string name="spell_checker_service_name" msgid="7338064335159755926">"Засіб перевірки орфографії Android"</string>
     <string name="aosp_spell_checker_service_name" msgid="6985142605330377819">"Засіб перевірки орфографії Android (AOSP)"</string>
     <string name="android_spell_checker_settings" msgid="5822324635435443689">"Налаштування перевірки орфографії"</string>
@@ -112,7 +112,7 @@
     <string name="voice_input_modes_summary_off" msgid="63875609591897607">"Голос. ввід вимкнено"</string>
     <string name="configure_input_method" msgid="373356270290742459">"Налаштування методів введення"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"Мови вводу"</string>
-    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"Указ. мітку часу в журн."</string>
+    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"Мітка часу в журналі"</string>
     <string name="notify_recorded_timestamp" msgid="8036429032449612051">"Записана мітка часу"</string>
     <string name="do_not_log_this_session" msgid="413762473641146336">"Не реєструвати цю сесію"</string>
     <string name="notify_session_log_deleting" msgid="3299507647764414623">"Видалення журналу сесії"</string>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index f5e38f9..4907f20 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -24,7 +24,7 @@
     <string name="aosp_android_keyboard_ime_name" msgid="7877134937939182296">"Android 键盘 (AOSP)"</string>
     <string name="english_ime_settings" msgid="6661589557206947774">"Android 键盘设置"</string>
     <string name="english_ime_input_options" msgid="3909945612939668554">"输入选项"</string>
-    <string name="english_ime_research_log" msgid="8492602295696577851">"探究日志命令"</string>
+    <string name="english_ime_research_log" msgid="8492602295696577851">"研究记录命令"</string>
     <string name="spell_checker_service_name" msgid="7338064335159755926">"Android 拼写检查工具"</string>
     <string name="aosp_spell_checker_service_name" msgid="6985142605330377819">"Android 拼写检查工具 (AOSP)"</string>
     <string name="android_spell_checker_settings" msgid="5822324635435443689">"拼写检查设置"</string>
@@ -112,12 +112,12 @@
     <string name="voice_input_modes_summary_off" msgid="63875609591897607">"语音输入功能已停用"</string>
     <string name="configure_input_method" msgid="373356270290742459">"配置输入法"</string>
     <string name="language_selection_title" msgid="1651299598555326750">"输入语言"</string>
-    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"在日志中记上时间"</string>
-    <string name="notify_recorded_timestamp" msgid="8036429032449612051">"已记录时间"</string>
+    <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"标记记录中的时间"</string>
+    <string name="notify_recorded_timestamp" msgid="8036429032449612051">"已标记时间"</string>
     <string name="do_not_log_this_session" msgid="413762473641146336">"不记录本次会话"</string>
-    <string name="notify_session_log_deleting" msgid="3299507647764414623">"正在删除会话日志"</string>
-    <string name="notify_session_log_deleted" msgid="8687927130100934686">"会话日志已删除"</string>
-    <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"未能删除会话日志"</string>
+    <string name="notify_session_log_deleting" msgid="3299507647764414623">"正在删除会话记录"</string>
+    <string name="notify_session_log_deleted" msgid="8687927130100934686">"会话记录已删除"</string>
+    <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"未能删除会话记录"</string>
     <string name="select_language" msgid="3693815588777926848">"输入语言"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"再次触摸即可保存"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"有可用词典"</string>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index 8dcb407..9179e66 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -115,9 +115,9 @@
     <string name="note_timestamp_for_researchlog" msgid="1889446857977976026">"在紀錄中加註時間戳記"</string>
     <string name="notify_recorded_timestamp" msgid="8036429032449612051">"已記錄時間戳記"</string>
     <string name="do_not_log_this_session" msgid="413762473641146336">"不要記錄這個工作階段"</string>
-    <string name="notify_session_log_deleting" msgid="3299507647764414623">"正在刪除工作階段記錄"</string>
-    <string name="notify_session_log_deleted" msgid="8687927130100934686">"已刪除工作階段記錄"</string>
-    <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"「未」刪除工作階段記錄"</string>
+    <string name="notify_session_log_deleting" msgid="3299507647764414623">"正在刪除工作階段紀錄"</string>
+    <string name="notify_session_log_deleted" msgid="8687927130100934686">"已刪除工作階段紀錄"</string>
+    <string name="notify_session_log_not_deleted" msgid="2592908998810755970">"「未」刪除工作階段紀錄"</string>
     <string name="select_language" msgid="3693815588777926848">"輸入語言"</string>
     <string name="hint_add_to_dictionary" msgid="573678656946085380">"再次輕觸即可儲存"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"可使用字典"</string>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index a565703..0b781af 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -240,7 +240,7 @@
     <!-- Toast notification message that the time has been marked for later review. [CHAR LIMIT=25] -->
     <string name="notify_recorded_timestamp">Recorded timestamp</string>
 
-    <!-- Title for dialog option to let users cancel logging and delete log for this session [CHAR LIMIT=25] -->
+    <!-- Title for dialog option to let users cancel logging and delete log for this session [CHAR LIMIT=35] -->
     <string name="do_not_log_this_session">Do not log this session</string>
     <!-- Toast notification that the system is processing the request to delete the log for this session [CHAR LIMIT=35] -->
     <string name="notify_session_log_deleting">Deleting session log</string>
diff --git a/java/res/xml-sw600dp/key_dash.xml b/java/res/xml-sw600dp/key_dash.xml
index 8f91eff..118b67f 100644
--- a/java/res/xml-sw600dp/key_dash.xml
+++ b/java/res/xml-sw600dp/key_dash.xml
@@ -31,10 +31,9 @@
         <case
             latin:languageCode="ar|fa"
         >
-            <!-- U+064B: "ً" ARABIC FATHATAN -->
             <Key
                 latin:keyLabel="."
-                latin:keyHintLabel="&#x064B;"
+                latin:keyHintLabel="!text/keyhintlabel_for_arabic_diacritics"
                 latin:moreKeys="!text/more_keys_for_arabic_diacritics"
                 latin:keyStyle="hasShiftedLetterHintStyle" />
         </case>
diff --git a/java/res/xml-sw600dp/rowkeys_farsi1.xml b/java/res/xml-sw600dp/rowkeys_farsi1.xml
index ab260a4..53208f2 100644
--- a/java/res/xml-sw600dp/rowkeys_farsi1.xml
+++ b/java/res/xml-sw600dp/rowkeys_farsi1.xml
@@ -45,12 +45,11 @@
     <!-- U+0647: "ه" ARABIC LETTER HEH
          U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM
          U+0647/U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER
-         U+06C0: "ۀ" ARABIC LETTER HEH WITH YEH ABOVE
+         U+0647/U+0654: ARABIC LETTER HEH + ARABIC HAMZA ABOVE
          U+0629: "ة" ARABIC LETTER TEH MARBUTA -->
-    <!-- TODO: DroidSansArabic lacks the glyph of U+06C0 ARABIC LETTER HEH WITH YEH ABOVE -->
     <Key
         latin:keyLabel="&#x0647;"
-        latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;,&#x06C0;,&#x0629;,%" />
+        latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;,&#x0647;&#x0654;,&#x0629;,%" />
     <!-- U+062E: "خ" ARABIC LETTER KHAH -->
     <Key
         latin:keyLabel="&#x062E;" />
diff --git a/java/res/xml/key_styles_currency.xml b/java/res/xml/key_styles_currency.xml
index d5c6a87..6dea16f 100644
--- a/java/res/xml/key_styles_currency.xml
+++ b/java/res/xml/key_styles_currency.xml
@@ -105,6 +105,7 @@
             latin:languageCode="fa"
         >
             <!-- U+FDFC: "﷼" RIAL SIGN
+                 U+060B: "؋" AFGHANI SIGN
                  U+00A3: "£" POUND SIGN
                  U+20AC: "€" EURO SIGN
                  U+00A2: "¢" CENT SIGN -->
@@ -112,20 +113,20 @@
             <key-style
                 latin:styleName="currencyKeyStyle"
                 latin:keyLabel="&#xFDFC;"
-                latin:moreKeys="!text/more_keys_for_currency_general" />
+                latin:moreKeys="!text/more_keys_for_currency_general,&#x060B;" />
             <key-style
                 latin:styleName="moreCurrency1KeyStyle"
-                latin:keyLabel="£" />
+                latin:keyLabel="&#x00A3;" />
             <key-style
                 latin:styleName="moreCurrency2KeyStyle"
-                latin:keyLabel="€" />
+                latin:keyLabel="&#x20AC;" />
             <key-style
                 latin:styleName="moreCurrency3KeyStyle"
                 latin:keyLabel="$"
-                latin:moreKeys="¢" />
+                latin:moreKeys="&#x00A2;" />
             <key-style
                 latin:styleName="moreCurrency4KeyStyle"
-                latin:keyLabel="¢" />
+                latin:keyLabel="&#x00A2;" />
         </case>
         <!-- United Kingdom -->
         <case
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index a026284..07bff09 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -49,7 +49,7 @@
     lt: Lithuanian/qwerty
     lv: Latvian/qwerty
     mk: Macedonian/south_slavic
-    nb: Norwaian Bokmål/nordic
+    nb: Norwegian Bokmål/nordic
     nl: Dutch/qwerty
     pl: Polish/qwerty
     pt_BR: Portuguese Brazil/qwerty
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index 3598a68..1379819 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -122,7 +122,6 @@
                 android:defaultValue="true" />
             <CheckBoxPreference
                 android:key="next_word_prediction"
-                android:dependency="next_word_suggestion"
                 android:title="@string/bigram_prediction"
                 android:summary="@string/bigram_prediction_summary"
                 android:persistent="true"
diff --git a/java/res/xml/row_qwerty4.xml b/java/res/xml/row_qwerty4.xml
index 43385d2..c29fbf2 100644
--- a/java/res/xml/row_qwerty4.xml
+++ b/java/res/xml/row_qwerty4.xml
@@ -36,9 +36,8 @@
             <case
                 latin:languageCode="ar|fa"
             >
-                <!-- U+064B: "ً" ARABIC FATHATAN -->
                 <Key
-                    latin:keyHintLabel="&#x064B;"
+                    latin:keyHintLabel="!text/keyhintlabel_for_arabic_diacritics"
                     latin:keyLabelFlags="hasPopupHint|hasShiftedLetterHint"
                     latin:moreKeys="!text/more_keys_for_arabic_diacritics"
                     latin:keyStyle="punctuationKeyStyle" />
diff --git a/java/res/xml/rowkeys_farsi1.xml b/java/res/xml/rowkeys_farsi1.xml
index 15cb801..81618af7 100644
--- a/java/res/xml/rowkeys_farsi1.xml
+++ b/java/res/xml/rowkeys_farsi1.xml
@@ -22,9 +22,11 @@
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
     <!-- U+0635: "ص" ARABIC LETTER SAD
+         U+0636: "ض" ARABIC LETTER DAD
          U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE -->
     <Key
         latin:keyLabel="&#x0635;"
+        latin:moreKeys="&#x0636;,%"
         latin:keyHintLabel="1"
         latin:additionalMoreKeys="1,&#x06F1;" />
     <!-- U+0642: "ق" ARABIC LETTER QAF
@@ -54,13 +56,12 @@
     <!-- U+0647: "ه" ARABIC LETTER HEH
          U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM
          U+0647/U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER
-         U+06C0: "ۀ" ARABIC LETTER HEH WITH YEH ABOVE
+         U+0647/U+0654: ARABIC LETTER HEH + ARABIC HAMZA ABOVE
          U+0629: "ة" ARABIC LETTER TEH MARBUTA
          U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX -->
-    <!-- TODO: DroidSansArabic lacks the glyph of U+06C0 ARABIC LETTER HEH WITH YEH ABOVE -->
     <Key
         latin:keyLabel="&#x0647;"
-        latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;,&#x06C0;,&#x0629;,%"
+        latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;,&#x0647;&#x0654;,&#x0629;,%"
         latin:keyHintLabel="6"
         latin:additionalMoreKeys="6,&#x06F6;" />
     <!-- U+062E: "خ" ARABIC LETTER KHAH
diff --git a/java/res/xml/rowkeys_farsi3.xml b/java/res/xml/rowkeys_farsi3.xml
index 8db56e3..44710e0 100644
--- a/java/res/xml/rowkeys_farsi3.xml
+++ b/java/res/xml/rowkeys_farsi3.xml
@@ -26,20 +26,20 @@
     <Key
         latin:keyLabel="&#x0637;"
         latin:moreKeys="&#x0638;" />
-    <!-- U+0698: "ژ" ARABIC LETTER JEH -->
+    <!-- U+0632: "ز" ARABIC LETTER ZAIN
+         U+0698: "ژ" ARABIC LETTER JEH -->
     <Key
-        latin:keyLabel="&#x0698;" />
-    <!-- U+0632: "ز" ARABIC LETTER ZAIN -->
-    <Key
-        latin:keyLabel="&#x0632;" />
+        latin:keyLabel="&#x0632;"
+        latin:moreKeys="&#x0698;" />
     <!-- U+0631: "ر" ARABIC LETTER REH -->
     <Key
         latin:keyLabel="&#x0631;" />
-    <!-- U+062F: "د" ARABIC LETTER DAL
-         U+0630: "ذ" ARABIC LETTER THAL -->
+    <!-- U+0630: "ذ" ARABIC LETTER THAL -->
     <Key
-        latin:keyLabel="&#x062F;"
-        latin:moreKeys="&#x0630;" />
+        latin:keyLabel="&#x0630;" />
+    <!-- U+062F: "د" ARABIC LETTER DAL -->
+    <Key
+        latin:keyLabel="&#x062F;" />
     <!-- U+067E: "پ" ARABIC LETTER PEH -->
     <Key
         latin:keyLabel="&#x067E;" />
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index b4fa86d..be7644f 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -159,7 +159,7 @@
 
     @Override
     public boolean dismissMoreKeysPanel() {
-        if (mIsDismissing) return false;
+        if (mIsDismissing || mController == null) return false;
         mIsDismissing = true;
         final boolean dismissed = mController.dismissMoreKeysPanel();
         mIsDismissing = false;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index f429a3e..917e233 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -161,71 +161,72 @@
         /* 53 */ "more_keys_for_right_parenthesis",
         /* 54 */ "more_keys_for_less_than",
         /* 55 */ "more_keys_for_greater_than",
-        /* 56 */ "keylabel_for_symbols_1",
-        /* 57 */ "keylabel_for_symbols_2",
-        /* 58 */ "keylabel_for_symbols_3",
-        /* 59 */ "keylabel_for_symbols_4",
-        /* 60 */ "keylabel_for_symbols_5",
-        /* 61 */ "keylabel_for_symbols_6",
-        /* 62 */ "keylabel_for_symbols_7",
-        /* 63 */ "keylabel_for_symbols_8",
-        /* 64 */ "keylabel_for_symbols_9",
-        /* 65 */ "keylabel_for_symbols_0",
-        /* 66 */ "additional_more_keys_for_symbols_1",
-        /* 67 */ "additional_more_keys_for_symbols_2",
-        /* 68 */ "additional_more_keys_for_symbols_3",
-        /* 69 */ "additional_more_keys_for_symbols_4",
-        /* 70 */ "additional_more_keys_for_symbols_5",
-        /* 71 */ "additional_more_keys_for_symbols_6",
-        /* 72 */ "additional_more_keys_for_symbols_7",
-        /* 73 */ "additional_more_keys_for_symbols_8",
-        /* 74 */ "additional_more_keys_for_symbols_9",
-        /* 75 */ "additional_more_keys_for_symbols_0",
-        /* 76 */ "more_keys_for_symbols_1",
-        /* 77 */ "more_keys_for_symbols_2",
-        /* 78 */ "more_keys_for_symbols_3",
-        /* 79 */ "more_keys_for_symbols_4",
-        /* 80 */ "more_keys_for_symbols_5",
-        /* 81 */ "more_keys_for_symbols_6",
-        /* 82 */ "more_keys_for_symbols_7",
-        /* 83 */ "more_keys_for_symbols_8",
-        /* 84 */ "more_keys_for_symbols_9",
-        /* 85 */ "more_keys_for_symbols_0",
-        /* 86 */ "keylabel_for_comma",
-        /* 87 */ "more_keys_for_comma",
-        /* 88 */ "keylabel_for_symbols_exclamation",
-        /* 89 */ "keylabel_for_symbols_question",
-        /* 90 */ "keylabel_for_symbols_semicolon",
-        /* 91 */ "keylabel_for_symbols_percent",
-        /* 92 */ "more_keys_for_symbols_exclamation",
-        /* 93 */ "more_keys_for_symbols_question",
-        /* 94 */ "more_keys_for_symbols_semicolon",
-        /* 95 */ "more_keys_for_symbols_percent",
-        /* 96 */ "keylabel_for_tablet_comma",
-        /* 97 */ "keyhintlabel_for_tablet_comma",
-        /* 98 */ "more_keys_for_tablet_comma",
-        /* 99 */ "keyhintlabel_for_tablet_period",
-        /* 100 */ "more_keys_for_tablet_period",
-        /* 101 */ "keylabel_for_apostrophe",
-        /* 102 */ "keyhintlabel_for_apostrophe",
-        /* 103 */ "more_keys_for_apostrophe",
-        /* 104 */ "more_keys_for_am_pm",
-        /* 105 */ "settings_as_more_key",
-        /* 106 */ "shortcut_as_more_key",
-        /* 107 */ "action_next_as_more_key",
-        /* 108 */ "action_previous_as_more_key",
-        /* 109 */ "label_to_more_symbol_key",
-        /* 110 */ "label_to_more_symbol_for_tablet_key",
-        /* 111 */ "label_tab_key",
-        /* 112 */ "label_to_phone_numeric_key",
-        /* 113 */ "label_to_phone_symbols_key",
-        /* 114 */ "label_time_am",
-        /* 115 */ "label_time_pm",
-        /* 116 */ "label_to_symbol_key_pcqwerty",
-        /* 117 */ "keylabel_for_popular_domain",
-        /* 118 */ "more_keys_for_popular_domain",
-        /* 119 */ "more_keys_for_smiley",
-        /* 120 */ "more_keys_for_arabic_diacritics",
+        /* 56 */ "more_keys_for_arabic_diacritics",
+        /* 57 */ "keyhintlabel_for_arabic_diacritics",
+        /* 58 */ "keylabel_for_symbols_1",
+        /* 59 */ "keylabel_for_symbols_2",
+        /* 60 */ "keylabel_for_symbols_3",
+        /* 61 */ "keylabel_for_symbols_4",
+        /* 62 */ "keylabel_for_symbols_5",
+        /* 63 */ "keylabel_for_symbols_6",
+        /* 64 */ "keylabel_for_symbols_7",
+        /* 65 */ "keylabel_for_symbols_8",
+        /* 66 */ "keylabel_for_symbols_9",
+        /* 67 */ "keylabel_for_symbols_0",
+        /* 68 */ "additional_more_keys_for_symbols_1",
+        /* 69 */ "additional_more_keys_for_symbols_2",
+        /* 70 */ "additional_more_keys_for_symbols_3",
+        /* 71 */ "additional_more_keys_for_symbols_4",
+        /* 72 */ "additional_more_keys_for_symbols_5",
+        /* 73 */ "additional_more_keys_for_symbols_6",
+        /* 74 */ "additional_more_keys_for_symbols_7",
+        /* 75 */ "additional_more_keys_for_symbols_8",
+        /* 76 */ "additional_more_keys_for_symbols_9",
+        /* 77 */ "additional_more_keys_for_symbols_0",
+        /* 78 */ "more_keys_for_symbols_1",
+        /* 79 */ "more_keys_for_symbols_2",
+        /* 80 */ "more_keys_for_symbols_3",
+        /* 81 */ "more_keys_for_symbols_4",
+        /* 82 */ "more_keys_for_symbols_5",
+        /* 83 */ "more_keys_for_symbols_6",
+        /* 84 */ "more_keys_for_symbols_7",
+        /* 85 */ "more_keys_for_symbols_8",
+        /* 86 */ "more_keys_for_symbols_9",
+        /* 87 */ "more_keys_for_symbols_0",
+        /* 88 */ "keylabel_for_comma",
+        /* 89 */ "more_keys_for_comma",
+        /* 90 */ "keylabel_for_symbols_exclamation",
+        /* 91 */ "keylabel_for_symbols_question",
+        /* 92 */ "keylabel_for_symbols_semicolon",
+        /* 93 */ "keylabel_for_symbols_percent",
+        /* 94 */ "more_keys_for_symbols_exclamation",
+        /* 95 */ "more_keys_for_symbols_question",
+        /* 96 */ "more_keys_for_symbols_semicolon",
+        /* 97 */ "more_keys_for_symbols_percent",
+        /* 98 */ "keylabel_for_tablet_comma",
+        /* 99 */ "keyhintlabel_for_tablet_comma",
+        /* 100 */ "more_keys_for_tablet_comma",
+        /* 101 */ "keyhintlabel_for_tablet_period",
+        /* 102 */ "more_keys_for_tablet_period",
+        /* 103 */ "keylabel_for_apostrophe",
+        /* 104 */ "keyhintlabel_for_apostrophe",
+        /* 105 */ "more_keys_for_apostrophe",
+        /* 106 */ "more_keys_for_am_pm",
+        /* 107 */ "settings_as_more_key",
+        /* 108 */ "shortcut_as_more_key",
+        /* 109 */ "action_next_as_more_key",
+        /* 110 */ "action_previous_as_more_key",
+        /* 111 */ "label_to_more_symbol_key",
+        /* 112 */ "label_to_more_symbol_for_tablet_key",
+        /* 113 */ "label_tab_key",
+        /* 114 */ "label_to_phone_numeric_key",
+        /* 115 */ "label_to_phone_symbols_key",
+        /* 116 */ "label_time_am",
+        /* 117 */ "label_time_pm",
+        /* 118 */ "label_to_symbol_key_pcqwerty",
+        /* 119 */ "keylabel_for_popular_domain",
+        /* 120 */ "more_keys_for_popular_domain",
+        /* 121 */ "more_keys_for_smiley",
     };
 
     private static final String EMPTY = "";
@@ -288,108 +289,94 @@
         // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
         /* 54 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB",
         /* 55 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB",
-        /* 56 */ "1",
-        /* 57 */ "2",
-        /* 58 */ "3",
-        /* 59 */ "4",
-        /* 60 */ "5",
-        /* 61 */ "6",
-        /* 62 */ "7",
-        /* 63 */ "8",
-        /* 64 */ "9",
-        /* 65 */ "0",
-        /* 66~ */
+        /* 56 */ EMPTY,
+        /* 57 */ EMPTY,
+        /* 58 */ "1",
+        /* 59 */ "2",
+        /* 60 */ "3",
+        /* 61 */ "4",
+        /* 62 */ "5",
+        /* 63 */ "6",
+        /* 64 */ "7",
+        /* 65 */ "8",
+        /* 66 */ "9",
+        /* 67 */ "0",
+        /* 68~ */
         EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
-        /* ~75 */
+        /* ~77 */
         // U+00B9: "¹" SUPERSCRIPT ONE
         // U+00BD: "½" VULGAR FRACTION ONE HALF
         // U+2153: "⅓" VULGAR FRACTION ONE THIRD
         // U+00BC: "¼" VULGAR FRACTION ONE QUARTER
         // U+215B: "⅛" VULGAR FRACTION ONE EIGHTH
-        /* 76 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
+        /* 78 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
         // U+00B2: "²" SUPERSCRIPT TWO
         // U+2154: "⅔" VULGAR FRACTION TWO THIRDS
-        /* 77 */ "\u00B2,\u2154",
+        /* 79 */ "\u00B2,\u2154",
         // U+00B3: "³" SUPERSCRIPT THREE
         // U+00BE: "¾" VULGAR FRACTION THREE QUARTERS
         // U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS
-        /* 78 */ "\u00B3,\u00BE,\u215C",
+        /* 80 */ "\u00B3,\u00BE,\u215C",
         // U+2074: "⁴" SUPERSCRIPT FOUR
-        /* 79 */ "\u2074",
+        /* 81 */ "\u2074",
         // U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS
-        /* 80 */ "\u215D",
-        /* 81 */ EMPTY,
-        // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
-        /* 82 */ "\u215E",
+        /* 82 */ "\u215D",
         /* 83 */ EMPTY,
-        /* 84 */ EMPTY,
+        // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
+        /* 84 */ "\u215E",
+        /* 85 */ EMPTY,
+        /* 86 */ EMPTY,
         // U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
         // U+2205: "∅" EMPTY SET
-        /* 85 */ "\u207F,\u2205",
-        /* 86 */ ",",
-        /* 87 */ EMPTY,
-        /* 88 */ "!",
-        /* 89 */ "?",
-        /* 90 */ ";",
-        /* 91 */ "%",
+        /* 87 */ "\u207F,\u2205",
+        /* 88 */ ",",
+        /* 89 */ EMPTY,
+        /* 90 */ "!",
+        /* 91 */ "?",
+        /* 92 */ ";",
+        /* 93 */ "%",
         // U+00A1: "¡" INVERTED EXCLAMATION MARK
-        /* 92 */ "\u00A1",
+        /* 94 */ "\u00A1",
         // U+00BF: "¿" INVERTED QUESTION MARK
-        /* 93 */ "\u00BF",
-        /* 94 */ EMPTY,
+        /* 95 */ "\u00BF",
+        /* 96 */ EMPTY,
         // U+2030: "‰" PER MILLE SIGN
-        /* 95 */ "\u2030",
-        /* 96 */ ",",
-        /* 97 */ "!",
-        /* 98 */ "!",
-        /* 99 */ "?",
-        /* 100 */ "?",
-        /* 101 */ "\'",
-        /* 102 */ "\"",
-        /* 103 */ "\"",
-        /* 104 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm",
-        /* 105 */ "!icon/settings_key|!code/key_settings",
-        /* 106 */ "!icon/shortcut_key|!code/key_shortcut",
-        /* 107 */ "!hasLabels!,!text/label_next_key|!code/key_action_next",
-        /* 108 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous",
+        /* 97 */ "\u2030",
+        /* 98 */ ",",
+        /* 99 */ "!",
+        /* 100 */ "!",
+        /* 101 */ "?",
+        /* 102 */ "?",
+        /* 103 */ "\'",
+        /* 104 */ "\"",
+        /* 105 */ "\"",
+        /* 106 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm",
+        /* 107 */ "!icon/settings_key|!code/key_settings",
+        /* 108 */ "!icon/shortcut_key|!code/key_shortcut",
+        /* 109 */ "!hasLabels!,!text/label_next_key|!code/key_action_next",
+        /* 110 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous",
         // Label for "switch to more symbol" modifier key.  Must be short to fit on key!
-        /* 109 */ "= \\ <",
+        /* 111 */ "= \\ <",
         // Label for "switch to more symbol" modifier key on tablets.  Must be short to fit on key!
-        /* 110 */ "~ \\ {",
+        /* 112 */ "~ \\ {",
         // Label for "Tab" key.  Must be short to fit on key!
-        /* 111 */ "Tab",
+        /* 113 */ "Tab",
         // Label for "switch to phone numeric" key.  Must be short to fit on key!
-        /* 112 */ "123",
+        /* 114 */ "123",
         // Label for "switch to phone symbols" key.  Must be short to fit on key!
         // U+FF0A: "*" FULLWIDTH ASTERISK
         // U+FF03: "#" FULLWIDTH NUMBER SIGN
-        /* 113 */ "\uFF0A\uFF03",
+        /* 115 */ "\uFF0A\uFF03",
         // Key label for "ante meridiem"
-        /* 114 */ "AM",
+        /* 116 */ "AM",
         // Key label for "post meridiem"
-        /* 115 */ "PM",
+        /* 117 */ "PM",
         // Label for "switch to symbols" key on PC QWERTY layout
-        /* 116 */ "Sym",
-        /* 117 */ ".com",
+        /* 118 */ "Sym",
+        /* 119 */ ".com",
         // popular web domains for the locale - most popular, displayed on the keyboard
-        /* 118 */ "!hasLabels!,.net,.org,.gov,.edu",
-        /* 119 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ",
-        // U+064F: "ُ" ARABIC DAMMA
-        // U+064C: "ٌ" ARABIC DAMMATAN
-        // U+0651: "ّ" ARABIC SHADDA
-        // U+0652: "ْ" ARABIC SUKUN
-        // U+0653: "ٓ" ARABIC MADDAH ABOVE
-        // U+064D: "ٍ" ARABIC KASRATAN
-        // U+064B: "ً" ARABIC FATHATAN
-        // U+0650: "ِ" ARABIC KASRA
-        // U+064E: "َ" ARABIC FATHA
-        // U+0640: "ـ" ARABIC TATWEEL
-        // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
-        // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
-        // U+0655: "ٕ" ARABIC HAMZA BELOW
-        // U+0654: "ٔ" ARABIC HAMZA ABOVE
-        // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
-        /* 120 */ "!fixedColumnOrder!5,\u064F,\u064C,\u0651,\u0652,\u0653,\u064D,\u064B,\u0650,\u064E,\u0640\u0640\u0640|\u0640,\u0656,\u0670,\u0655,\u0654",
+        /* 120 */ "!hasLabels!,.net,.org,.gov,.edu",
+        /* 121 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ",
     };
 
     /* Language ar: Arabic */
@@ -441,63 +428,80 @@
         // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
         /* 54 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
         /* 55 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+        // U+0655: "ٕ" ARABIC HAMZA BELOW
+        // U+0654: "ٔ" ARABIC HAMZA ABOVE
+        // U+0652: "ْ" ARABIC SUKUN
+        // U+064D: "ٍ" ARABIC KASRATAN
+        // U+064C: "ٌ" ARABIC DAMMATAN
+        // U+064B: "ً" ARABIC FATHATAN
+        // U+0651: "ّ" ARABIC SHADDA
+        // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
+        // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
+        // U+0653: "ٓ" ARABIC MADDAH ABOVE
+        // U+0650: "ِ" ARABIC KASRA
+        // U+064F: "ُ" ARABIC DAMMA
+        // U+064E: "َ" ARABIC FATHA
+        // U+0640: "ـ" ARABIC TATWEEL
+        // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
+        /* 56 */ "!fixedColumnOrder!7,\u0655,\u0654,\u0652,\u064D,\u064C,\u064B,\u0651,\u0656,\u0670,\u0653,\u0650,\u064F,\u064E,\u0640\u0640\u0640|\u0640",
+        /* 57 */ "\u0651",
         // U+0661: "١" ARABIC-INDIC DIGIT ONE
-        /* 56 */ "\u0661",
+        /* 58 */ "\u0661",
         // U+0662: "٢" ARABIC-INDIC DIGIT TWO
-        /* 57 */ "\u0662",
+        /* 59 */ "\u0662",
         // U+0663: "٣" ARABIC-INDIC DIGIT THREE
-        /* 58 */ "\u0663",
+        /* 60 */ "\u0663",
         // U+0664: "٤" ARABIC-INDIC DIGIT FOUR
-        /* 59 */ "\u0664",
+        /* 61 */ "\u0664",
         // U+0665: "٥" ARABIC-INDIC DIGIT FIVE
-        /* 60 */ "\u0665",
+        /* 62 */ "\u0665",
         // U+0666: "٦" ARABIC-INDIC DIGIT SIX
-        /* 61 */ "\u0666",
+        /* 63 */ "\u0666",
         // U+0667: "٧" ARABIC-INDIC DIGIT SEVEN
-        /* 62 */ "\u0667",
+        /* 64 */ "\u0667",
         // U+0668: "٨" ARABIC-INDIC DIGIT EIGHT
-        /* 63 */ "\u0668",
+        /* 65 */ "\u0668",
         // U+0669: "٩" ARABIC-INDIC DIGIT NINE
-        /* 64 */ "\u0669",
+        /* 66 */ "\u0669",
         // U+0660: "٠" ARABIC-INDIC DIGIT ZERO
-        /* 65 */ "\u0660",
-        /* 66 */ "1",
-        /* 67 */ "2",
-        /* 68 */ "3",
-        /* 69 */ "4",
-        /* 70 */ "5",
-        /* 71 */ "6",
-        /* 72 */ "7",
-        /* 73 */ "8",
-        /* 74 */ "9",
+        /* 67 */ "\u0660",
+        /* 68 */ "1",
+        /* 69 */ "2",
+        /* 70 */ "3",
+        /* 71 */ "4",
+        /* 72 */ "5",
+        /* 73 */ "6",
+        /* 74 */ "7",
+        /* 75 */ "8",
+        /* 76 */ "9",
         // U+066B: "٫" ARABIC DECIMAL SEPARATOR
         // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
-        /* 75 */ "0,\u066B,\u066C",
-        /* 76~ */
+        /* 77 */ "0,\u066B,\u066C",
+        /* 78~ */
         null, null, null, null, null, null, null, null, null, null,
-        /* ~85 */
+        /* ~87 */
         // U+060C: "،" ARABIC COMMA
-        /* 86 */ "\u060C",
-        /* 87 */ "\\,",
-        /* 88 */ null,
-        /* 89 */ "\u061F",
-        /* 90 */ "\u061B",
+        /* 88 */ "\u060C",
+        /* 89 */ "\\,",
+        /* 90 */ null,
+        /* 91 */ "\u061F",
+        /* 92 */ "\u061B",
         // U+066A: "٪" ARABIC PERCENT SIGN
-        /* 91 */ "\u066A",
-        /* 92 */ null,
-        /* 93 */ "?",
-        /* 94 */ ";",
+        /* 93 */ "\u066A",
+        /* 94 */ null,
+        /* 95 */ "?",
+        /* 96 */ ";",
         // U+2030: "‰" PER MILLE SIGN
-        /* 95 */ "\\%,\u2030",
-        /* 96~ */
+        /* 97 */ "\\%,\u2030",
+        /* 98~ */
         null, null, null, null, null,
-        /* ~100 */
+        /* ~102 */
         // U+060C: "،" ARABIC COMMA
         // U+061B: "؛" ARABIC SEMICOLON
         // U+061F: "؟" ARABIC QUESTION MARK
-        /* 101 */ "\u060C",
-        /* 102 */ "\u061F",
-        /* 103 */ "\u061F,\u061B,!,:,-,/,\',\"",
+        /* 103 */ "\u060C",
+        /* 104 */ "\u061F",
+        /* 105 */ "\u061F,\u061B,!,:,-,/,\',\"",
     };
 
     /* Language be: Belarusian */
@@ -861,23 +865,23 @@
         /* 49~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null, null,
-        /* ~87 */
+        null, null, null, null, null, null, null, null, null, null, null,
+        /* ~89 */
         // U+00A1: "¡" INVERTED EXCLAMATION MARK
-        /* 88 */ "\u00A1",
+        /* 90 */ "\u00A1",
         // U+00BF: "¿" INVERTED QUESTION MARK
-        /* 89 */ "\u00BF",
-        /* 90 */ null,
-        /* 91 */ null,
-        /* 92 */ "!",
-        /* 93 */ "?",
-        /* 94~ */
+        /* 91 */ "\u00BF",
+        /* 92 */ null,
+        /* 93 */ null,
+        /* 94 */ "!",
+        /* 95 */ "?",
+        /* 96~ */
         null, null, null,
-        /* ~96 */
-        /* 97 */ "\u00A1",
-        /* 98 */ "\u00A1,!",
-        /* 99 */ "\u00BF",
-        /* 100 */ "\u00BF,?",
+        /* ~98 */
+        /* 99 */ "\u00A1",
+        /* 100 */ "\u00A1,!",
+        /* 101 */ "\u00BF",
+        /* 102 */ "\u00BF,?",
     };
 
     /* Language et: Estonian */
@@ -1029,65 +1033,82 @@
         // U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK
         /* 54 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
         /* 55 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+        // U+0655: "ٕ" ARABIC HAMZA BELOW
+        // U+0652: "ْ" ARABIC SUKUN
+        // U+0651: "ّ" ARABIC SHADDA
+        // U+064C: "ٌ" ARABIC DAMMATAN
+        // U+064D: "ٍ" ARABIC KASRATAN
+        // U+064B: "ً" ARABIC FATHATAN
+        // U+0654: "ٔ" ARABIC HAMZA ABOVE
+        // U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
+        // U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
+        // U+0653: "ٓ" ARABIC MADDAH ABOVE
+        // U+064F: "ُ" ARABIC DAMMA
+        // U+0650: "ِ" ARABIC KASRA
+        // U+064E: "َ" ARABIC FATHA
+        // U+0640: "ـ" ARABIC TATWEEL
+        // In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
+        /* 56 */ "!fixedColumnOrder!7,\u0655,\u0652,\u0651,\u064C,\u064D,\u064B,\u0654,\u0656,\u0670,\u0653,\u064F,\u0650,\u064E,\u0640\u0640\u0640|\u0640",
+        /* 57 */ "\u0653",
         // U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE
-        /* 56 */ "\u06F1",
+        /* 58 */ "\u06F1",
         // U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO
-        /* 57 */ "\u06F2",
+        /* 59 */ "\u06F2",
         // U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE
-        /* 58 */ "\u06F3",
+        /* 60 */ "\u06F3",
         // U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR
-        /* 59 */ "\u06F4",
+        /* 61 */ "\u06F4",
         // U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE
-        /* 60 */ "\u06F5",
+        /* 62 */ "\u06F5",
         // U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX
-        /* 61 */ "\u06F6",
+        /* 63 */ "\u06F6",
         // U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN
-        /* 62 */ "\u06F7",
+        /* 64 */ "\u06F7",
         // U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT
-        /* 63 */ "\u06F8",
+        /* 65 */ "\u06F8",
         // U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE
-        /* 64 */ "\u06F9",
+        /* 66 */ "\u06F9",
         // U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO
-        /* 65 */ "\u06F0",
-        /* 66 */ "1",
-        /* 67 */ "2",
-        /* 68 */ "3",
-        /* 69 */ "4",
-        /* 70 */ "5",
-        /* 71 */ "6",
-        /* 72 */ "7",
-        /* 73 */ "8",
-        /* 74 */ "9",
+        /* 67 */ "\u06F0",
+        /* 68 */ "1",
+        /* 69 */ "2",
+        /* 70 */ "3",
+        /* 71 */ "4",
+        /* 72 */ "5",
+        /* 73 */ "6",
+        /* 74 */ "7",
+        /* 75 */ "8",
+        /* 76 */ "9",
         // U+066B: "٫" ARABIC DECIMAL SEPARATOR
         // U+066C: "٬" ARABIC THOUSANDS SEPARATOR
-        /* 75 */ "0,\u066B,\u066C",
-        /* 76~ */
+        /* 77 */ "0,\u066B,\u066C",
+        /* 78~ */
         null, null, null, null, null, null, null, null, null, null,
-        /* ~85 */
+        /* ~87 */
         // U+060C: "،" ARABIC COMMA
-        /* 86 */ "\u060C",
-        /* 87 */ "\\,",
-        /* 88 */ null,
-        /* 89 */ "\u061F",
-        /* 90 */ "\u061B",
+        /* 88 */ "\u060C",
+        /* 89 */ "\\,",
+        /* 90 */ null,
+        /* 91 */ "\u061F",
+        /* 92 */ "\u061B",
         // U+066A: "٪" ARABIC PERCENT SIGN
-        /* 91 */ "\u066A",
-        /* 92 */ null,
-        /* 93 */ "?",
-        /* 94 */ ";",
+        /* 93 */ "\u066A",
+        /* 94 */ null,
+        /* 95 */ "?",
+        /* 96 */ ";",
         // U+2030: "‰" PER MILLE SIGN
-        /* 95 */ "\\%,\u2030",
+        /* 97 */ "\\%,\u2030",
         // U+060C: "،" ARABIC COMMA
         // U+061B: "؛" ARABIC SEMICOLON
         // U+061F: "؟" ARABIC QUESTION MARK
-        /* 96 */ "\u060C",
-        /* 97 */ "!",
-        /* 98 */ "!,\\,",
-        /* 99 */ "\u061F",
-        /* 100 */ "\u061F,?",
-        /* 101 */ null,
-        /* 102 */ null,
-        /* 103 */ "\u061F,\u061B,!,:,-,/,\',\"",
+        /* 98 */ "\u060C",
+        /* 99 */ "!",
+        /* 100 */ "!,\\,",
+        /* 101 */ "\u061F",
+        /* 102 */ "\u061F,?",
+        /* 103 */ null,
+        /* 104 */ null,
+        /* 105 */ "\u061F,\u061B,!,:,-,/,\',\"",
     };
 
     /* Language fi: Finnish */
@@ -1196,38 +1217,38 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null, null, null, null,
-        /* ~55 */
+        null, null, null, null, null, null, null, null, null, null, null, null, null,
+        /* ~57 */
         // U+0967: "१" DEVANAGARI DIGIT ONE
-        /* 56 */ "\u0967",
+        /* 58 */ "\u0967",
         // U+0968: "२" DEVANAGARI DIGIT TWO
-        /* 57 */ "\u0968",
+        /* 59 */ "\u0968",
         // U+0969: "३" DEVANAGARI DIGIT THREE
-        /* 58 */ "\u0969",
+        /* 60 */ "\u0969",
         // U+096A: "४" DEVANAGARI DIGIT FOUR
-        /* 59 */ "\u096A",
+        /* 61 */ "\u096A",
         // U+096B: "५" DEVANAGARI DIGIT FIVE
-        /* 60 */ "\u096B",
+        /* 62 */ "\u096B",
         // U+096C: "६" DEVANAGARI DIGIT SIX
-        /* 61 */ "\u096C",
+        /* 63 */ "\u096C",
         // U+096D: "७" DEVANAGARI DIGIT SEVEN
-        /* 62 */ "\u096D",
+        /* 64 */ "\u096D",
         // U+096E: "८" DEVANAGARI DIGIT EIGHT
-        /* 63 */ "\u096E",
+        /* 65 */ "\u096E",
         // U+096F: "९" DEVANAGARI DIGIT NINE
-        /* 64 */ "\u096F",
+        /* 66 */ "\u096F",
         // U+0966: "०" DEVANAGARI DIGIT ZERO
-        /* 65 */ "\u0966",
-        /* 66 */ "1",
-        /* 67 */ "2",
-        /* 68 */ "3",
-        /* 69 */ "4",
-        /* 70 */ "5",
-        /* 71 */ "6",
-        /* 72 */ "7",
-        /* 73 */ "8",
-        /* 74 */ "9",
-        /* 75 */ "0",
+        /* 67 */ "\u0966",
+        /* 68 */ "1",
+        /* 69 */ "2",
+        /* 70 */ "3",
+        /* 71 */ "4",
+        /* 72 */ "5",
+        /* 73 */ "6",
+        /* 74 */ "7",
+        /* 75 */ "8",
+        /* 76 */ "9",
+        /* 77 */ "0",
     };
 
     /* Language hr: Croatian */
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5236591..77a0ccf 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -872,7 +872,7 @@
         if (ProductionFlag.IS_EXPERIMENTAL) {
             ResearchLogger.latinIME_onDisplayCompletions(applicationSpecifiedCompletions);
         }
-        if (mInputAttributes.mApplicationSpecifiedCompletionOn) {
+        if (null != mInputAttributes && mInputAttributes.mApplicationSpecifiedCompletionOn) {
             mApplicationSpecifiedCompletions = applicationSpecifiedCompletions;
             if (applicationSpecifiedCompletions == null) {
                 clearSuggestions();
@@ -1627,8 +1627,8 @@
     }
 
     public boolean isSuggestionsRequested() {
-        // TODO: move this method to mSettingsValues
-        return mInputAttributes.mIsSettingsSuggestionStripOn
+        // TODO: move this method to mCurrentSettings
+        return (null != mInputAttributes && mInputAttributes.mIsSettingsSuggestionStripOn)
                 && (mCurrentSettings.isCorrectionOn() || isShowingSuggestionsStrip());
     }
 
@@ -1648,7 +1648,7 @@
             return true;
         if (!isShowingSuggestionsStrip())
             return false;
-        if (mInputAttributes.mApplicationSpecifiedCompletionOn)
+        if (null != mInputAttributes && mInputAttributes.mApplicationSpecifiedCompletionOn)
             return true;
         return isSuggestionsRequested();
     }
@@ -1804,14 +1804,7 @@
 
     @Override
     public void pickSuggestionManually(final int index, final CharSequence suggestion,
-            int x, int y) {
-        mConnection.beginBatchEdit(getCurrentInputConnection());
-        pickSuggestionManuallyWhileInBatchEdit(index, suggestion, x, y);
-        mConnection.endBatchEdit();
-    }
-
-    public void pickSuggestionManuallyWhileInBatchEdit(final int index,
-        final CharSequence suggestion, final int x, final int y) {
+            final int x, final int y) {
         final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions();
         // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput
         if (suggestion.length() == 1 && isShowingPunctuationList()) {
@@ -1837,7 +1830,7 @@
             }
         }
 
-        if (mInputAttributes.mApplicationSpecifiedCompletionOn
+        if ((null != mInputAttributes && mInputAttributes.mApplicationSpecifiedCompletionOn)
                 && mApplicationSpecifiedCompletions != null
                 && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
             if (mSuggestionsView != null) {
@@ -1846,7 +1839,9 @@
             mKeyboardSwitcher.updateShiftState();
             resetComposingState(true /* alsoResetLastComposedWord */);
             final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index];
+            mConnection.beginBatchEdit(getCurrentInputConnection());
             mConnection.commitCompletion(completionInfo);
+            mConnection.endBatchEdit();
             if (ProductionFlag.IS_EXPERIMENTAL) {
                 ResearchLogger.latinIME_pickApplicationSpecifiedCompletion(index,
                         completionInfo.getText(), x, y);
@@ -1958,12 +1953,16 @@
             // showSuggestions will retrieve the word near the cursor, we don't want that here)
             showSuggestions(suggestedWords, "");
         } else {
-            if (!isShowingPunctuationList()) setPunctuationSuggestions();
+            clearSuggestions();
         }
     }
 
     public void setPunctuationSuggestions() {
-        setSuggestions(mCurrentSettings.mSuggestPuncList, false);
+        if (mCurrentSettings.mBigramPredictionEnabled) {
+            clearSuggestions();
+        } else {
+            setSuggestions(mCurrentSettings.mSuggestPuncList, false);
+        }
         setAutoCorrectionIndicator(false);
         setSuggestionStripShown(isSuggestionsStripVisible());
     }
@@ -1986,10 +1985,11 @@
             } else {
                 secondWord = suggestion.toString();
             }
-            // We demote unrecognized word and words with 0-frequency (assuming they would be
-            // profanity etc.) by specifying them as "invalid".
+            // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid".
+            // We don't add words with 0-frequency (assuming they would be profanity etc.).
             final int maxFreq = AutoCorrection.getMaxFrequency(
                     mSuggest.getUnigramDictionaries(), suggestion);
+            if (maxFreq == 0) return null;
             mUserHistoryDictionary.addToUserHistory(null == prevWord ? null : prevWord.toString(),
                     secondWord, maxFreq > 0);
             return prevWord;
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 227990a..0c19bed 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -65,66 +65,70 @@
         if (--mNestLevel == 0 && null != mIC) mIC.endBatchEdit();
     }
 
+    private void checkBatchEdit() {
+        if (mNestLevel != 1) {
+            // TODO: exception instead
+            Log.e(TAG, "Batch edit level incorrect : " + mNestLevel);
+            Log.e(TAG, Utils.getStackTrace(4));
+        }
+    }
+
     public void finishComposingText() {
-        if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
+        checkBatchEdit();
         if (null != mIC) mIC.finishComposingText();
     }
 
     public void commitText(final CharSequence text, final int i) {
-        if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
+        checkBatchEdit();
         if (null != mIC) mIC.commitText(text, i);
     }
 
     public int getCursorCapsMode(final int inputType) {
-        if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
         if (null == mIC) return Constants.TextUtils.CAP_MODE_OFF;
         return mIC.getCursorCapsMode(inputType);
     }
 
     public CharSequence getTextBeforeCursor(final int i, final int j) {
-        if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
         if (null != mIC) return mIC.getTextBeforeCursor(i, j);
         return null;
     }
 
     public CharSequence getTextAfterCursor(final int i, final int j) {
-        if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
         if (null != mIC) return mIC.getTextAfterCursor(i, j);
         return null;
     }
 
     public void deleteSurroundingText(final int i, final int j) {
-        if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
+        checkBatchEdit();
         if (null != mIC) mIC.deleteSurroundingText(i, j);
     }
 
     public void performEditorAction(final int actionId) {
-        if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
         if (null != mIC) mIC.performEditorAction(actionId);
     }
 
     public void sendKeyEvent(final KeyEvent keyEvent) {
-        if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
+        checkBatchEdit();
         if (null != mIC) mIC.sendKeyEvent(keyEvent);
     }
 
     public void setComposingText(final CharSequence text, final int i) {
-        if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
+        checkBatchEdit();
         if (null != mIC) mIC.setComposingText(text, i);
     }
 
     public void setSelection(final int from, final int to) {
-        if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
+        checkBatchEdit();
         if (null != mIC) mIC.setSelection(from, to);
     }
 
     public void commitCorrection(final CorrectionInfo correctionInfo) {
-        if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
+        checkBatchEdit();
         if (null != mIC) mIC.commitCorrection(correctionInfo);
     }
 
     public void commitCompletion(final CompletionInfo completionInfo) {
-        if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead
+        checkBatchEdit();
         if (null != mIC) mIC.commitCompletion(completionInfo);
     }
 
@@ -316,6 +320,7 @@
     }
 
     public void removeTrailingSpace() {
+        checkBatchEdit();
         final CharSequence lastOne = getTextBeforeCursor(1, 0);
         if (lastOne != null && lastOne.length() == 1
                 && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
@@ -372,6 +377,7 @@
     }
 
     public boolean revertDoubleSpace() {
+        checkBatchEdit();
         // Here we test whether we indeed have a period and a space before us. This should not
         // be needed, but it's there just in case something went wrong.
         final CharSequence textBeforeCursor = getTextBeforeCursor(2, 0);
@@ -395,6 +401,7 @@
     }
 
     public boolean revertSwapPunctuation() {
+        checkBatchEdit();
         // Here we test whether we indeed have a space and something else before us. This should not
         // be needed, but it's there just in case something went wrong.
         final CharSequence textBeforeCursor = getTextBeforeCursor(2, 0);
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index c9ff0a5..152d668 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -149,10 +149,13 @@
             generalSettings.removePreference(mVoicePreference);
         }
 
+        final PreferenceGroup advancedSettings =
+                (PreferenceGroup) findPreference(PREF_ADVANCED_SETTINGS);
+        // Remove those meaningless options for now. TODO: delete them for good
+        advancedSettings.removePreference(findPreference(PREF_BIGRAM_SUGGESTION));
+        advancedSettings.removePreference(findPreference(PREF_KEY_ENABLE_SPAN_INSERT));
         if (!VibratorUtils.getInstance(context).hasVibrator()) {
             generalSettings.removePreference(findPreference(PREF_VIBRATE_ON));
-            final PreferenceGroup advancedSettings =
-                    (PreferenceGroup) findPreference(PREF_ADVANCED_SETTINGS);
             if (null != advancedSettings) { // Theoretically advancedSettings cannot be null
                 advancedSettings.removePreference(findPreference(PREF_VIBRATION_DURATION_SETTINGS));
             }
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 6a79aa6..f8a0a4d 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -151,8 +151,8 @@
                 && isBigramSuggestionEnabled(prefs, res, mAutoCorrectEnabled);
         mBigramPredictionEnabled = mBigramSuggestionEnabled
                 && isBigramPredictionEnabled(prefs, res);
-        mEnableSuggestionSpanInsertion =
-                prefs.getBoolean(Settings.PREF_KEY_ENABLE_SPAN_INSERT, true);
+        // TODO: remove mEnableSuggestionSpanInsertion. It's always true.
+        mEnableSuggestionSpanInsertion = true;
         mVibrationDurationSettingsRawValue =
                 prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1);
         mKeypressSoundVolumeRawValue = prefs.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f);
@@ -288,13 +288,8 @@
 
     private static boolean isBigramSuggestionEnabled(final SharedPreferences sp,
             final Resources resources, final boolean autoCorrectEnabled) {
-        final boolean showBigramSuggestionsOption = resources.getBoolean(
-                R.bool.config_enable_next_word_suggestions_option);
-        if (!showBigramSuggestionsOption) {
-            return autoCorrectEnabled;
-        }
-        return sp.getBoolean(Settings.PREF_BIGRAM_SUGGESTION, resources.getBoolean(
-                R.bool.config_default_next_word_suggestions));
+        // TODO: remove this method. Bigram suggestion is always true.
+        return true;
     }
 
     private static boolean isBigramPredictionEnabled(final SharedPreferences sp,
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 903b5a3..f2d21ab 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -204,18 +204,24 @@
     }
 
     // Get the current stack trace
-    public static String getStackTrace() {
+    public static String getStackTrace(final int limit) {
         StringBuilder sb = new StringBuilder();
         try {
             throw new RuntimeException();
         } catch (RuntimeException e) {
             StackTraceElement[] frames = e.getStackTrace();
             // Start at 1 because the first frame is here and we don't care about it
-            for (int j = 1; j < frames.length; ++j) sb.append(frames[j].toString() + "\n");
+            for (int j = 1; j < frames.length && j < limit + 1; ++j) {
+                sb.append(frames[j].toString() + "\n");
+            }
         }
         return sb.toString();
     }
 
+    public static String getStackTrace() {
+        return getStackTrace(Integer.MAX_VALUE);
+    }
+
     public static class UsabilityStudyLogUtils {
         // TODO: remove code duplication with ResearchLog class
         private static final String USABILITY_TAG = UsabilityStudyLogUtils.class.getSimpleName();
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
index 8a29dcc..19287e3 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
@@ -167,7 +167,7 @@
 
     @Override
     public boolean dismissMoreKeysPanel() {
-        if (mIsDismissing) return false;
+        if (mIsDismissing || mController == null) return false;
         mIsDismissing = true;
         final boolean dismissed = mController.dismissMoreKeysPanel();
         mIsDismissing = false;
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java
index 3d593aa..e86390b 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java
@@ -670,7 +670,7 @@
     }
 
     public void setSuggestions(SuggestedWords suggestedWords) {
-        if (suggestedWords == null || suggestedWords.size() == 0)
+        if (suggestedWords == null)
             return;
 
         clear();
@@ -884,5 +884,6 @@
         super.onDetachedFromWindow();
         mHandler.cancelAllMessages();
         hidePreview();
+        dismissMoreSuggestions();
     }
 }
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index edcc067..3bb7b58 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -18,7 +18,7 @@
 # If you change any of those flags, you need to rebuild both libjni_latinime_static
 # and the shared library.
 #FLAG_DBG := true
-#FLAG_DO_PROFILE := true
+FLAG_DO_PROFILE ?= false
 
 ######################################
 include $(CLEAR_VARS)
diff --git a/native/jni/src/additional_proximity_chars.h b/native/jni/src/additional_proximity_chars.h
index e0ecc0e..82c31f8 100644
--- a/native/jni/src/additional_proximity_chars.h
+++ b/native/jni/src/additional_proximity_chars.h
@@ -26,6 +26,7 @@
 
 class AdditionalProximityChars {
  private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(AdditionalProximityChars);
     static const std::string LOCALE_EN_US;
     static const int EN_US_ADDITIONAL_A_SIZE = 4;
     static const int32_t EN_US_ADDITIONAL_A[];
diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp
index 9ef024d..1443369 100644
--- a/native/jni/src/bigram_dictionary.cpp
+++ b/native/jni/src/bigram_dictionary.cpp
@@ -27,9 +27,8 @@
 
 namespace latinime {
 
-BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength,
-        Dictionary *parentDictionary)
-    : DICT(dict), MAX_WORD_LENGTH(maxWordLength), mParentDictionary(parentDictionary) {
+BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength)
+        : DICT(dict), MAX_WORD_LENGTH(maxWordLength) {
     if (DEBUG_DICT) {
         AKLOGI("BigramDictionary - constructor");
     }
@@ -38,7 +37,8 @@
 BigramDictionary::~BigramDictionary() {
 }
 
-bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequency) {
+bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequency,
+        const int maxBigrams, int *bigramFreq, unsigned short *bigramChars) const {
     word[length] = 0;
     if (DEBUG_DICT) {
 #ifdef FLAG_DBG
@@ -50,25 +50,25 @@
 
     // Find the right insertion point
     int insertAt = 0;
-    while (insertAt < mMaxBigrams) {
-        if (frequency > mBigramFreq[insertAt] || (mBigramFreq[insertAt] == frequency
-                && length < Dictionary::wideStrLen(mBigramChars + insertAt * MAX_WORD_LENGTH))) {
+    while (insertAt < maxBigrams) {
+        if (frequency > bigramFreq[insertAt] || (bigramFreq[insertAt] == frequency
+                && length < Dictionary::wideStrLen(bigramChars + insertAt * MAX_WORD_LENGTH))) {
             break;
         }
         insertAt++;
     }
     if (DEBUG_DICT) {
-        AKLOGI("Bigram: InsertAt -> %d maxBigrams: %d", insertAt, mMaxBigrams);
+        AKLOGI("Bigram: InsertAt -> %d maxBigrams: %d", insertAt, maxBigrams);
     }
-    if (insertAt < mMaxBigrams) {
-        memmove((char*) mBigramFreq + (insertAt + 1) * sizeof(mBigramFreq[0]),
-               (char*) mBigramFreq + insertAt * sizeof(mBigramFreq[0]),
-               (mMaxBigrams - insertAt - 1) * sizeof(mBigramFreq[0]));
-        mBigramFreq[insertAt] = frequency;
-        memmove((char*) mBigramChars + (insertAt + 1) * MAX_WORD_LENGTH * sizeof(short),
-               (char*) mBigramChars + (insertAt    ) * MAX_WORD_LENGTH * sizeof(short),
-               (mMaxBigrams - insertAt - 1) * sizeof(short) * MAX_WORD_LENGTH);
-        unsigned short *dest = mBigramChars + (insertAt    ) * MAX_WORD_LENGTH;
+    if (insertAt < maxBigrams) {
+        memmove((char*) bigramFreq + (insertAt + 1) * sizeof(bigramFreq[0]),
+               (char*) bigramFreq + insertAt * sizeof(bigramFreq[0]),
+               (maxBigrams - insertAt - 1) * sizeof(bigramFreq[0]));
+        bigramFreq[insertAt] = frequency;
+        memmove((char*) bigramChars + (insertAt + 1) * MAX_WORD_LENGTH * sizeof(short),
+               (char*) bigramChars + (insertAt    ) * MAX_WORD_LENGTH * sizeof(short),
+               (maxBigrams - insertAt - 1) * sizeof(short) * MAX_WORD_LENGTH);
+        unsigned short *dest = bigramChars + (insertAt    ) * MAX_WORD_LENGTH;
         while (length--) {
             *dest++ = *word++;
         }
@@ -84,7 +84,7 @@
 /* Parameters :
  * prevWord: the word before, the one for which we need to look up bigrams.
  * prevWordLength: its length.
- * codes: what user typed, in the same format as for UnigramDictionary::getSuggestions.
+ * inputCodes: what user typed, in the same format as for UnigramDictionary::getSuggestions.
  * codesSize: the size of the codes array.
  * bigramChars: an array for output, at the same format as outwords for getSuggestions.
  * bigramFreq: an array to output frequencies.
@@ -98,15 +98,11 @@
  * and the bigrams are used to boost unigram result scores, it makes little sense to
  * reduce their scope to the ones that match the first letter.
  */
-int BigramDictionary::getBigrams(const int32_t *prevWord, int prevWordLength, int *codes,
+int BigramDictionary::getBigrams(const int32_t *prevWord, int prevWordLength, int *inputCodes,
         int codesSize, unsigned short *bigramChars, int *bigramFreq, int maxWordLength,
-        int maxBigrams) {
+        int maxBigrams) const {
     // TODO: remove unused arguments, and refrain from storing stuff in members of this class
     // TODO: have "in" arguments before "out" ones, and make out args explicit in the name
-    mBigramFreq = bigramFreq;
-    mBigramChars = bigramChars;
-    mInputCodes = codes;
-    mMaxBigrams = maxBigrams;
 
     const uint8_t* const root = DICT;
     int pos = getBigramListPositionForWord(prevWord, prevWordLength);
@@ -124,16 +120,17 @@
                 bigramBuffer, &unigramFreq);
 
         // codesSize == 0 means we are trying to find bigram predictions.
-        if (codesSize < 1 || checkFirstCharacter(bigramBuffer)) {
-            const int bigramFreq = UnigramDictionary::MASK_ATTRIBUTE_FREQUENCY & bigramFlags;
+        if (codesSize < 1 || checkFirstCharacter(bigramBuffer, inputCodes)) {
+            const int bigramFreqTemp = UnigramDictionary::MASK_ATTRIBUTE_FREQUENCY & bigramFlags;
             // Due to space constraints, the frequency for bigrams is approximate - the lower the
             // unigram frequency, the worse the precision. The theoritical maximum error in
             // resulting frequency is 8 - although in the practice it's never bigger than 3 or 4
             // in very bad cases. This means that sometimes, we'll see some bigrams interverted
             // here, but it can't get too bad.
             const int frequency =
-                    BinaryFormat::computeFrequencyForBigram(unigramFreq, bigramFreq);
-            if (addWordBigram(bigramBuffer, length, frequency)) {
+                    BinaryFormat::computeFrequencyForBigram(unigramFreq, bigramFreqTemp);
+            if (addWordBigram(
+                    bigramBuffer, length, frequency, maxBigrams, bigramFreq, bigramChars)) {
                 ++bigramCount;
             }
         }
@@ -144,7 +141,7 @@
 // Returns a pointer to the start of the bigram list.
 // If the word is not found or has no bigrams, this function returns 0.
 int BigramDictionary::getBigramListPositionForWord(const int32_t *prevWord,
-        const int prevWordLength) {
+        const int prevWordLength) const {
     if (0 >= prevWordLength) return 0;
     const uint8_t* const root = DICT;
     int pos = BinaryFormat::getTerminalPosition(root, prevWord, prevWordLength);
@@ -164,7 +161,7 @@
 }
 
 void BigramDictionary::fillBigramAddressToFrequencyMapAndFilter(const int32_t *prevWord,
-        const int prevWordLength, std::map<int, int> *map, uint8_t *filter) {
+        const int prevWordLength, std::map<int, int> *map, uint8_t *filter) const {
     memset(filter, 0, BIGRAM_FILTER_BYTE_SIZE);
     const uint8_t* const root = DICT;
     int pos = getBigramListPositionForWord(prevWord, prevWordLength);
@@ -181,11 +178,10 @@
     } while (0 != (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags));
 }
 
-bool BigramDictionary::checkFirstCharacter(unsigned short *word) {
+bool BigramDictionary::checkFirstCharacter(unsigned short *word, int *inputCodes) const {
     // Checks whether this word starts with same character or neighboring characters of
     // what user typed.
 
-    int *inputCodes = mInputCodes;
     int maxAlt = MAX_ALTERNATIVES;
     const unsigned short firstBaseChar = toBaseLowerCase(*word);
     while (maxAlt > 0) {
@@ -199,7 +195,7 @@
 }
 
 bool BigramDictionary::isValidBigram(const int32_t *word1, int length1, const int32_t *word2,
-        int length2) {
+        int length2) const {
     const uint8_t* const root = DICT;
     int pos = getBigramListPositionForWord(word1, length1);
     // getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams
diff --git a/native/jni/src/bigram_dictionary.h b/native/jni/src/bigram_dictionary.h
index b8763a5..1ff1b2e 100644
--- a/native/jni/src/bigram_dictionary.h
+++ b/native/jni/src/bigram_dictionary.h
@@ -27,34 +27,29 @@
 class Dictionary;
 class BigramDictionary {
  public:
-    BigramDictionary(const unsigned char *dict, int maxWordLength, Dictionary *parentDictionary);
-    int getBigrams(const int32_t *word, int length, int *codes, int codesSize,
-            unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams);
-    int getBigramListPositionForWord(const int32_t *prevWord, const int prevWordLength);
+    BigramDictionary(const unsigned char *dict, int maxWordLength);
+    int getBigrams(const int32_t *word, int length, int *inputCodes, int codesSize,
+            unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams) const;
+    int getBigramListPositionForWord(const int32_t *prevWord, const int prevWordLength) const;
     void fillBigramAddressToFrequencyMapAndFilter(const int32_t *prevWord, const int prevWordLength,
-            std::map<int, int> *map, uint8_t *filter);
-    bool isValidBigram(const int32_t *word1, int length1, const int32_t *word2, int length2);
+            std::map<int, int> *map, uint8_t *filter) const;
+    bool isValidBigram(const int32_t *word1, int length1, const int32_t *word2, int length2) const;
     ~BigramDictionary();
  private:
-    bool addWordBigram(unsigned short *word, int length, int frequency);
+    DISALLOW_IMPLICIT_CONSTRUCTORS(BigramDictionary);
+    bool addWordBigram(unsigned short *word, int length, int frequency, const int maxBigrams,
+            int *bigramFreq, unsigned short *bigramChars) const;
     int getBigramAddress(int *pos, bool advance);
     int getBigramFreq(int *pos);
     void searchForTerminalNode(int addressLookingFor, int frequency);
     bool getFirstBitOfByte(int *pos) { return (DICT[*pos] & 0x80) > 0; }
     bool getSecondBitOfByte(int *pos) { return (DICT[*pos] & 0x40) > 0; }
-    bool checkFirstCharacter(unsigned short *word);
+    bool checkFirstCharacter(unsigned short *word, int *inputCodes) const;
 
     const unsigned char *DICT;
     const int MAX_WORD_LENGTH;
     // TODO: Re-implement proximity correction for bigram correction
     static const int MAX_ALTERNATIVES = 1;
-
-    Dictionary *mParentDictionary;
-    int *mBigramFreq;
-    int mMaxBigrams;
-    unsigned short *mBigramChars;
-    int *mInputCodes;
-    int mInputLength;
 };
 
 } // namespace latinime
diff --git a/native/jni/src/binary_format.h b/native/jni/src/binary_format.h
index 51bf8eb..214ecfa 100644
--- a/native/jni/src/binary_format.h
+++ b/native/jni/src/binary_format.h
@@ -25,6 +25,7 @@
 
 class BinaryFormat {
  private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryFormat);
     const static int32_t MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20;
     const static int32_t CHARACTER_ARRAY_TERMINATOR = 0x1F;
     const static int MULTIPLE_BYTE_CHARACTER_ADDITIONAL_SIZE = 2;
diff --git a/native/jni/src/correction.cpp b/native/jni/src/correction.cpp
index 3957b01..827067b 100644
--- a/native/jni/src/correction.cpp
+++ b/native/jni/src/correction.cpp
@@ -106,11 +106,6 @@
 // Correction //
 ////////////////
 
-Correction::Correction(const int typedLetterMultiplier, const int fullWordMultiplier)
-        : TYPED_LETTER_MULTIPLIER(typedLetterMultiplier), FULL_WORD_MULTIPLIER(fullWordMultiplier) {
-    initEditDistance(mEditDistanceTable);
-}
-
 void Correction::resetCorrection() {
     mTotalTraverseCount = 0;
 }
@@ -908,7 +903,7 @@
 
     if (DEBUG_CORRECTION_FREQ
             && (INPUTLENGTH_FOR_DEBUG <= 0 || INPUTLENGTH_FOR_DEBUG == inputLength)) {
-        DUMP_WORD(proximityInfo->getPrimaryInputWord(), inputLength);
+        DUMP_WORD(correction->getPrimaryInputWord(), inputLength);
         DUMP_WORD(correction->mWord, outputLength);
         AKLOGI("FinalFreq: [P%d, S%d, T%d, E%d, A%d] %d, %d, %d, %d, %d, %d", proximityMatchedCount,
                 skippedCount, transposedCount, excessiveCount, additionalProximityCount,
diff --git a/native/jni/src/correction.h b/native/jni/src/correction.h
index 60d7dc3..ae7b3a5 100644
--- a/native/jni/src/correction.h
+++ b/native/jni/src/correction.h
@@ -94,7 +94,7 @@
         }
     }
 
-    Correction(const int typedLetterMultiplier, const int fullWordMultiplier);
+    Correction() {};
     void resetCorrection();
     void initCorrection(
             const ProximityInfo *pi, const int inputLength, const int maxWordLength);
@@ -175,8 +175,6 @@
      private:
         static const int CODE_SPACE = ' ';
         static const int MAX_INITIAL_SCORE = 255;
-        static const int TYPED_LETTER_MULTIPLIER = 2;
-        static const int FULL_WORD_MULTIPLIER = 2;
     };
 
     // proximity info state
@@ -195,6 +193,7 @@
     }
 
  private:
+    DISALLOW_COPY_AND_ASSIGN(Correction);
     inline void incrementInputIndex();
     inline void incrementOutputIndex();
     inline void startToTraverseAllNodes();
@@ -206,8 +205,8 @@
     inline int getFinalProbabilityInternal(const int probability, unsigned short **word,
             int* wordLength, const int inputLength);
 
-    const int TYPED_LETTER_MULTIPLIER;
-    const int FULL_WORD_MULTIPLIER;
+    static const int TYPED_LETTER_MULTIPLIER = 2;
+    static const int FULL_WORD_MULTIPLIER = 2;
     const ProximityInfo *mProximityInfo;
 
     bool mUseFullEditDistance;
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index e4c6753..8bcadcb 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -292,6 +292,14 @@
 #define INPUTLENGTH_FOR_DEBUG -1
 #define MIN_OUTPUT_INDEX_FOR_DEBUG -1
 
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+  TypeName(const TypeName&);               \
+  void operator=(const TypeName&)
+
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName();                                    \
+  DISALLOW_COPY_AND_ASSIGN(TypeName)
+
 // Used as a return value for character comparison
 typedef enum {
     // Same char, possibly with different case or accent
diff --git a/native/jni/src/dictionary.cpp b/native/jni/src/dictionary.cpp
index 1fb0247..83bb267 100644
--- a/native/jni/src/dictionary.cpp
+++ b/native/jni/src/dictionary.cpp
@@ -38,29 +38,24 @@
             AKLOGI("IN NATIVE SUGGEST Version: %d", (mDict[0] & 0xFF));
         }
     }
-    mCorrection = new Correction(typedLetterMultiplier, fullWordMultiplier);
-    mWordsPriorityQueuePool = new WordsPriorityQueuePool(
-            maxWords, SUB_QUEUE_MAX_WORDS, maxWordLength);
     const unsigned int headerSize = BinaryFormat::getHeaderSize(mDict);
     const unsigned int options = BinaryFormat::getFlags(mDict);
     mUnigramDictionary = new UnigramDictionary(mDict + headerSize, typedLetterMultiplier,
             fullWordMultiplier, maxWordLength, maxWords, options);
-    mBigramDictionary = new BigramDictionary(mDict + headerSize, maxWordLength, this);
+    mBigramDictionary = new BigramDictionary(mDict + headerSize, maxWordLength);
 }
 
 Dictionary::~Dictionary() {
-    delete mCorrection;
-    delete mWordsPriorityQueuePool;
     delete mUnigramDictionary;
     delete mBigramDictionary;
 }
 
-int Dictionary::getFrequency(const int32_t *word, int length) {
+int Dictionary::getFrequency(const int32_t *word, int length) const {
     return mUnigramDictionary->getFrequency(word, length);
 }
 
 bool Dictionary::isValidBigram(const int32_t *word1, int length1, const int32_t *word2,
-        int length2) {
+        int length2) const {
     return mBigramDictionary->isValidBigram(word1, length1, word2, length2);
 }
 
diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h
index 9f23679..fd69f79 100644
--- a/native/jni/src/dictionary.h
+++ b/native/jni/src/dictionary.h
@@ -21,7 +21,6 @@
 
 #include "bigram_dictionary.h"
 #include "char_utils.h"
-#include "correction.h"
 #include "defines.h"
 #include "proximity_info.h"
 #include "unigram_dictionary.h"
@@ -36,28 +35,28 @@
 
     int getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates,
             int *codes, int codesSize, const int32_t* prevWordChars, const int prevWordLength,
-            bool useFullEditDistance, unsigned short *outWords, int *frequencies) {
+            bool useFullEditDistance, unsigned short *outWords, int *frequencies) const {
         std::map<int, int> bigramMap;
         uint8_t bigramFilter[BIGRAM_FILTER_BYTE_SIZE];
         mBigramDictionary->fillBigramAddressToFrequencyMapAndFilter(prevWordChars,
                 prevWordLength, &bigramMap, bigramFilter);
-        return mUnigramDictionary->getSuggestions(proximityInfo, mWordsPriorityQueuePool,
-                mCorrection, xcoordinates, ycoordinates, codes, codesSize, &bigramMap,
+        return mUnigramDictionary->getSuggestions(proximityInfo,
+                xcoordinates, ycoordinates, codes, codesSize, &bigramMap,
                 bigramFilter, useFullEditDistance, outWords, frequencies);
     }
 
     int getBigrams(const int32_t *word, int length, int *codes, int codesSize,
-            unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams) {
+            unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams) const {
         return mBigramDictionary->getBigrams(word, length, codes, codesSize, outWords, frequencies,
                 maxWordLength, maxBigrams);
     }
 
-    int getFrequency(const int32_t *word, int length);
-    bool isValidBigram(const int32_t *word1, int length1, const int32_t *word2, int length2);
-    void *getDict() { return (void *)mDict; }
-    int getDictSize() { return mDictSize; }
-    int getMmapFd() { return mMmapFd; }
-    int getDictBufAdjust() { return mDictBufAdjust; }
+    int getFrequency(const int32_t *word, int length) const;
+    bool isValidBigram(const int32_t *word1, int length1, const int32_t *word2, int length2) const;
+    void *getDict() const { return (void *)mDict; }
+    int getDictSize() const { return mDictSize; }
+    int getMmapFd() const { return mMmapFd; }
+    int getDictBufAdjust() const { return mDictBufAdjust; }
     ~Dictionary();
 
     // public static utility methods
@@ -65,6 +64,7 @@
     static int wideStrLen(unsigned short *str);
 
  private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(Dictionary);
     const unsigned char *mDict;
 
     // Used only for the mmap version of dictionary loading, but we use these as dummy variables
@@ -73,10 +73,8 @@
     const int mMmapFd;
     const int mDictBufAdjust;
 
-    UnigramDictionary *mUnigramDictionary;
-    BigramDictionary *mBigramDictionary;
-    WordsPriorityQueuePool *mWordsPriorityQueuePool;
-    Correction *mCorrection;
+    const UnigramDictionary *mUnigramDictionary;
+    const BigramDictionary *mBigramDictionary;
 };
 
 // public static utility methods
diff --git a/native/jni/src/proximity_info.cpp b/native/jni/src/proximity_info.cpp
index d1aa664..2ba244a 100644
--- a/native/jni/src/proximity_info.cpp
+++ b/native/jni/src/proximity_info.cpp
@@ -53,10 +53,10 @@
                   && keyWidths && keyHeights && keyCharCodes && sweetSpotCenterXs
                   && sweetSpotCenterYs && sweetSpotRadii),
           mLocaleStr(localeStr) {
+    const int proximityGridLength = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE;
     if (DEBUG_PROXIMITY_INFO) {
         AKLOGI("Create proximity info array %d", proximityGridLength);
     }
-    const int proximityGridLength = GRID_WIDTH * GRID_HEIGHT * MAX_PROXIMITY_CHARS_SIZE;
     mProximityCharsArray = new int32_t[proximityGridLength];
     memcpy(mProximityCharsArray, proximityCharsArray,
             proximityGridLength * sizeof(mProximityCharsArray[0]));
diff --git a/native/jni/src/proximity_info.h b/native/jni/src/proximity_info.h
index 67f2f60..fec6555 100644
--- a/native/jni/src/proximity_info.h
+++ b/native/jni/src/proximity_info.h
@@ -99,6 +99,7 @@
     }
 
  private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfo);
     // The max number of the keys in one keyboard layout
     static const int MAX_KEY_COUNT_IN_A_KEYBOARD = 64;
     // The upper limit of the char code in mCodeToKeyIndex
diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h
index 3a98d9b..717871c 100644
--- a/native/jni/src/proximity_info_state.h
+++ b/native/jni/src/proximity_info_state.h
@@ -49,6 +49,7 @@
     /////////////////////////////////////////
     // Defined here                        //
     /////////////////////////////////////////
+    ProximityInfoState() {};
     inline const int* getProximityCharsAt(const int index) const {
         return mInputCodes + (index * MAX_PROXIMITY_CHARS_SIZE_INTERNAL);
     }
@@ -162,6 +163,7 @@
     }
 
  private:
+    DISALLOW_COPY_AND_ASSIGN(ProximityInfoState);
     /////////////////////////////////////////
     // Defined in proximity_info_state.cpp //
     /////////////////////////////////////////
diff --git a/native/jni/src/terminal_attributes.h b/native/jni/src/terminal_attributes.h
index 9a803cc..c712f50 100644
--- a/native/jni/src/terminal_attributes.h
+++ b/native/jni/src/terminal_attributes.h
@@ -62,6 +62,7 @@
     };
 
  private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(TerminalAttributes);
     const uint8_t* const mDict;
     const uint8_t mFlags;
     const int mStartPos;
diff --git a/native/jni/src/unigram_dictionary.cpp b/native/jni/src/unigram_dictionary.cpp
index 27196f4..3417d2b 100644
--- a/native/jni/src/unigram_dictionary.cpp
+++ b/native/jni/src/unigram_dictionary.cpp
@@ -170,14 +170,15 @@
 // bigramFilter is a bloom filter for fast rejection: see functions setInFilter and isInFilter
 // in bigram_dictionary.cpp
 int UnigramDictionary::getSuggestions(ProximityInfo *proximityInfo,
-        WordsPriorityQueuePool *queuePool, Correction *correction, const int *xcoordinates,
+        const int *xcoordinates,
         const int *ycoordinates, const int *codes, const int codesSize,
         const std::map<int, int> *bigramMap, const uint8_t *bigramFilter,
         const bool useFullEditDistance, unsigned short *outWords, int *frequencies) const {
 
-    queuePool->clearAll();
-    Correction* masterCorrection = correction;
-    correction->resetCorrection();
+    WordsPriorityQueuePool queuePool(MAX_WORDS, SUB_QUEUE_MAX_WORDS, MAX_WORD_LENGTH);
+    queuePool.clearAll();
+    Correction masterCorrection;
+    masterCorrection.resetCorrection();
     if (BinaryFormat::REQUIRES_GERMAN_UMLAUT_PROCESSING & FLAGS)
     { // Incrementally tune the word and try all possibilities
         int codesBuffer[getCodesBufferSize(codes, codesSize)];
@@ -185,8 +186,8 @@
         int yCoordinatesBuffer[codesSize];
         getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer,
                 xCoordinatesBuffer, yCoordinatesBuffer, codesSize, bigramMap, bigramFilter,
-                useFullEditDistance, codes, codesSize, 0, codesBuffer, masterCorrection,
-                queuePool, GERMAN_UMLAUT_DIGRAPHS,
+                useFullEditDistance, codes, codesSize, 0, codesBuffer, &masterCorrection,
+                &queuePool, GERMAN_UMLAUT_DIGRAPHS,
                 sizeof(GERMAN_UMLAUT_DIGRAPHS) / sizeof(GERMAN_UMLAUT_DIGRAPHS[0]));
     } else if (BinaryFormat::REQUIRES_FRENCH_LIGATURES_PROCESSING & FLAGS) {
         int codesBuffer[getCodesBufferSize(codes, codesSize)];
@@ -194,28 +195,28 @@
         int yCoordinatesBuffer[codesSize];
         getWordWithDigraphSuggestionsRec(proximityInfo, xcoordinates, ycoordinates, codesBuffer,
                 xCoordinatesBuffer, yCoordinatesBuffer, codesSize, bigramMap, bigramFilter,
-                useFullEditDistance, codes, codesSize, 0, codesBuffer, masterCorrection,
-                queuePool, FRENCH_LIGATURES_DIGRAPHS,
+                useFullEditDistance, codes, codesSize, 0, codesBuffer, &masterCorrection,
+                &queuePool, FRENCH_LIGATURES_DIGRAPHS,
                 sizeof(FRENCH_LIGATURES_DIGRAPHS) / sizeof(FRENCH_LIGATURES_DIGRAPHS[0]));
     } else { // Normal processing
         getWordSuggestions(proximityInfo, xcoordinates, ycoordinates, codes, codesSize,
-                bigramMap, bigramFilter, useFullEditDistance, masterCorrection, queuePool);
+                bigramMap, bigramFilter, useFullEditDistance, &masterCorrection, &queuePool);
     }
 
     PROF_START(20);
     if (DEBUG_DICT) {
-        float ns = queuePool->getMasterQueue()->getHighestNormalizedScore(
-                correction->getPrimaryInputWord(), codesSize, 0, 0, 0);
+        float ns = queuePool.getMasterQueue()->getHighestNormalizedScore(
+                masterCorrection.getPrimaryInputWord(), codesSize, 0, 0, 0);
         ns += 0;
         AKLOGI("Max normalized score = %f", ns);
     }
     const int suggestedWordsCount =
-            queuePool->getMasterQueue()->outputSuggestions(
-                    correction->getPrimaryInputWord(), codesSize, frequencies, outWords);
+            queuePool.getMasterQueue()->outputSuggestions(
+                    masterCorrection.getPrimaryInputWord(), codesSize, frequencies, outWords);
 
     if (DEBUG_DICT) {
-        float ns = queuePool->getMasterQueue()->getHighestNormalizedScore(
-                correction->getPrimaryInputWord(), codesSize, 0, 0, 0);
+        float ns = queuePool.getMasterQueue()->getHighestNormalizedScore(
+                masterCorrection.getPrimaryInputWord(), codesSize, 0, 0, 0);
         ns += 0;
         AKLOGI("Returning %d words", suggestedWordsCount);
         /// Print the returned words
diff --git a/native/jni/src/unigram_dictionary.h b/native/jni/src/unigram_dictionary.h
index 1b26eff..8352c54 100644
--- a/native/jni/src/unigram_dictionary.h
+++ b/native/jni/src/unigram_dictionary.h
@@ -77,14 +77,15 @@
             int fullWordMultiplier, int maxWordLength, int maxWords, const unsigned int flags);
     int getFrequency(const int32_t* const inWord, const int length) const;
     int getBigramPosition(int pos, unsigned short *word, int offset, int length) const;
-    int getSuggestions(ProximityInfo *proximityInfo, WordsPriorityQueuePool *queuePool,
-            Correction *correction, const int *xcoordinates, const int *ycoordinates,
+    int getSuggestions(
+            ProximityInfo *proximityInfo, const int *xcoordinates, const int *ycoordinates,
             const int *codes, const int codesSize, const std::map<int, int> *bigramMap,
             const uint8_t *bigramFilter, const bool useFullEditDistance, unsigned short *outWords,
             int *frequencies) const;
     virtual ~UnigramDictionary();
 
  private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(UnigramDictionary);
     void getWordSuggestions(ProximityInfo *proximityInfo, const int *xcoordinates,
             const int *ycoordinates, const int *codes, const int inputLength,
             const std::map<int, int> *bigramMap, const uint8_t *bigramFilter,
diff --git a/native/jni/src/words_priority_queue.h b/native/jni/src/words_priority_queue.h
index 7629251..9c6d28d 100644
--- a/native/jni/src/words_priority_queue.h
+++ b/native/jni/src/words_priority_queue.h
@@ -182,6 +182,7 @@
     }
 
  private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(WordsPriorityQueue);
     struct wordComparator {
         bool operator ()(SuggestedWord * left, SuggestedWord * right) {
             return left->mScore > right->mScore;
diff --git a/native/jni/src/words_priority_queue_pool.h b/native/jni/src/words_priority_queue_pool.h
index 210b5a8..b4e2bed 100644
--- a/native/jni/src/words_priority_queue_pool.h
+++ b/native/jni/src/words_priority_queue_pool.h
@@ -85,6 +85,7 @@
     }
 
  private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(WordsPriorityQueuePool);
     WordsPriorityQueue* mMasterQueue;
     WordsPriorityQueue* mSubQueues[SUB_QUEUE_MAX_COUNT * MULTIPLE_WORDS_SUGGESTION_MAX_WORDS];
     char mMasterQueueBuf[sizeof(WordsPriorityQueue)];
diff --git a/tools/maketext/res/values-ar/donottranslate-more-keys.xml b/tools/maketext/res/values-ar/donottranslate-more-keys.xml
index 9368321..970e85c 100644
--- a/tools/maketext/res/values-ar/donottranslate-more-keys.xml
+++ b/tools/maketext/res/values-ar/donottranslate-more-keys.xml
@@ -105,4 +105,21 @@
     <!-- TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK -->
     <!-- <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB|&#x00AB;;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string> -->
     <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!4,&#x201C;,&#x201D;,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
+    <!-- U+0655: "ٕ" ARABIC HAMZA BELOW
+         U+0654: "ٔ" ARABIC HAMZA ABOVE
+         U+0652: "ْ" ARABIC SUKUN
+         U+064D: "ٍ" ARABIC KASRATAN
+         U+064C: "ٌ" ARABIC DAMMATAN
+         U+064B: "ً" ARABIC FATHATAN
+         U+0651: "ّ" ARABIC SHADDA -->
+    <!-- U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
+         U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
+         U+0653: "ٓ" ARABIC MADDAH ABOVE
+         U+0650: "ِ" ARABIC KASRA
+         U+064F: "ُ" ARABIC DAMMA
+         U+064E: "َ" ARABIC FATHA
+         U+0640: "ـ" ARABIC TATWEEL -->
+    <!-- In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. -->
+    <string name="more_keys_for_arabic_diacritics">"!fixedColumnOrder!7,&#x0655;,&#x0654;,&#x0652;,&#x064D;,&#x064C;,&#x064B;,&#x0651;,&#x0656;,&#x0670;,&#x0653;,&#x0650;,&#x064F;,&#x064E;,&#x0640;&#x0640;&#x0640;|&#x0640;"</string>
+    <string name="keyhintlabel_for_arabic_diacritics">&#x0651;</string>
 </resources>
diff --git a/tools/maketext/res/values-fa/donottranslate-more-keys.xml b/tools/maketext/res/values-fa/donottranslate-more-keys.xml
index 56b8911..b34e580 100644
--- a/tools/maketext/res/values-fa/donottranslate-more-keys.xml
+++ b/tools/maketext/res/values-fa/donottranslate-more-keys.xml
@@ -108,4 +108,21 @@
     <!-- TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK -->
     <!-- <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;|&#x00BB;,&#x00BB|&#x00AB;;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string> -->
     <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!4,&#x201C;,&#x201D;,&#x00AB;|&#x00BB;,&#x00BB;|&#x00AB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
+    <!-- U+0655: "ٕ" ARABIC HAMZA BELOW
+         U+0652: "ْ" ARABIC SUKUN
+         U+0651: "ّ" ARABIC SHADDA
+         U+064C: "ٌ" ARABIC DAMMATAN
+         U+064D: "ٍ" ARABIC KASRATAN
+         U+064B: "ً" ARABIC FATHATAN
+         U+0654: "ٔ" ARABIC HAMZA ABOVE -->
+    <!-- U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
+         U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
+         U+0653: "ٓ" ARABIC MADDAH ABOVE
+         U+064F: "ُ" ARABIC DAMMA
+         U+0650: "ِ" ARABIC KASRA
+         U+064E: "َ" ARABIC FATHA
+         U+0640: "ـ" ARABIC TATWEEL -->
+    <!-- In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. -->
+    <string name="more_keys_for_arabic_diacritics">"!fixedColumnOrder!7,&#x0655;,&#x0652;,&#x0651;,&#x064C;,&#x064D;,&#x064B;,&#x0654;,&#x0656;,&#x0670;,&#x0653;,&#x064F;,&#x0650;,&#x064E;,&#x0640;&#x0640;&#x0640;|&#x0640;"</string>
+    <string name="keyhintlabel_for_arabic_diacritics">&#x064B;</string>
 </resources>
diff --git a/tools/maketext/res/values/donottranslate-more-keys.xml b/tools/maketext/res/values/donottranslate-more-keys.xml
index 16eaa61..922b42d 100644
--- a/tools/maketext/res/values/donottranslate-more-keys.xml
+++ b/tools/maketext/res/values/donottranslate-more-keys.xml
@@ -109,6 +109,8 @@
          U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK -->
     <string name="more_keys_for_less_than">!fixedColumnOrder!3,&#x2039;,&#x2264;,&#x00AB;</string>
     <string name="more_keys_for_greater_than">!fixedColumnOrder!3,&#x203A;,&#x2265;,&#x00BB;</string>
+    <string name="more_keys_for_arabic_diacritics"></string>
+    <string name="keyhintlabel_for_arabic_diacritics"></string>
     <string name="keylabel_for_symbols_1">1</string>
     <string name="keylabel_for_symbols_2">2</string>
     <string name="keylabel_for_symbols_3">3</string>
@@ -202,20 +204,4 @@
     <!-- popular web domains for the locale - most popular, displayed on the keyboard -->
     <string name="more_keys_for_popular_domain">"!hasLabels!,.net,.org,.gov,.edu"</string>
     <string name="more_keys_for_smiley">"!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ "</string>
-    <!-- U+064F: "ُ" ARABIC DAMMA
-         U+064C: "ٌ" ARABIC DAMMATAN
-         U+0651: "ّ" ARABIC SHADDA
-         U+0652: "ْ" ARABIC SUKUN
-         U+0653: "ٓ" ARABIC MADDAH ABOVE -->
-    <!-- U+064D: "ٍ" ARABIC KASRATAN
-         U+064B: "ً" ARABIC FATHATAN
-         U+0650: "ِ" ARABIC KASRA
-         U+064E: "َ" ARABIC FATHA
-         U+0640: "ـ" ARABIC TATWEEL -->
-    <!-- U+0656: "ٖ" ARABIC SUBSCRIPT ALEF
-         U+0670: "ٰ" ARABIC LETTER SUPERSCRIPT ALEF
-         U+0655: "ٕ" ARABIC HAMZA BELOW
-         U+0654: "ٔ" ARABIC HAMZA ABOVE -->
-    <!-- In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. -->
-    <string name="more_keys_for_arabic_diacritics">"!fixedColumnOrder!5,&#x064F;,&#x064C;,&#x0651;,&#x0652;,&#x0653;,&#x064D;,&#x064B;,&#x0650;,&#x064E;,&#x0640;&#x0640;&#x0640;|&#x0640;,&#x0656;,&#x0670;,&#x0655;,&#x0654;"</string>
 </resources>
diff --git a/tools/maketext/src/com/android/inputmethod/latin/maketext/JarUtils.java b/tools/maketext/src/com/android/inputmethod/latin/maketext/JarUtils.java
index 366d73e..07a6c30 100644
--- a/tools/maketext/src/com/android/inputmethod/latin/maketext/JarUtils.java
+++ b/tools/maketext/src/com/android/inputmethod/latin/maketext/JarUtils.java
@@ -27,14 +27,13 @@
 import java.util.jar.JarFile;
 
 public class JarUtils {
-    private static final String MANIFEST = "META-INF/MANIFEST.MF";
-
     private JarUtils() {
         // This utility class is not publicly instantiable.
     }
 
-    public static JarFile getJarFile(final ClassLoader loader) {
-        final URL resUrl = loader.getResource(MANIFEST);
+    public static JarFile getJarFile(final Class<?> mainClass) {
+        final String mainClassPath = "/" + mainClass.getName().replace('.', '/') + ".class";
+        final URL resUrl = mainClass.getResource(mainClassPath);
         if (!resUrl.getProtocol().equals("jar")) {
             throw new RuntimeException("Should run as jar");
         }
diff --git a/tools/maketext/src/com/android/inputmethod/latin/maketext/LabelText.java b/tools/maketext/src/com/android/inputmethod/latin/maketext/LabelText.java
index a5abcf1..4a92369 100644
--- a/tools/maketext/src/com/android/inputmethod/latin/maketext/LabelText.java
+++ b/tools/maketext/src/com/android/inputmethod/latin/maketext/LabelText.java
@@ -58,7 +58,7 @@
 
     public static void main(final String[] args) {
         final Options options = new Options(args);
-        final JarFile jar = JarUtils.getJarFile(LabelText.class.getClassLoader());
+        final JarFile jar = JarUtils.getJarFile(LabelText.class);
         final MoreKeysResources resources = new MoreKeysResources(jar);
         resources.writeToJava(options.mJava);
     }
diff --git a/tools/maketext/src/com/android/inputmethod/latin/maketext/MoreKeysResources.java b/tools/maketext/src/com/android/inputmethod/latin/maketext/MoreKeysResources.java
index a483593..37ac0d0 100644
--- a/tools/maketext/src/com/android/inputmethod/latin/maketext/MoreKeysResources.java
+++ b/tools/maketext/src/com/android/inputmethod/latin/maketext/MoreKeysResources.java
@@ -100,7 +100,7 @@
                 final File outputFile = new File(outPackage,
                         JAVA_TEMPLATE.replace(".tmpl", ".java"));
                 outPackage.mkdirs();
-                ps = new PrintStream(outputFile);
+                ps = new PrintStream(outputFile, "UTF-8");
             }
             lnr = new LineNumberReader(new InputStreamReader(JarUtils.openResource(template)));
             inflateTemplate(lnr, ps);