Merge "Import translations. DO NOT MERGE"
diff --git a/dictionaries/en_GB_wordlist.combined.gz b/dictionaries/en_GB_wordlist.combined.gz
index a93d834..bf637e9 100644
--- a/dictionaries/en_GB_wordlist.combined.gz
+++ b/dictionaries/en_GB_wordlist.combined.gz
Binary files differ
diff --git a/dictionaries/en_US_wordlist.combined.gz b/dictionaries/en_US_wordlist.combined.gz
index 6925fbd..9ea04b1 100644
--- a/dictionaries/en_US_wordlist.combined.gz
+++ b/dictionaries/en_US_wordlist.combined.gz
Binary files differ
diff --git a/dictionaries/en_wordlist.combined.gz b/dictionaries/en_wordlist.combined.gz
index 9e19274..87a8633 100644
--- a/dictionaries/en_wordlist.combined.gz
+++ b/dictionaries/en_wordlist.combined.gz
Binary files differ
diff --git a/java/res/layout/emoji_keyboard_tab_icon.xml b/java/res/layout/emoji_keyboard_tab_icon.xml
index 13bb41c..15f9c3a 100644
--- a/java/res/layout/emoji_keyboard_tab_icon.xml
+++ b/java/res/layout/emoji_keyboard_tab_icon.xml
@@ -19,6 +19,8 @@
 -->
 
 <!-- Note: contentDescription will be added programatically in {@link EmojiPalettesView}. -->
+<!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
+     We just need to ignore the system's audio and haptic feedback settings. -->
 <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="0dip"
     android:layout_weight="1.0"
@@ -26,4 +28,6 @@
     android:gravity="center"
     android:scaleType="center"
     android:contentDescription="@null"
+    android:hapticFeedbackEnabled="false"
+    android:soundEffectsEnabled="false"
 />
diff --git a/java/res/layout/emoji_palettes_view.xml b/java/res/layout/emoji_palettes_view.xml
index 06a937b..9ff090a 100644
--- a/java/res/layout/emoji_palettes_view.xml
+++ b/java/res/layout/emoji_palettes_view.xml
@@ -62,11 +62,15 @@
             android:layout_height="match_parent"
             android:background="@drawable/suggestions_strip_divider" />
         <!-- TODO: Implement KeyView and replace this. -->
+        <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
+             We just need to ignore the system's audio and haptic feedback settings. -->
         <ImageButton
             android:id="@+id/emoji_keyboard_delete"
             android:layout_width="0dip"
             android:layout_weight="12.5"
             android:layout_height="match_parent"
+            android:hapticFeedbackEnabled="false"
+            android:soundEffectsEnabled="false"
             android:contentDescription="@string/spoken_description_delete" />
     </LinearLayout>
     <android.support.v4.view.ViewPager
@@ -85,18 +89,26 @@
         android:layout_weight="1"
     >
         <!-- TODO: Implement a KeyView and replace this. -->
+        <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
+             We just need to ignore the system's audio and haptic feedback settings. -->
         <TextView
             android:id="@+id/emoji_keyboard_alphabet_left"
             android:layout_width="0dip"
             android:layout_weight="0.15"
             android:gravity="center"
-            android:layout_height="match_parent" />
+            android:layout_height="match_parent"
+            android:hapticFeedbackEnabled="false"
+            android:soundEffectsEnabled="false" />
         <!-- TODO: Implement KeyView and replace this. -->
+        <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
+             We just need to ignore the system's audio and haptic feedback settings. -->
         <RelativeLayout
             android:id="@+id/emoji_keyboard_space"
             android:layout_width="0dip"
             android:layout_weight="0.70"
             android:layout_height="match_parent"
+            android:hapticFeedbackEnabled="false"
+            android:soundEffectsEnabled="false"
             android:contentDescription="@string/spoken_description_space">
             <!-- WORKAROUND: Show the spacebar icon as a bacground of this View. -->
             <View
@@ -108,11 +120,15 @@
                 android:layout_centerInParent="true" />
         </RelativeLayout>
         <!-- TODO: Implement KeyView and replace this. -->
+        <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
+             We just need to ignore the system's audio and haptic feedback settings. -->
         <TextView
             android:id="@+id/emoji_keyboard_alphabet_right"
             android:layout_width="0dip"
             android:layout_weight="0.15"
             android:gravity="center"
-            android:layout_height="match_parent" />
+            android:layout_height="match_parent"
+            android:hapticFeedbackEnabled="false"
+            android:soundEffectsEnabled="false" />
     </LinearLayout>
 </com.android.inputmethod.keyboard.emoji.EmojiPalettesView>
diff --git a/java/res/layout/suggestion_divider.xml b/java/res/layout/suggestion_divider.xml
index be97eae..563599d 100644
--- a/java/res/layout/suggestion_divider.xml
+++ b/java/res/layout/suggestion_divider.xml
@@ -18,13 +18,17 @@
 */
 -->
 
+<!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
+     We just need to ignore the system's audio and haptic feedback settings. -->
 <ImageView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="wrap_content"
     android:layout_height="match_parent"
+    android:padding="0dp"
+    android:gravity="center"
     android:src="@drawable/suggestions_strip_divider"
+    android:contentDescription="@null"
     android:clickable="false"
     android:longClickable="false"
-    android:contentDescription="@null"
-    android:padding="0dp"
-    android:gravity="center" />
+    android:hapticFeedbackEnabled="false"
+    android:soundEffectsEnabled="false" />
diff --git a/java/res/layout/suggestions_strip.xml b/java/res/layout/suggestions_strip.xml
index 3d2f07f..4894779 100644
--- a/java/res/layout/suggestions_strip.xml
+++ b/java/res/layout/suggestions_strip.xml
@@ -20,13 +20,19 @@
 
 <merge
     xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
+         We just need to ignore the system's audio and haptic feedback settings. -->
     <LinearLayout
         android:id="@+id/suggestions_strip"
         android:orientation="horizontal"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_marginLeft="@dimen/config_suggestions_strip_horizontal_margin"
-        android:layout_marginRight="@dimen/config_suggestions_strip_horizontal_margin" />
+        android:layout_marginRight="@dimen/config_suggestions_strip_horizontal_margin"
+        android:hapticFeedbackEnabled="false"
+        android:soundEffectsEnabled="false" />
+    <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
+         We just need to ignore the system's audio and haptic feedback settings. -->
     <LinearLayout
         android:id="@+id/add_to_dictionary_strip"
         android:orientation="horizontal"
@@ -34,7 +40,8 @@
         android:layout_height="match_parent"
         android:layout_marginLeft="@dimen/config_suggestions_strip_horizontal_margin"
         android:layout_marginRight="@dimen/config_suggestions_strip_horizontal_margin"
-        android:visibility="invisible">
+        android:hapticFeedbackEnabled="false"
+        android:soundEffectsEnabled="false">
         <TextView
             android:id="@+id/word_to_save"
             android:layout_width="match_parent"
@@ -49,13 +56,17 @@
             android:textAlignment="viewStart"
             style="?attr/suggestionWordStyle" />
     </LinearLayout>
+    <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
+         We just need to ignore the system's audio and haptic feedback settings. -->
     <LinearLayout
         android:id="@+id/important_notice_strip"
         android:orientation="horizontal"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_marginLeft="@dimen/config_suggestions_strip_horizontal_margin"
-        android:layout_marginRight="@dimen/config_suggestions_strip_horizontal_margin">
+        android:layout_marginRight="@dimen/config_suggestions_strip_horizontal_margin"
+        android:hapticFeedbackEnabled="false"
+        android:soundEffectsEnabled="false" >
         <TextView
             android:id="@+id/important_notice_title"
             android:layout_width="match_parent"
diff --git a/java/res/raw/main_en.dict b/java/res/raw/main_en.dict
index d0ccdbb..d631d6f 100644
--- a/java/res/raw/main_en.dict
+++ b/java/res/raw/main_en.dict
Binary files differ
diff --git a/java/res/values-km-rKH/strings.xml b/java/res/values-km-rKH/strings.xml
index 5d68816..c7b6f2b 100644
--- a/java/res/values-km-rKH/strings.xml
+++ b/java/res/values-km-rKH/strings.xml
@@ -28,7 +28,7 @@
     <string name="popup_on_keypress" msgid="123894815723512944">"លេច​ឡើង​នៅ​​ពេល​ចុច​គ្រាប់​ចុច"</string>
     <string name="general_category" msgid="1859088467017573195">"ទូទៅ"</string>
     <string name="correction_category" msgid="2236750915056607613">"ការ​កែ​អត្ថបទ"</string>
-    <string name="gesture_typing_category" msgid="497263612130532630">"បញ្ចូល​ដោយ​ប្រើ​កាយវិការ"</string>
+    <string name="gesture_typing_category" msgid="497263612130532630">"បញ្ចូល​ដោយ​ប្រើ​កាយវិការ​"</string>
     <string name="misc_category" msgid="6894192814868233453">"ជម្រើស​ផ្សេងទៀត"</string>
     <string name="advanced_settings" msgid="362895144495591463">"ការ​កំណត់​កម្រិត​ខ្ពស់"</string>
     <string name="advanced_settings_summary" msgid="4487980456152830271">"ជម្រើស​សម្រាប់​អ្នក​ជំនាញ"</string>
@@ -38,7 +38,7 @@
     <string name="show_language_switch_key_summary" msgid="7343403647474265713">"បង្ហាញ​នៅ​ពេល​ដែល​បើក​ភាសា​បញ្ចូល​ច្រើន"</string>
     <string name="sliding_key_input_preview" msgid="6604262359510068370">"បង្ហាញ​ទ្រនិច​បង្ហាញ​ស្លាយ"</string>
     <string name="sliding_key_input_preview_summary" msgid="6340524345729093886">"បង្ហាញ​​សញ្ញា​មើល​​ឃើញ​ខណៈ​ពេល​ដែល​រុញ​ពី​ឆ្វេង ឬ​​គ្រាប់​ចុច​​និមិត្ត​សញ្ញា"</string>
-    <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"​សោ​លេចឡើង​បោះបង់​ការ​​ពន្យារពេល"</string>
+    <string name="key_preview_popup_dismiss_delay" msgid="6213164897443068248">"​សោ​លេចឡើង​បោះបង់​ការ​​ពន្យារពេល​"</string>
     <string name="key_preview_popup_dismiss_no_delay" msgid="2096123151571458064">"គ្មាន​ការ​ពន្យារពេល"</string>
     <string name="key_preview_popup_dismiss_default_delay" msgid="2166964333903906734">"លំនាំដើម"</string>
     <string name="abbreviation_unit_milliseconds" msgid="8700286094028323363">"<xliff:g id="MILLISECONDS">%s</xliff:g> មិល្លី​វិនាទី"</string>
@@ -50,7 +50,7 @@
     <skip />
     <string name="use_double_space_period" msgid="8781529969425082860">"រយៈ​ពេល​ចុច​ដកឃ្លា​ពីរដង"</string>
     <string name="use_double_space_period_summary" msgid="6532892187247952799">"ប៉ះ​ដកឃ្លា​ពីរ​​ដង​បញ្ចូល​​​រយៈ​ពេល​ដែល​អនុវត្ត​តាម​ដកឃ្លា"</string>
-    <string name="auto_cap" msgid="1719746674854628252">"ការ​សរសេរ​ជា​អក្សរ​ធំ​​ស្វ័យប្រវត្តិ"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"ការ​សរសេរ​ជា​អក្សរ​ធំ​​ស្វ័យប្រវត្តិ​"</string>
     <string name="auto_cap_summary" msgid="7934452761022946874">"សរសេរ​ពាក្យ​ដំបូង​​​ជា​អក្សរ​ធំ​​នៃ​ប្រយោគ​នីមួយ​ៗ"</string>
     <string name="edit_personal_dictionary" msgid="3996910038952940420">"វចនានុក្រម​ផ្ទាល់ខ្លួន"</string>
     <string name="configure_dictionaries_title" msgid="4238652338556902049">"ផ្នែក​បន្ថែម​វចនានុក្រម"</string>
@@ -61,7 +61,7 @@
     <string name="prefs_suggestion_visibility_show_only_portrait_name" msgid="3859783767435239118">"បង្ហាញ​នៅ​ក្នុង​របៀប​បញ្ឈរ"</string>
     <string name="prefs_suggestion_visibility_hide_name" msgid="6309143926422234673">"លាក់​ជានិច្ច"</string>
     <string name="prefs_block_potentially_offensive_title" msgid="5078480071057408934">"ទប់ស្កាត់​​ពាក្យ​​បំពាន"</string>
-    <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"កុំ​ស្នើ​ឲ្យ​ពាក្យ​បំពាន​មាន​សក្ដានុពល"</string>
+    <string name="prefs_block_potentially_offensive_summary" msgid="2371835479734991364">"កុំ​ស្នើ​ឲ្យ​ពាក្យ​បំពាន​មាន​សក្ដានុពល​"</string>
     <string name="auto_correction" msgid="7630720885194996950">"ការ​កែ​​​ស្វ័យប្រវត្តិ"</string>
     <string name="auto_correction_summary" msgid="5625751551134658006">"ចន្លោះ​មិន​ឃើញ ​និង​សញ្ញា​​វណ្ណយុត្ត​កែ​ពាក្យ​ដែល​បាន​វាយ​ខុស​ស្វ័យប្រវត្តិ"</string>
     <string name="auto_correction_threshold_mode_off" msgid="8470882665417944026">"បិទ"</string>
@@ -121,7 +121,7 @@
     <string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"ថិរវេលា​​ញ័រ​​ពេល​ចុច​គ្រាប់ចុច"</string>
     <string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"កម្រិត​សំឡេង​ពេល​ចុច​គ្រាប់​ចុច"</string>
     <string name="prefs_read_external_dictionary" msgid="2588931418575013067">"អាន​ឯកសារ​វចនានុក្រម​ខាង​ក្រៅ"</string>
-    <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"គ្មាន​ឯកសារ​វចនានុក្រម​នៅ​ក្នុង​ថត​ទាញ​យក"</string>
+    <string name="read_external_dictionary_no_files_message" msgid="4947420942224623792">"គ្មាន​ឯកសារ​វចនានុក្រម​នៅ​ក្នុង​ថត​ទាញ​យក​​"</string>
     <string name="read_external_dictionary_multiple_files_title" msgid="7637749044265808628">"ជ្រើស​ឯកសារ​វចនានុក្រម​ ដើម្បី​ដំឡើង"</string>
     <string name="read_external_dictionary_confirm_install_message" msgid="4782116251651288054">"ពិត​ជា​ដំឡើង​ឯកសារ​នេះ​សម្រាប់ <xliff:g id="LANGUAGE_NAME">%s</xliff:g>?"</string>
     <string name="error" msgid="8940763624668513648">"មាន​កំហុស"</string>
@@ -152,7 +152,7 @@
     <string name="dictionary_provider_name" msgid="3027315045397363079">"កម្មវិធី​ផ្ដល់​វចនានុក្រម"</string>
     <string name="dictionary_service_name" msgid="6237472350693511448">"សេវាកម្ម​​វចនានុក្រម"</string>
     <string name="download_description" msgid="6014835283119198591">"ព័ត៌មាន​បច្ចុប្បន្នភាព​វចនានុក្រម"</string>
-    <string name="dictionary_settings_title" msgid="8091417676045693313">"ផ្នែក​បន្ថែម​វចនានុក្រម"</string>
+    <string name="dictionary_settings_title" msgid="8091417676045693313">"ផ្នែក​បន្ថែម​វចនានុក្រម​​"</string>
     <string name="dictionary_install_over_metered_network_prompt" msgid="3587517870006332980">"វចនានុក្រម​​​​​អាច​ប្រើ​បាន"</string>
     <string name="dictionary_settings_summary" msgid="5305694987799824349">"ការ​កំណត់​សម្រាប់​វចនានុក្រម"</string>
     <string name="user_dictionaries" msgid="3582332055892252845">"វចនានុក្រម​​​អ្នក​ប្រើ"</string>
@@ -168,10 +168,10 @@
     <string name="message_updating" msgid="4457761393932375219">"ពិនិត្យមើល​បច្ចុប្បន្នភាព"</string>
     <string name="message_loading" msgid="5638680861387748936">"កំពុង​ផ្ទុក..."</string>
     <string name="main_dict_description" msgid="3072821352793492143">"វចនានុក្រម​ចម្បង"</string>
-    <string name="cancel" msgid="6830980399865683324">"បោះ​បង់"</string>
+    <string name="cancel" msgid="6830980399865683324">"បោះ​បង់​"</string>
     <string name="go_to_settings" msgid="3876892339342569259">"ការ​កំណត់"</string>
     <string name="install_dict" msgid="180852772562189365">"ដំឡើង"</string>
-    <string name="cancel_download_dict" msgid="7843340278507019303">"បោះ​បង់"</string>
+    <string name="cancel_download_dict" msgid="7843340278507019303">"បោះ​បង់​"</string>
     <string name="delete_dict" msgid="756853268088330054">"លុប"</string>
     <string name="should_download_over_metered_prompt" msgid="1583881200688185508">"ភាសា​ដែល​បាន​ជ្រើស​នៅ​លើ​ឧបករណ៍​ចល័ត​មាន​វចនានុក្រម​អាច​ប្រើ​បាន។&lt;br/&gt; យើង​ផ្ដល់​អនុសាសន៍​ឲ្យ &lt;b&gt;ទាញ​យក&lt;/b&gt; វចនានុក្រម​ភាសា <xliff:g id="LANGUAGE_NAME">%1$s</xliff:g> ដើម្បី​បង្កើន​បទពិសោធន៍​វាយ​បញ្ចូល​របស់​អ្នក។&lt;br/&gt; &lt;br/&gt; ការ​ទាញ​យក​អាច​ចំណាយ​ពេល​ប្រហែល​ពីរ​នាទី​នៅ​តាម 3G។ ការ​គិត​ថ្លៃ​អាច​អនុវត្ត​ប្រសិន​បើ​អ្នក​មិន​ប្រើ &lt;b&gt;ផែនការ​ទិន្នន័យ​គ្មាន​ដែន​កំណត់&lt;/b&gt;.&lt;br/&gt; បើ​អ្នក​មិន​ប្រាកដ​​ថា​ផែនការ​ណា​មួយ​ដែល​អ្នក​មាន យើង​ផ្ដល់​អនុសាសន៍​ឲ្យ​​ភ្ជាប់​វ៉ាយហ្វាយ ដើម្បី​ចាប់ផ្ដើម​ទាញ​យក​ដោយ​ស្វ័យ​ប្រវត្តិ។&lt;br/&gt; &lt;br/&gt; ជំនួយ៖ អ្នក​អាច​ទាញ​យក និង​លុប​វចនានុក្រម​ដោយ​ចូល​ទៅ​ &lt;b&gt;ភាសា &amp; ការ​បញ្ចូល&lt;/b&gt; នៅ​ក្នុង​ម៉ឺនុយ &lt;b&gt;ការ​កំណត់&lt;/b&gt; សម្រាប់​ឧបករណ៍​ចល័ត។"</string>
     <string name="download_over_metered" msgid="1643065851159409546">"ទាញ​យក​ឥឡូវ​នេះ (<xliff:g id="SIZE_IN_MEGABYTES">%1$.1f</xliff:g> មេកាបៃ)"</string>
@@ -189,7 +189,7 @@
     <string name="user_dict_settings_add_word_option_name" msgid="6665558053408962865">"ពាក្យ៖"</string>
     <string name="user_dict_settings_add_shortcut_option_name" msgid="3094731590655523777">"ផ្លូវកាត់​៖"</string>
     <string name="user_dict_settings_add_locale_option_name" msgid="4738643440987277705">"ភាសា៖"</string>
-    <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"វាយ​បញ្ចូល​ពាក្យ"</string>
+    <string name="user_dict_settings_add_word_hint" msgid="4902434148985906707">"វាយ​បញ្ចូល​ពាក្យ​"</string>
     <string name="user_dict_settings_add_shortcut_hint" msgid="2265453012555060178">"ផ្លូវកាត់​ជា​ជម្រើស"</string>
     <string name="user_dict_settings_edit_dialog_title" msgid="3765774633869590352">"កែ​ពាក្យ"</string>
     <string name="user_dict_settings_context_menu_edit_title" msgid="6812255903472456302">"កែ"</string>
diff --git a/java/res/values/keyboard-themes.xml b/java/res/values/keyboard-themes.xml
index 0325f5b..a06082c 100644
--- a/java/res/values/keyboard-themes.xml
+++ b/java/res/values/keyboard-themes.xml
@@ -20,15 +20,15 @@
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- For keyboard color scheme option dialog. -->
     <string-array name="keyboard_theme_names" translatable="false">
+        <!-- TODO: Make this item as translatable string resource. -->
+        <item>Material</item>
         <item>@string/keyboard_color_scheme_white</item>
         <item>@string/keyboard_color_scheme_blue</item>
-        <!-- TODO: Make this item as translatable string resource. -->
-        <item>Quantum</item>
     </string-array>
     <!-- An element must be a keyboard theme id of {@link KeyboardTheme#THEME_ID_*}. -->
     <string-array name="keyboard_theme_ids" translatable="false">
+        <item>3</item>
         <item>2</item>
         <item>0</item>
-        <item>3</item>
     </string-array>
 </resources>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 3f5980d..8849115 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -349,14 +349,8 @@
     <string name="read_external_dictionary_confirm_install_message">Really install this file for <xliff:g id="LANGUAGE_NAME" example="English">%s</xliff:g>?</string>
     <!-- Title for an error dialog that contains the details of the error in the body [CHAR LIMIT=80] -->
     <string name="error">There was an error</string>
-    <!-- Title of the settings for dumpping contacts dictionary file [CHAR LIMIT=35] -->
-    <string name="prefs_dump_contacts_dict">Dump contacts dictionary</string>
-    <!-- Title of the settings for dumpping personal dictionary file [CHAR LIMIT=35] -->
-    <string name="prefs_dump_user_dict">Dump personal dictionary</string>
-    <!-- Title of the settings for dumpping user history dictionary file [CHAR LIMIT=35] -->
-    <string name="prefs_dump_user_history_dict">Dump user history dictionary</string>
-    <!-- Title of the settings for dumpping personalization dictionary file [CHAR LIMIT=35] -->
-    <string name="prefs_dump_personalization_dict">Dump personalization dictionary</string>
+    <!-- Title of the settings group for dumpping dictionary files that have been created on the device [CHAR LIMIT=35] -->
+    <string name="prefs_dump_dynamic_dicts" translatable="false">Dump dictionary</string>
 
     <!-- Title of the button to revert to the default value of the device in the settings dialog [CHAR LIMIT=15] -->
     <string name="button_default">Default</string>
diff --git a/java/res/values/themes-common.xml b/java/res/values/themes-common.xml
index df26fb3..02a93ca 100644
--- a/java/res/values/themes-common.xml
+++ b/java/res/values/themes-common.xml
@@ -124,9 +124,10 @@
         <item name="android:paddingTop">0dp</item>
         <item name="android:paddingRight">@dimen/config_suggestion_text_horizontal_padding</item>
         <item name="android:paddingBottom">0dp</item>
-        <!-- Provide a haptic feedback by ourselves based on the keyboard settings.
-             We just need to ignore the system's haptic feedback settings. -->
+        <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
+             We just need to ignore the system's audio and haptic feedback settings. -->
         <item name="android:hapticFeedbackEnabled">false</item>
+        <item name="android:soundEffectsEnabled">false</item>
         <item name="android:focusable">false</item>
         <item name="android:clickable">false</item>
         <item name="android:singleLine">true</item>
diff --git a/java/res/xml/prefs_for_debug.xml b/java/res/xml/prefs_for_debug.xml
index 1a7fe71..0bcc5cb 100644
--- a/java/res/xml/prefs_for_debug.xml
+++ b/java/res/xml/prefs_for_debug.xml
@@ -61,16 +61,8 @@
     <PreferenceScreen
         android:key="read_external_dictionary"
         android:title="@string/prefs_read_external_dictionary" />
-    <PreferenceScreen
-        android:key="dump_contacts_dict"
-        android:title="@string/prefs_dump_contacts_dict" />
-    <PreferenceScreen
-        android:key="dump_user_dict"
-        android:title="@string/prefs_dump_user_dict" />
-    <PreferenceScreen
-        android:key="dump_user_history_dict"
-        android:title="@string/prefs_dump_user_history_dict" />
-    <PreferenceScreen
-        android:key="dump_personalization_dict"
-        android:title="@string/prefs_dump_personalization_dict" />
+    <PreferenceCategory
+        android:key="pref_key_dump_dictionaries"
+        android:title="@string/prefs_dump_dynamic_dicts">
+    </PreferenceCategory>
 </PreferenceScreen>
diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java
index abed520..e37cd23 100644
--- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java
+++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java
@@ -46,6 +46,7 @@
 import com.android.inputmethod.keyboard.internal.KeyDrawParams;
 import com.android.inputmethod.keyboard.internal.KeyVisualAttributes;
 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
+import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SubtypeSwitcher;
@@ -240,6 +241,8 @@
 
     @Override
     public void onTabChanged(final String tabId) {
+        AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(
+                Constants.CODE_UNSPECIFIED, this);
         final int categoryId = mEmojiCategory.getCategoryId(tabId);
         setCurrentCategoryId(categoryId, false /* force */);
         updateEmojiCategoryPageIdView();
diff --git a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java
index 54bc295..eb8b34c 100644
--- a/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java
+++ b/java/src/com/android/inputmethod/latin/AudioAndHapticFeedbackManager.java
@@ -16,14 +16,14 @@
 
 package com.android.inputmethod.latin;
 
-import com.android.inputmethod.latin.settings.SettingsValues;
-
 import android.content.Context;
 import android.media.AudioManager;
 import android.os.Vibrator;
 import android.view.HapticFeedbackConstants;
 import android.view.View;
 
+import com.android.inputmethod.latin.settings.SettingsValues;
+
 /**
  * This class gathers audio feedback and haptic feedback functions.
  *
@@ -86,40 +86,41 @@
         if (mAudioManager == null) {
             return;
         }
-        if (mSoundOn) {
-            final int sound;
-            switch (code) {
-            case Constants.CODE_DELETE:
-                sound = AudioManager.FX_KEYPRESS_DELETE;
-                break;
-            case Constants.CODE_ENTER:
-                sound = AudioManager.FX_KEYPRESS_RETURN;
-                break;
-            case Constants.CODE_SPACE:
-                sound = AudioManager.FX_KEYPRESS_SPACEBAR;
-                break;
-            default:
-                sound = AudioManager.FX_KEYPRESS_STANDARD;
-                break;
-            }
-            mAudioManager.playSoundEffect(sound, mSettingsValues.mKeypressSoundVolume);
+        if (!mSoundOn) {
+            return;
         }
+        final int sound;
+        switch (code) {
+        case Constants.CODE_DELETE:
+            sound = AudioManager.FX_KEYPRESS_DELETE;
+            break;
+        case Constants.CODE_ENTER:
+            sound = AudioManager.FX_KEYPRESS_RETURN;
+            break;
+        case Constants.CODE_SPACE:
+            sound = AudioManager.FX_KEYPRESS_SPACEBAR;
+            break;
+        default:
+            sound = AudioManager.FX_KEYPRESS_STANDARD;
+            break;
+        }
+        mAudioManager.playSoundEffect(sound, mSettingsValues.mKeypressSoundVolume);
     }
 
     public void performHapticFeedback(final View viewToPerformHapticFeedbackOn) {
         if (!mSettingsValues.mVibrateOn) {
             return;
         }
-        if (mSettingsValues.mKeypressVibrationDuration < 0) {
-            // Go ahead with the system default
-            if (viewToPerformHapticFeedbackOn != null) {
-                viewToPerformHapticFeedbackOn.performHapticFeedback(
-                        HapticFeedbackConstants.KEYBOARD_TAP,
-                        HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
-            }
+        if (mSettingsValues.mKeypressVibrationDuration >= 0) {
+            vibrate(mSettingsValues.mKeypressVibrationDuration);
             return;
         }
-        vibrate(mSettingsValues.mKeypressVibrationDuration);
+        // Go ahead with the system default
+        if (viewToPerformHapticFeedbackOn != null) {
+            viewToPerformHapticFeedbackOn.performHapticFeedback(
+                    HapticFeedbackConstants.KEYBOARD_TAP,
+                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
+        }
     }
 
     public void onSettingsChanged(final SettingsValues settingsValues) {
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 35012a4..fa51436 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -214,6 +214,9 @@
     public static final int CODE_INVERTED_QUESTION_MARK = 0xBF; // ¿
     public static final int CODE_INVERTED_EXCLAMATION_MARK = 0xA1; // ¡
 
+    public static final String REGEXP_PERIOD = "\\.";
+    public static final String STRING_SPACE = " ";
+
     /**
      * Special keys code. Must be negative.
      * These should be aligned with {@link KeyboardCodesSet#ID_TO_NAME},
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index dd5b376..96160fa 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -74,11 +74,6 @@
      */
     private final boolean mUseFirstLastBigrams;
 
-    private ContactsBinaryDictionary(final Context context, final Locale locale,
-            final File dictFile) {
-        this(context, locale, dictFile, NAME);
-    }
-
     protected ContactsBinaryDictionary(final Context context, final Locale locale,
             final File dictFile, final String name) {
         super(context, getDictName(name, locale, dictFile), locale, Dictionary.TYPE_CONTACTS,
@@ -90,8 +85,8 @@
 
     @UsedForTesting
     public static ContactsBinaryDictionary getDictionary(final Context context, final Locale locale,
-            final File dictFile) {
-        return new ContactsBinaryDictionary(context, locale, dictFile);
+            final File dictFile, final String dictNamePrefix) {
+        return new ContactsBinaryDictionary(context, locale, dictFile, dictNamePrefix + NAME);
     }
 
     private synchronized void registerObserver(final Context context) {
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index bdf3923..e6e2bcb 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
@@ -74,7 +74,7 @@
                 Dictionary.TYPE_CONTEXTUAL
             };
 
-    private static final Map<String, Class<? extends ExpandableBinaryDictionary>>
+    public static final Map<String, Class<? extends ExpandableBinaryDictionary>>
             DICT_TYPE_TO_CLASS = new HashMap<>();
 
     static {
@@ -87,7 +87,7 @@
 
     private static final String DICT_FACTORY_METHOD_NAME = "getDictionary";
     private static final Class<?>[] DICT_FACTORY_METHOD_ARG_TYPES =
-            new Class[] { Context.class, Locale.class, File.class };
+            new Class[] { Context.class, Locale.class, File.class, String.class };
 
     private static final String[] SUB_DICT_TYPES =
             Arrays.copyOfRange(DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS, 1 /* start */,
@@ -185,7 +185,8 @@
     }
 
     private static ExpandableBinaryDictionary getSubDict(final String dictType,
-            final Context context, final Locale locale, final File dictFile) {
+            final Context context, final Locale locale, final File dictFile,
+            final String dictNamePrefix) {
         final Class<? extends ExpandableBinaryDictionary> dictClass =
                 DICT_TYPE_TO_CLASS.get(dictType);
         if (dictClass == null) {
@@ -195,7 +196,7 @@
             final Method factoryMethod = dictClass.getMethod(DICT_FACTORY_METHOD_NAME,
                     DICT_FACTORY_METHOD_ARG_TYPES);
             final Object dict = factoryMethod.invoke(null /* obj */,
-                    new Object[] { context, locale, dictFile });
+                    new Object[] { context, locale, dictFile, dictNamePrefix });
             return (ExpandableBinaryDictionary) dict;
         } catch (final NoSuchMethodException | SecurityException | IllegalAccessException
                 | IllegalArgumentException | InvocationTargetException e) {
@@ -208,6 +209,15 @@
             final boolean useContactsDict, final boolean usePersonalizedDicts,
             final boolean forceReloadMainDictionary,
             final DictionaryInitializationListener listener) {
+        resetDictionariesWithDictNamePrefix(context, newLocale, useContactsDict,
+                usePersonalizedDicts, forceReloadMainDictionary, listener, "" /* dictNamePrefix */);
+    }
+
+    public void resetDictionariesWithDictNamePrefix(final Context context, final Locale newLocale,
+            final boolean useContactsDict, final boolean usePersonalizedDicts,
+            final boolean forceReloadMainDictionary,
+            final DictionaryInitializationListener listener,
+            final String dictNamePrefix) {
         final boolean localeHasBeenChanged = !newLocale.equals(mDictionaries.mLocale);
         // We always try to have the main dictionary. Other dictionaries can be unused.
         final boolean reloadMainDictionary = localeHasBeenChanged || forceReloadMainDictionary;
@@ -243,7 +253,8 @@
                 dict = mDictionaries.getSubDict(dictType);
             } else {
                 // Start to use new dictionary.
-                dict = getSubDict(dictType, context, newLocale, null /* dictFile */);
+                dict = getSubDict(dictType, context, newLocale, null /* dictFile */,
+                        dictNamePrefix);
             }
             subDicts.put(dictType, dict);
         }
@@ -312,7 +323,7 @@
             } else {
                 final File dictFile = dictionaryFiles.get(dictType);
                 final ExpandableBinaryDictionary dict = getSubDict(
-                        dictType, context, locale, dictFile);
+                        dictType, context, locale, dictFile, "" /* dictNamePrefix */);
                 if (additionalDictAttributes.containsKey(dictType)) {
                     dict.clearAndFlushDictionaryWithAdditionalAttributes(
                             additionalDictAttributes.get(dictType));
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index e5e00d5..4dbfa0b 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -49,6 +49,7 @@
  * queries in native code. This binary dictionary is written to internal storage.
  */
 abstract public class ExpandableBinaryDictionary extends Dictionary {
+    private static final boolean DEBUG = false;
 
     /** Used for Log actions from this class */
     private static final String TAG = ExpandableBinaryDictionary.class.getSimpleName();
@@ -114,8 +115,7 @@
     private boolean needsToMigrateDictionary(final int formatVersion) {
         // When we bump up the dictionary format version, the old version should be added to here
         // for supporting migration. Note that native code has to support reading such formats.
-        return formatVersion == FormatSpec.VERSION4_ONLY_FOR_TESTING
-                || formatVersion == FormatSpec.VERSION401;
+        return formatVersion == FormatSpec.VERSION4_ONLY_FOR_TESTING;
     }
 
     public boolean isValidDictionaryLocked() {
@@ -325,16 +325,17 @@
     protected void addNgramEntryLocked(final PrevWordsInfo prevWordsInfo, final String word,
             final int frequency, final int timestamp) {
         if (!mBinaryDictionary.addNgramEntry(prevWordsInfo, word, frequency, timestamp)) {
-            Log.e(TAG, "Cannot add n-gram entry.");
-            Log.e(TAG, "  PrevWordsInfo: " + prevWordsInfo);
-            Log.e(TAG, "  word: " + word);
+            if (DEBUG) {
+                Log.i(TAG, "Cannot add n-gram entry.");
+                Log.i(TAG, "  PrevWordsInfo: " + prevWordsInfo + ", word: " + word);
+            }
         }
     }
 
     /**
      * Dynamically remove the n-gram entry in the dictionary.
      */
-    public void removeNgramDynamically(final PrevWordsInfo prevWordsInfo, final String word1) {
+    public void removeNgramDynamically(final PrevWordsInfo prevWordsInfo, final String word) {
         reloadDictionaryIfRequired();
         asyncExecuteTaskWithWriteLock(new Runnable() {
             @Override
@@ -343,7 +344,12 @@
                     return;
                 }
                 runGCIfRequiredLocked(true /* mindsBlockByGC */);
-                mBinaryDictionary.removeNgramEntry(prevWordsInfo, word1);
+                if (!mBinaryDictionary.removeNgramEntry(prevWordsInfo, word)) {
+                    if (DEBUG) {
+                        Log.i(TAG, "Cannot remove n-gram entry.");
+                        Log.i(TAG, "  PrevWordsInfo: " + prevWordsInfo + ", word: " + word);
+                    }
+                }
             }
         });
     }
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 9da0f84..1ba5d5e 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -110,7 +110,7 @@
                 wordComposer, prevWordsInfo, proximityInfo, blockOffensiveWords,
                 additionalFeaturesOptions, SESSION_TYPING, rawSuggestions);
 
-        final boolean isFirstCharCapitalized = wordComposer.isFirstCharCapitalized();
+        final boolean isOnlyFirstCharCapitalized = wordComposer.isOnlyFirstCharCapitalized();
         // If resumed, then we don't want to upcase everything: resuming on a fully-capitalized
         // words is rarely done to switch to another fully-capitalized word, but usually to a
         // normal, non-capitalized suggestion.
@@ -122,7 +122,7 @@
         } else {
             final SuggestedWordInfo firstSuggestedWordInfo = getTransformedSuggestedWordInfo(
                     suggestionResults.first(), suggestionResults.mLocale, isAllUpperCase,
-                    isFirstCharCapitalized, trailingSingleQuotesCount);
+                    isOnlyFirstCharCapitalized, trailingSingleQuotesCount);
             firstSuggestion = firstSuggestedWordInfo.mWord;
             if (!firstSuggestedWordInfo.isKindOf(SuggestedWordInfo.KIND_WHITELIST)) {
                 whitelistedWord = null;
@@ -142,7 +142,7 @@
         final boolean allowsToBeAutoCorrected = (null != whitelistedWord
                 && !whitelistedWord.equals(typedWord))
                 || (consideredWord.length() > 1 && !mDictionaryFacilitator.isValidWord(
-                        consideredWord, wordComposer.isFirstCharCapitalized())
+                        consideredWord, isOnlyFirstCharCapitalized)
                         && !typedWord.equals(firstSuggestion));
 
         final boolean hasAutoCorrection;
@@ -173,12 +173,12 @@
         final ArrayList<SuggestedWordInfo> suggestionsContainer =
                 new ArrayList<>(suggestionResults);
         final int suggestionsCount = suggestionsContainer.size();
-        if (isFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) {
+        if (isOnlyFirstCharCapitalized || isAllUpperCase || 0 != trailingSingleQuotesCount) {
             for (int i = 0; i < suggestionsCount; ++i) {
                 final SuggestedWordInfo wordInfo = suggestionsContainer.get(i);
                 final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo(
-                        wordInfo, suggestionResults.mLocale, isAllUpperCase, isFirstCharCapitalized,
-                        trailingSingleQuotesCount);
+                        wordInfo, suggestionResults.mLocale, isAllUpperCase,
+                        isOnlyFirstCharCapitalized, trailingSingleQuotesCount);
                 suggestionsContainer.set(i, transformedWordInfo);
             }
         }
@@ -292,11 +292,11 @@
 
     /* package for test */ static SuggestedWordInfo getTransformedSuggestedWordInfo(
             final SuggestedWordInfo wordInfo, final Locale locale, final boolean isAllUpperCase,
-            final boolean isFirstCharCapitalized, final int trailingSingleQuotesCount) {
+            final boolean isOnlyFirstCharCapitalized, final int trailingSingleQuotesCount) {
         final StringBuilder sb = new StringBuilder(wordInfo.mWord.length());
         if (isAllUpperCase) {
             sb.append(wordInfo.mWord.toUpperCase(locale));
-        } else if (isFirstCharCapitalized) {
+        } else if (isOnlyFirstCharCapitalized) {
             sb.append(StringUtils.capitalizeFirstCodePoint(wordInfo.mWord, locale));
         } else {
             sb.append(wordInfo.mWord);
diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index b89ab84..debaad1 100644
--- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
@@ -67,10 +67,6 @@
     final private String mLocale;
     final private boolean mAlsoUseMoreRestrictiveLocales;
 
-    private UserBinaryDictionary(final Context context, final Locale locale, final File dictFile) {
-        this(context, locale, false /* alsoUseMoreRestrictiveLocales */, dictFile, NAME);
-    }
-
     protected UserBinaryDictionary(final Context context, final Locale locale,
             final boolean alsoUseMoreRestrictiveLocales, final File dictFile, final String name) {
         super(context, getDictName(name, locale, dictFile), locale, Dictionary.TYPE_USER, dictFile);
@@ -107,8 +103,9 @@
 
     @UsedForTesting
     public static UserBinaryDictionary getDictionary(final Context context, final Locale locale,
-            final File dictFile) {
-        return new UserBinaryDictionary(context, locale, dictFile);
+            final File dictFile, final String dictNamePrefix) {
+        return new UserBinaryDictionary(context, locale, false /* alsoUseMoreRestrictiveLocales */,
+                dictFile, dictNamePrefix + NAME);
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 7a50d1a..6ce1f85 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -45,9 +45,6 @@
     // The list of events that served to compose this string.
     private final ArrayList<Event> mEvents;
     private final InputPointers mInputPointers = new InputPointers(MAX_WORD_LENGTH);
-    // The information of previous words (before the composing word). Must not be null. Used as
-    // context for suggestions.
-    private PrevWordsInfo mPrevWordsInfo;
     private String mAutoCorrection;
     private boolean mIsResumed;
     private boolean mIsBatchMode;
@@ -72,9 +69,9 @@
     private int mCursorPositionWithinWord;
 
     /**
-     * Whether the user chose to capitalize the first char of the word.
+     * Whether the composing word has the only first char capitalized.
      */
-    private boolean mIsFirstCharCapitalized;
+    private boolean mIsOnlyFirstCharCapitalized;
 
     public WordComposer() {
         mCombinerChain = new CombinerChain("");
@@ -84,7 +81,6 @@
         mIsBatchMode = false;
         mCursorPositionWithinWord = 0;
         mRejectedBatchModeSuggestion = null;
-        mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
         refreshTypedWordCache();
     }
 
@@ -111,12 +107,11 @@
         mAutoCorrection = null;
         mCapsCount = 0;
         mDigitsCount = 0;
-        mIsFirstCharCapitalized = false;
+        mIsOnlyFirstCharCapitalized = false;
         mIsResumed = false;
         mIsBatchMode = false;
         mCursorPositionWithinWord = 0;
         mRejectedBatchModeSuggestion = null;
-        mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
         refreshTypedWordCache();
     }
 
@@ -178,12 +173,6 @@
         return mInputPointers;
     }
 
-    private static boolean isFirstCharCapitalized(final int index, final int codePoint,
-            final boolean previous) {
-        if (index == 0) return Character.isUpperCase(codePoint);
-        return previous && !Character.isUpperCase(codePoint);
-    }
-
     /**
      * Process an input event.
      *
@@ -203,7 +192,7 @@
         mCursorPositionWithinWord = mCodePointSize;
         // We may have deleted the last one.
         if (0 == mCodePointSize) {
-            mIsFirstCharCapitalized = false;
+            mIsOnlyFirstCharCapitalized = false;
         }
         if (Constants.CODE_DELETE != event.mKeyCode) {
             if (newIndex < MAX_WORD_LENGTH) {
@@ -215,8 +204,12 @@
                     mInputPointers.addPointerAt(newIndex, keyX, keyY, 0, 0);
                 }
             }
-            mIsFirstCharCapitalized = isFirstCharCapitalized(
-                    newIndex, primaryCode, mIsFirstCharCapitalized);
+            if (0 == newIndex) {
+                mIsOnlyFirstCharCapitalized = Character.isUpperCase(primaryCode);
+            } else {
+                mIsOnlyFirstCharCapitalized = mIsOnlyFirstCharCapitalized
+                        && !Character.isUpperCase(primaryCode);
+            }
             if (Character.isUpperCase(primaryCode)) mCapsCount++;
             if (Character.isDigit(primaryCode)) mDigitsCount++;
         }
@@ -296,10 +289,8 @@
      * This will register NOT_A_COORDINATE for X and Ys, and use the passed keyboard for proximity.
      * @param codePoints the code points to set as the composing word.
      * @param coordinates the x, y coordinates of the key in the CoordinateUtils format
-     * @param prevWordsInfo the information of previous words, to use as context for suggestions
      */
-    public void setComposingWord(final int[] codePoints, final int[] coordinates,
-            final PrevWordsInfo prevWordsInfo) {
+    public void setComposingWord(final int[] codePoints, final int[] coordinates) {
         reset();
         final int length = codePoints.length;
         for (int i = 0; i < length; ++i) {
@@ -308,7 +299,6 @@
                     CoordinateUtils.yFromArray(coordinates, i)));
         }
         mIsResumed = true;
-        mPrevWordsInfo = prevWordsInfo;
     }
 
     /**
@@ -319,16 +309,13 @@
         return mTypedWordCache.toString();
     }
 
-    public PrevWordsInfo getPrevWordsInfoForSuggestion() {
-        return mPrevWordsInfo;
-    }
-
     /**
-     * Whether or not the user typed a capital letter as the first letter in the word
+     * Whether or not the user typed a capital letter as the first letter in the word, and no
+     * other letter is capitalized
      * @return capitalization preference
      */
-    public boolean isFirstCharCapitalized() {
-        return mIsFirstCharCapitalized;
+    public boolean isOnlyFirstCharCapitalized() {
+        return mIsOnlyFirstCharCapitalized;
     }
 
     /**
@@ -364,7 +351,7 @@
     }
 
     /**
-     * Saves the caps mode and the previous word at the start of composing.
+     * Saves the caps mode at the start of composing.
      *
      * WordComposer needs to know about the caps mode for several reasons. The first is, we need
      * to know after the fact what the reason was, to register the correct form into the user
@@ -373,12 +360,9 @@
      * Also, batch input needs to know about the current caps mode to display correctly
      * capitalized suggestions.
      * @param mode the mode at the time of start
-     * @param prevWordsInfo the information of previous words
      */
-    public void setCapitalizedModeAndPreviousWordAtStartComposingTime(final int mode,
-            final PrevWordsInfo prevWordsInfo) {
+    public void setCapitalizedModeAtStartComposingTime(final int mode) {
         mCapitalizedMode = mode;
-        mPrevWordsInfo = prevWordsInfo;
     }
 
     /**
@@ -429,11 +413,10 @@
         mCapsCount = 0;
         mDigitsCount = 0;
         mIsBatchMode = false;
-        mPrevWordsInfo = new PrevWordsInfo(committedWord.toString());
         mCombinerChain.reset();
         mEvents.clear();
         mCodePointSize = 0;
-        mIsFirstCharCapitalized = false;
+        mIsOnlyFirstCharCapitalized = false;
         mCapitalizedMode = CAPS_MODE_OFF;
         refreshTypedWordCache();
         mAutoCorrection = null;
@@ -443,15 +426,7 @@
         return lastComposedWord;
     }
 
-    // Call this when the recorded previous word should be discarded. This is typically called
-    // when the user inputs a separator that's not whitespace (including the case of the
-    // double-space-to-period feature).
-    public void discardPreviousWordForSuggestion() {
-        mPrevWordsInfo = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
-    }
-
-    public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord,
-            final PrevWordsInfo prevWordsInfo) {
+    public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) {
         mEvents.clear();
         Collections.copy(mEvents, lastComposedWord.mEvents);
         mInputPointers.set(lastComposedWord.mInputPointers);
@@ -462,7 +437,6 @@
         mCursorPositionWithinWord = mCodePointSize;
         mRejectedBatchModeSuggestion = null;
         mIsResumed = true;
-        mPrevWordsInfo = prevWordsInfo;
     }
 
     public boolean isBatchMode() {
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index c90dc90..24cc1ef 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -544,11 +544,8 @@
             }
         }
         mConnection.endBatchEdit();
-        mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
-                getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()),
-                // Prev word is 1st word before cursor
-                getPrevWordsInfoFromNthPreviousWordForSuggestion(
-                        settingsValues.mSpacingAndPunctuations, 1 /* nthPreviousWord */));
+        mWordComposer.setCapitalizedModeAtStartComposingTime(
+                getActualCapsMode(settingsValues, keyboardSwitcher.getKeyboardShiftMode()));
     }
 
     /* The sequence number member is only used in onUpdateBatchInput. It is increased each time
@@ -584,10 +581,8 @@
                     mSpaceState = SpaceState.PHANTOM;
                     keyboardSwitcher.requestUpdatingShiftState(
                             getCurrentAutoCapsState(settingsValues), getCurrentRecapitalizeState());
-                    mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
-                            getActualCapsMode(settingsValues,
-                                    keyboardSwitcher.getKeyboardShiftMode()),
-                                            new PrevWordsInfo(commitParts[0]));
+                    mWordComposer.setCapitalizedModeAtStartComposingTime(getActualCapsMode(
+                            settingsValues, keyboardSwitcher.getKeyboardShiftMode()));
                     ++mAutoCommitSequenceNumber;
                 }
             }
@@ -724,15 +719,7 @@
             mWordComposer.processEvent(inputTransaction.mEvent);
             // If it's the first letter, make note of auto-caps state
             if (mWordComposer.isSingleLetter()) {
-                // We pass 2 to getPreviousWordForSuggestion when the previous code point is a word
-                // connector. Otherwise, we pass 1 because we were not composing a word yet, so the
-                // word we want is the 1st word before the cursor.
-                mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
-                        inputTransaction.mShiftState,
-                        getPrevWordsInfoFromNthPreviousWordForSuggestion(
-                                settingsValues.mSpacingAndPunctuations,
-                                settingsValues.mSpacingAndPunctuations.isWordConnector(
-                                        mConnection.getCodePointBeforeCursor()) ? 2 : 1));
+                mWordComposer.setCapitalizedModeAtStartComposingTime(inputTransaction.mShiftState);
             }
             mConnection.setComposingText(getTextWithUnderline(
                     mWordComposer.getTypedWord()), 1);
@@ -924,10 +911,8 @@
                     // No need to reset mSpaceState, it has already be done (that's why we
                     // receive it as a parameter)
                     inputTransaction.setRequiresUpdateSuggestions();
-                    mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
-                            WordComposer.CAPS_MODE_OFF,
-                            getPrevWordsInfoFromNthPreviousWordForSuggestion(
-                                    inputTransaction.mSettingsValues.mSpacingAndPunctuations, 1));
+                    mWordComposer.setCapitalizedModeAtStartComposingTime(
+                            WordComposer.CAPS_MODE_OFF);
                     return;
                 }
             } else if (SpaceState.SWAP_PUNCTUATION == inputTransaction.mSpaceState) {
@@ -1107,7 +1092,6 @@
             final String textToInsert = inputTransaction.mSettingsValues.mSpacingAndPunctuations
                     .mSentenceSeparatorAndSpace;
             mConnection.commitText(textToInsert, 1);
-            mWordComposer.discardPreviousWordForSuggestion();
             return true;
         }
         return false;
@@ -1267,10 +1251,7 @@
         final int expectedCursorPosition = mConnection.getExpectedSelectionStart();
         if (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations)) {
             // Show predictions.
-            mWordComposer.setCapitalizedModeAndPreviousWordAtStartComposingTime(
-                    WordComposer.CAPS_MODE_OFF,
-                    getPrevWordsInfoFromNthPreviousWordForSuggestion(
-                            settingsValues.mSpacingAndPunctuations, 1));
+            mWordComposer.setCapitalizedModeAtStartComposingTime(WordComposer.CAPS_MODE_OFF);
             mLatinIME.mHandler.postUpdateSuggestionStrip();
             return;
         }
@@ -1322,7 +1303,7 @@
                 settingsValues.mSpacingAndPunctuations,
                 0 == numberOfCharsInWordBeforeCursor ? 1 : 2);
         mWordComposer.setComposingWord(codePoints,
-                mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), prevWordsInfo);
+                mLatinIME.getCoordinatesForCurrentKeyboard(codePoints));
         mWordComposer.setCursorPositionWithinWord(
                 typedWord.codePointCount(0, numberOfCharsInWordBeforeCursor));
         mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor,
@@ -1450,7 +1431,7 @@
             // with the typed word, so we need to resume suggestions right away.
             final int[] codePoints = StringUtils.toCodePointArray(stringToCommit);
             mWordComposer.setComposingWord(codePoints,
-                    mLatinIME.getCoordinatesForCurrentKeyboard(codePoints), prevWordsInfo);
+                    mLatinIME.getCoordinatesForCurrentKeyboard(codePoints));
             mConnection.setComposingText(textToCommit, 1);
         }
         // Don't restart suggestion yet. We'll restart if the user deletes the separator.
@@ -1897,21 +1878,6 @@
         // strings.
         mLastComposedWord = mWordComposer.commitWord(commitType,
                 chosenWordWithSuggestions, separatorString, prevWordsInfo);
-        final boolean shouldDiscardPreviousWordForSuggestion;
-        if (0 == StringUtils.codePointCount(separatorString)) {
-            // Separator is 0-length, we can keep the previous word for suggestion. Either this
-            // was a manual pick or the language has no spaces in which case we want to keep the
-            // previous word, or it was the keyboard closing or the cursor moving in which case it
-            // will be reset anyway.
-            shouldDiscardPreviousWordForSuggestion = false;
-        } else {
-            // Otherwise, we discard if the separator contains any non-whitespace.
-            shouldDiscardPreviousWordForSuggestion =
-                    !StringUtils.containsOnlyWhitespace(separatorString);
-        }
-        if (shouldDiscardPreviousWordForSuggestion) {
-            mWordComposer.discardPreviousWordForSuggestion();
-        }
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java
index 96f03f9..96755a9 100644
--- a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java
@@ -37,7 +37,7 @@
     }
     @UsedForTesting
     public static ContextualDictionary getDictionary(final Context context, final Locale locale,
-            final File dictFile) {
+            final File dictFile, final String dictNamePrefix) {
         return new ContextualDictionary(context, locale, dictFile);
     }
 
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
index 19fa29e..f2ad22a 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java
@@ -35,7 +35,7 @@
 
     @UsedForTesting
     public static PersonalizationDictionary getDictionary(final Context context,
-            final Locale locale, final File dictFile) {
+            final Locale locale, final File dictFile, final String dictNamePrefix) {
         return PersonalizationHelper.getPersonalizationDictionary(context, locale);
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
index ea10356..3916fc2 100644
--- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java
@@ -43,7 +43,7 @@
 
     @UsedForTesting
     public static UserHistoryDictionary getDictionary(final Context context, final Locale locale,
-            final File dictFile) {
+            final File dictFile, final String dictNamePrefix) {
         return PersonalizationHelper.getUserHistoryDictionary(context, locale);
     }
 
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
index 9e7e07e..845ddb3 100644
--- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
@@ -25,10 +25,12 @@
 import android.preference.Preference;
 import android.preference.Preference.OnPreferenceClickListener;
 import android.preference.PreferenceFragment;
+import android.preference.PreferenceGroup;
 import android.preference.PreferenceScreen;
 
 import com.android.inputmethod.latin.Dictionary;
 import com.android.inputmethod.latin.DictionaryDumpBroadcastReceiver;
+import com.android.inputmethod.latin.DictionaryFacilitator;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.debug.ExternalDictionaryGetterForDebug;
 import com.android.inputmethod.latin.utils.ApplicationUtils;
@@ -48,10 +50,9 @@
     public static final String PREF_KEY_PREVIEW_DISMISS_DURATION =
             "pref_key_preview_dismiss_duration";
     private static final String PREF_READ_EXTERNAL_DICTIONARY = "read_external_dictionary";
-    private static final String PREF_DUMP_CONTACTS_DICT = "dump_contacts_dict";
-    private static final String PREF_DUMP_USER_DICT = "dump_user_dict";
-    private static final String PREF_DUMP_USER_HISTORY_DICT = "dump_user_history_dict";
-    private static final String PREF_DUMP_PERSONALIZATION_DICT = "dump_personalization_dict";
+    private static final String PREF_KEY_DUMP_DICTS = "pref_key_dump_dictionaries";
+    private static final String PREF_KEY_DUMP_DICT_PREFIX = "pref_key_dump_dictionaries";
+    private static final String DICT_NAME_KEY_FOR_EXTRAS = "dict_name";
     public static final String PREF_SLIDING_KEY_INPUT_PREVIEW = "pref_sliding_key_input_preview";
     public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout";
 
@@ -80,16 +81,18 @@
                     });
         }
 
+        final PreferenceGroup dictDumpPreferenceGroup =
+                (PreferenceGroup)findPreference(PREF_KEY_DUMP_DICTS);
         final OnPreferenceClickListener dictDumpPrefClickListener =
                 new DictDumpPrefClickListener(this);
-        findPreference(PREF_DUMP_CONTACTS_DICT).setOnPreferenceClickListener(
-                dictDumpPrefClickListener);
-        findPreference(PREF_DUMP_USER_DICT).setOnPreferenceClickListener(
-                dictDumpPrefClickListener);
-        findPreference(PREF_DUMP_USER_HISTORY_DICT).setOnPreferenceClickListener(
-                dictDumpPrefClickListener);
-        findPreference(PREF_DUMP_PERSONALIZATION_DICT).setOnPreferenceClickListener(
-                dictDumpPrefClickListener);
+        for (final String dictName : DictionaryFacilitator.DICT_TYPE_TO_CLASS.keySet()) {
+            final Preference preference = new Preference(getActivity());
+            preference.setKey(PREF_KEY_DUMP_DICT_PREFIX + dictName);
+            preference.setTitle("Dump " + dictName + " dictionary");
+            preference.setOnPreferenceClickListener(dictDumpPrefClickListener);
+            preference.getExtras().putString(DICT_NAME_KEY_FOR_EXTRAS, dictName);
+            dictDumpPreferenceGroup.addPreference(preference);
+        }
         final Resources res = getResources();
         setupKeyLongpressTimeoutSettings(prefs, res);
         setupKeyPreviewAnimationDuration(prefs, res, PREF_KEY_PREVIEW_SHOW_UP_DURATION,
@@ -117,18 +120,7 @@
 
         @Override
         public boolean onPreferenceClick(final Preference arg0) {
-            final String dictName;
-            if (arg0.getKey().equals(PREF_DUMP_CONTACTS_DICT)) {
-                dictName = Dictionary.TYPE_CONTACTS;
-            } else if (arg0.getKey().equals(PREF_DUMP_USER_DICT)) {
-                dictName = Dictionary.TYPE_USER;
-            } else if (arg0.getKey().equals(PREF_DUMP_USER_HISTORY_DICT)) {
-                dictName = Dictionary.TYPE_USER_HISTORY;
-            } else if (arg0.getKey().equals(PREF_DUMP_PERSONALIZATION_DICT)) {
-                dictName = Dictionary.TYPE_PERSONALIZATION;
-            } else {
-                dictName = null;
-            }
+            final String dictName = arg0.getExtras().getString(DICT_NAME_KEY_FOR_EXTRAS);
             if (dictName != null) {
                 final Intent intent =
                         new Intent(DictionaryDumpBroadcastReceiver.DICTIONARY_DUMP_INTENT_ACTION);
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java
index cc80e6f..55274cf 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerSession.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.latin.spellcheck;
 
+import android.content.res.Resources;
 import android.os.Binder;
 import android.text.TextUtils;
 import android.util.Log;
@@ -26,14 +27,18 @@
 import com.android.inputmethod.latin.PrevWordsInfo;
 
 import java.util.ArrayList;
+import java.util.Locale;
 
 public final class AndroidSpellCheckerSession extends AndroidWordLevelSpellCheckerSession {
     private static final String TAG = AndroidSpellCheckerSession.class.getSimpleName();
     private static final boolean DBG = false;
     private final static String[] EMPTY_STRING_ARRAY = new String[0];
+    private final Resources mResources;
+    private SentenceLevelAdapter mSentenceLevelAdapter;
 
     public AndroidSpellCheckerSession(AndroidSpellCheckerService service) {
         super(service);
+        mResources = service.getResources();
     }
 
     private SentenceSuggestionsInfo fixWronglyInvalidatedWordWithSingleQuote(TextInfo ti,
@@ -115,8 +120,7 @@
     @Override
     public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple(TextInfo[] textInfos,
             int suggestionsLimit) {
-        final SentenceSuggestionsInfo[] retval =
-                super.onGetSentenceSuggestionsMultiple(textInfos, suggestionsLimit);
+        final SentenceSuggestionsInfo[] retval = splitAndSuggest(textInfos, suggestionsLimit);
         if (retval == null || retval.length != textInfos.length) {
             return retval;
         }
@@ -130,6 +134,58 @@
         return retval;
     }
 
+    /**
+     * Get sentence suggestions for specified texts in an array of TextInfo. This is taken from
+     * SpellCheckerService#onGetSentenceSuggestionsMultiple that we can't use because it's
+     * using private variables.
+     * The default implementation splits the input text to words and returns
+     * {@link SentenceSuggestionsInfo} which contains suggestions for each word.
+     * This function will run on the incoming IPC thread.
+     * So, this is not called on the main thread,
+     * but will be called in series on another thread.
+     * @param textInfos an array of the text metadata
+     * @param suggestionsLimit the maximum number of suggestions to be returned
+     * @return an array of {@link SentenceSuggestionsInfo} returned by
+     * {@link SpellCheckerService.Session#onGetSuggestions(TextInfo, int)}
+     */
+    private SentenceSuggestionsInfo[] splitAndSuggest(TextInfo[] textInfos, int suggestionsLimit) {
+        if (textInfos == null || textInfos.length == 0) {
+            return SentenceLevelAdapter.EMPTY_SENTENCE_SUGGESTIONS_INFOS;
+        }
+        SentenceLevelAdapter sentenceLevelAdapter;
+        synchronized(this) {
+            sentenceLevelAdapter = mSentenceLevelAdapter;
+            if (sentenceLevelAdapter == null) {
+                final String localeStr = getLocale();
+                if (!TextUtils.isEmpty(localeStr)) {
+                    sentenceLevelAdapter = new SentenceLevelAdapter(mResources,
+                            new Locale(localeStr));
+                    mSentenceLevelAdapter = sentenceLevelAdapter;
+                }
+            }
+        }
+        if (sentenceLevelAdapter == null) {
+            return SentenceLevelAdapter.EMPTY_SENTENCE_SUGGESTIONS_INFOS;
+        }
+        final int infosSize = textInfos.length;
+        final SentenceSuggestionsInfo[] retval = new SentenceSuggestionsInfo[infosSize];
+        for (int i = 0; i < infosSize; ++i) {
+            final SentenceLevelAdapter.SentenceTextInfoParams textInfoParams =
+                    sentenceLevelAdapter.getSplitWords(textInfos[i]);
+            final ArrayList<SentenceLevelAdapter.SentenceWordItem> mItems =
+                    textInfoParams.mItems;
+            final int itemsSize = mItems.size();
+            final TextInfo[] splitTextInfos = new TextInfo[itemsSize];
+            for (int j = 0; j < itemsSize; ++j) {
+                splitTextInfos[j] = mItems.get(j).mTextInfo;
+            }
+            retval[i] = SentenceLevelAdapter.reconstructSuggestions(
+                    textInfoParams, onGetSuggestionsMultiple(
+                            splitTextInfos, suggestionsLimit, true));
+        }
+        return retval;
+    }
+
     @Override
     public SuggestionsInfo[] onGetSuggestionsMultiple(TextInfo[] textInfos,
             int suggestionsLimit, boolean sequentialWords) {
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index d7953e6..54eebe3 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -282,6 +282,22 @@
                         return AndroidSpellCheckerService.getNotInDictEmptySuggestions(
                                 false /* reportAsTypo */);
                     }
+                    if (CHECKABILITY_CONTAINS_PERIOD == checkability) {
+                        final String[] splitText = inText.split(Constants.REGEXP_PERIOD);
+                        boolean allWordsAreValid = true;
+                        for (final String word : splitText) {
+                            if (!dictInfo.mDictionary.isValidWord(word)) {
+                                allWordsAreValid = false;
+                                break;
+                            }
+                        }
+                        if (allWordsAreValid) {
+                            return new SuggestionsInfo(SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO
+                                    | SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS,
+                                    new String[] {
+                                            TextUtils.join(Constants.STRING_SPACE, splitText) });
+                        }
+                    }
                     return dictInfo.mDictionary.isValidWord(inText)
                             ? AndroidSpellCheckerService.getInDictEmptySuggestions()
                             : AndroidSpellCheckerService.getNotInDictEmptySuggestions(
@@ -323,7 +339,7 @@
                 } else {
                     coordinates = dictInfo.mKeyboard.getCoordinates(codePoints);
                 }
-                composer.setComposingWord(codePoints, coordinates, null /* previousWord */);
+                composer.setComposingWord(codePoints, coordinates);
                 // TODO: make a spell checker option to block offensive words or not
                 final ArrayList<SuggestedWordInfo> suggestions =
                         dictInfo.mDictionary.getSuggestions(composer, prevWordsInfo,
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SentenceLevelAdapter.java b/java/src/com/android/inputmethod/latin/spellcheck/SentenceLevelAdapter.java
new file mode 100644
index 0000000..13352f3
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SentenceLevelAdapter.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.spellcheck;
+
+import android.content.res.Resources;
+import android.view.textservice.SentenceSuggestionsInfo;
+import android.view.textservice.SuggestionsInfo;
+import android.view.textservice.TextInfo;
+
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.settings.SpacingAndPunctuations;
+import com.android.inputmethod.latin.utils.RunInLocale;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+/**
+ * This code is mostly lifted directly from android.service.textservice.SpellCheckerService in
+ * the framework; maybe that should be protected instead, so that implementers don't have to
+ * rewrite everything for any small change.
+ */
+public class SentenceLevelAdapter {
+    public static final SentenceSuggestionsInfo[] EMPTY_SENTENCE_SUGGESTIONS_INFOS =
+            new SentenceSuggestionsInfo[] {};
+    private static final SuggestionsInfo EMPTY_SUGGESTIONS_INFO = new SuggestionsInfo(0, null);
+    /**
+     * Container for split TextInfo parameters
+     */
+    public static class SentenceWordItem {
+        public final TextInfo mTextInfo;
+        public final int mStart;
+        public final int mLength;
+        public SentenceWordItem(TextInfo ti, int start, int end) {
+            mTextInfo = ti;
+            mStart = start;
+            mLength = end - start;
+        }
+    }
+
+    /**
+     * Container for originally queried TextInfo and parameters
+     */
+    public static class SentenceTextInfoParams {
+        final TextInfo mOriginalTextInfo;
+        final ArrayList<SentenceWordItem> mItems;
+        final int mSize;
+        public SentenceTextInfoParams(TextInfo ti, ArrayList<SentenceWordItem> items) {
+            mOriginalTextInfo = ti;
+            mItems = items;
+            mSize = items.size();
+        }
+    }
+
+    private static class WordIterator {
+        private final SpacingAndPunctuations mSpacingAndPunctuations;
+        public WordIterator(final Resources res, final Locale locale) {
+            final RunInLocale<SpacingAndPunctuations> job
+                    = new RunInLocale<SpacingAndPunctuations>() {
+                @Override
+                protected SpacingAndPunctuations job(final Resources res) {
+                    return new SpacingAndPunctuations(res);
+                }
+            };
+            mSpacingAndPunctuations = job.runInLocale(res, locale);
+        }
+
+        public int getEndOfWord(final CharSequence sequence, int index) {
+            final int length = sequence.length();
+            index = index < 0 ? 0 : Character.offsetByCodePoints(sequence, index, 1);
+            while (index < length) {
+                final int codePoint = Character.codePointAt(sequence, index);
+                if (mSpacingAndPunctuations.isWordSeparator(codePoint)) {
+                    // If it's a period, we want to stop here only if it's followed by another
+                    // word separator. In all other cases we stop here.
+                    if (Constants.CODE_PERIOD == codePoint) {
+                        final int indexOfNextCodePoint =
+                                index + Character.charCount(Constants.CODE_PERIOD);
+                        if (indexOfNextCodePoint < length
+                                && mSpacingAndPunctuations.isWordSeparator(
+                                        Character.codePointAt(sequence, indexOfNextCodePoint))) {
+                            return index;
+                        }
+                    } else {
+                        return index;
+                    }
+                }
+                index += Character.charCount(codePoint);
+            }
+            return index;
+        }
+
+        public int getBeginningOfNextWord(final CharSequence sequence, int index) {
+            final int length = sequence.length();
+            if (index >= length) {
+                return -1;
+            }
+            index = index < 0 ? 0 : Character.offsetByCodePoints(sequence, index, 1);
+            while (index < length) {
+                final int codePoint = Character.codePointAt(sequence, index);
+                if (!mSpacingAndPunctuations.isWordSeparator(codePoint)) {
+                    return index;
+                }
+                index += Character.charCount(codePoint);
+            }
+            return -1;
+        }
+    }
+
+    private final WordIterator mWordIterator;
+    public SentenceLevelAdapter(final Resources res, final Locale locale) {
+        mWordIterator = new WordIterator(res, locale);
+    }
+
+    public SentenceTextInfoParams getSplitWords(TextInfo originalTextInfo) {
+        final WordIterator wordIterator = mWordIterator;
+        final CharSequence originalText = originalTextInfo.getText();
+        final int cookie = originalTextInfo.getCookie();
+        final int start = -1;
+        final int end = originalText.length();
+        final ArrayList<SentenceWordItem> wordItems = new ArrayList<SentenceWordItem>();
+        int wordStart = wordIterator.getBeginningOfNextWord(originalText, start);
+        int wordEnd = wordIterator.getEndOfWord(originalText, wordStart);
+        while (wordStart <= end && wordEnd != -1 && wordStart != -1) {
+            if (wordEnd >= start && wordEnd > wordStart) {
+                final String query = originalText.subSequence(wordStart, wordEnd).toString();
+                final TextInfo ti = new TextInfo(query, cookie, query.hashCode());
+                wordItems.add(new SentenceWordItem(ti, wordStart, wordEnd));
+            }
+            wordStart = wordIterator.getBeginningOfNextWord(originalText, wordEnd);
+            if (wordStart == -1) {
+                break;
+            }
+            wordEnd = wordIterator.getEndOfWord(originalText, wordStart);
+        }
+        return new SentenceTextInfoParams(originalTextInfo, wordItems);
+    }
+
+    public static SentenceSuggestionsInfo reconstructSuggestions(
+            SentenceTextInfoParams originalTextInfoParams, SuggestionsInfo[] results) {
+        if (results == null || results.length == 0) {
+            return null;
+        }
+        if (originalTextInfoParams == null) {
+            return null;
+        }
+        final int originalCookie = originalTextInfoParams.mOriginalTextInfo.getCookie();
+        final int originalSequence =
+                originalTextInfoParams.mOriginalTextInfo.getSequence();
+
+        final int querySize = originalTextInfoParams.mSize;
+        final int[] offsets = new int[querySize];
+        final int[] lengths = new int[querySize];
+        final SuggestionsInfo[] reconstructedSuggestions = new SuggestionsInfo[querySize];
+        for (int i = 0; i < querySize; ++i) {
+            final SentenceWordItem item = originalTextInfoParams.mItems.get(i);
+            SuggestionsInfo result = null;
+            for (int j = 0; j < results.length; ++j) {
+                final SuggestionsInfo cur = results[j];
+                if (cur != null && cur.getSequence() == item.mTextInfo.getSequence()) {
+                    result = cur;
+                    result.setCookieAndSequence(originalCookie, originalSequence);
+                    break;
+                }
+            }
+            offsets[i] = item.mStart;
+            lengths[i] = item.mLength;
+            reconstructedSuggestions[i] = result != null ? result : EMPTY_SUGGESTIONS_INFO;
+        }
+        return new SentenceSuggestionsInfo(reconstructedSuggestions, offsets, lengths);
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index 8ce8635..3be933f 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -428,6 +428,8 @@
 
     @Override
     public void onClick(final View view) {
+        AudioAndHapticFeedbackManager.getInstance().performHapticAndAudioFeedback(
+                Constants.CODE_UNSPECIFIED, this);
         if (view == mImportantNoticeStrip) {
             mListener.showImportantNoticeContents();
             return;
diff --git a/java/src/com/android/inputmethod/latin/utils/StringUtils.java b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
index 4ed0f0a..e4237a7 100644
--- a/java/src/com/android/inputmethod/latin/utils/StringUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/StringUtils.java
@@ -315,24 +315,6 @@
         return true;
     }
 
-    /**
-     * Returns true if all code points in text are whitespace, false otherwise. Empty is true.
-     */
-    // Interestingly enough, U+00A0 NO-BREAK SPACE and U+200B ZERO-WIDTH SPACE are not considered
-    // whitespace, while EN SPACE, EM SPACE and IDEOGRAPHIC SPACES are.
-    public static boolean containsOnlyWhitespace(final String text) {
-        final int length = text.length();
-        int i = 0;
-        while (i < length) {
-            final int codePoint = text.codePointAt(i);
-            if (!Character.isWhitespace(codePoint)) {
-                return false;
-            }
-            i += Character.charCount(codePoint);
-        }
-        return true;
-    }
-
     public static boolean isIdenticalAfterCapitalizeEachWord(final String text,
             final int[] sortedSeparators) {
         boolean needsCapsNext = true;
diff --git a/native/jni/NativeFileList.mk b/native/jni/NativeFileList.mk
index 07a82a9..2dd75c4 100644
--- a/native/jni/NativeFileList.mk
+++ b/native/jni/NativeFileList.mk
@@ -100,8 +100,8 @@
         log_utils.cpp \
         time_keeper.cpp)
 
-LATIN_IME_CORE_SRC_FILES_BACKWARD_V401 := \
-    $(addprefix suggest/policyimpl/dictionary/structure/backward/v401/, \
+LATIN_IME_CORE_SRC_FILES_BACKWARD_V402 := \
+    $(addprefix suggest/policyimpl/dictionary/structure/backward/v402/, \
         ver4_dict_buffers.cpp \
         ver4_dict_constants.cpp \
         ver4_patricia_trie_node_reader.cpp \
@@ -110,16 +110,16 @@
         ver4_patricia_trie_reading_utils.cpp \
         ver4_patricia_trie_writing_helper.cpp \
         ver4_pt_node_array_reader.cpp) \
-    $(addprefix suggest/policyimpl/dictionary/structure/backward/v401/content/, \
+    $(addprefix suggest/policyimpl/dictionary/structure/backward/v402/content/, \
         bigram_dict_content.cpp \
         probability_dict_content.cpp \
         shortcut_dict_content.cpp \
         sparse_table_dict_content.cpp \
         terminal_position_lookup_table.cpp) \
-    $(addprefix suggest/policyimpl/dictionary/structure/backward/v401/bigram/, \
+    $(addprefix suggest/policyimpl/dictionary/structure/backward/v402/bigram/, \
         ver4_bigram_list_policy.cpp)
 
-LATIN_IME_CORE_SRC_FILES += $(LATIN_IME_CORE_SRC_FILES_BACKWARD_V401)
+LATIN_IME_CORE_SRC_FILES += $(LATIN_IME_CORE_SRC_FILES_BACKWARD_V402)
 
 LATIN_IME_CORE_TEST_FILES := \
     defines_test.cpp \
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
index 75f4fef..87cf0cd 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
@@ -139,8 +139,6 @@
         switch (mDictFormatVersion) {
             case FormatUtils::VERSION_2:
                 return FormatUtils::VERSION_2;
-            case FormatUtils::VERSION_401:
-                return FormatUtils::VERSION_401;
             case FormatUtils::VERSION_4_ONLY_FOR_TESTING:
                 return FormatUtils::VERSION_4_ONLY_FOR_TESTING;
             case FormatUtils::VERSION_4:
@@ -249,7 +247,7 @@
     }
 
     bool supportsBeginningOfSentence() const {
-        return mDictFormatVersion > FormatUtils::VERSION_401;
+        return mDictFormatVersion >= FormatUtils::VERSION_4;
     }
 
  private:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp
index b13ad18..a8f8f28 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_read_write_utils.cpp
@@ -98,7 +98,6 @@
         case FormatUtils::VERSION_2:
             // Version 2 dictionary writing is not supported.
             return false;
-        case FormatUtils::VERSION_401:
         case FormatUtils::VERSION_4_ONLY_FOR_TESTING:
         case FormatUtils::VERSION_4:
         case FormatUtils::VERSION_4_DEV:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/Readme.txt b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/Readme.txt
similarity index 100%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/Readme.txt
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/Readme.txt
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.cpp
similarity index 97%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.cpp
index 7ad072f..3e8e059 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.cpp
@@ -22,19 +22,19 @@
  *   suggest/policyimpl/dictionary/structure/v4/bigram/ver4_bigram_list_policy.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.h"
 
 #include "suggest/core/dictionary/property/bigram_property.h"
 #include "suggest/policyimpl/dictionary/header/header_policy.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
 #include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 void Ver4BigramListPolicy::getNextBigram(int *const outBigramPos, int *const outProbability,
         bool *const outHasNext, int *const bigramEntryPos) const {
@@ -285,6 +285,6 @@
     return mBigramDictContent->writeBigramEntry(&updatedBigramEntry, bigramEntryPos);
 }
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.h
similarity index 89%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.h
index adf687b..6162346 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.h
@@ -22,28 +22,28 @@
  *   suggest/policyimpl/dictionary/structure/v4/bigram/ver4_bigram_list_policy.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_VER4_BIGRAM_LIST_POLICY_H
-#define LATINIME_BACKWARD_V401_VER4_BIGRAM_LIST_POLICY_H
+#ifndef LATINIME_BACKWARD_V402_VER4_BIGRAM_LIST_POLICY_H
+#define LATINIME_BACKWARD_V402_VER4_BIGRAM_LIST_POLICY_H
 
 #include "defines.h"
 #include "suggest/core/policy/dictionary_bigrams_structure_policy.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_entry.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_entry.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class BigramDictContent;
-} // namespace v401
+} // namespace v402
 } // namespace backward
 class BigramProperty;
 namespace backward {
-namespace v401 {
-} // namespace v401
+namespace v402 {
+} // namespace v402
 } // namespace backward
 class HeaderPolicy;
 namespace backward {
-namespace v401 {
+namespace v402 {
 class TerminalPositionLookupTable;
 
 class Ver4BigramListPolicy : public DictionaryBigramsStructurePolicy {
@@ -87,7 +87,7 @@
     const TerminalPositionLookupTable *const mTerminalPositionLookupTable;
     const HeaderPolicy *const mHeaderPolicy;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_VER4_BIGRAM_LIST_POLICY_H */
+#endif /* LATINIME_BACKWARD_V402_VER4_BIGRAM_LIST_POLICY_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_dict_content.cpp
similarity index 94%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_dict_content.cpp
index 1e53ff9..e2dd93c 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_dict_content.cpp
@@ -21,20 +21,22 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_dict_content.h"
 
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 const BigramEntry BigramDictContent::getBigramEntryAndAdvancePosition(
         int *const bigramEntryPos) const {
     const BufferWithExtendableBuffer *const bigramListBuffer = getContentBuffer();
-    if (*bigramEntryPos < 0 || *bigramEntryPos >=  bigramListBuffer->getTailPosition()) {
-        AKLOGE("Invalid bigram entry position. bigramEntryPos: %d, bufSize: %d",
-                *bigramEntryPos, bigramListBuffer->getTailPosition());
+    const int bigramEntryTailPos = (*bigramEntryPos) + getBigramEntrySize();
+    if (*bigramEntryPos < 0 || bigramEntryTailPos > bigramListBuffer->getTailPosition()) {
+        AKLOGE("Invalid bigram entry position. bigramEntryPos: %d, bigramEntryTailPos: %d, "
+                "bufSize: %d", *bigramEntryPos, bigramEntryTailPos,
+                        bigramListBuffer->getTailPosition());
         ASSERT(false);
         return BigramEntry(false /* hasNext */, NOT_A_PROBABILITY,
                 Ver4DictConstants::NOT_A_TERMINAL_ID);
@@ -47,8 +49,6 @@
     int level = 0;
     int count = 0;
     if (mHasHistoricalInfo) {
-        probability = bigramListBuffer->readUintAndAdvancePosition(
-                Ver4DictConstants::PROBABILITY_SIZE, bigramEntryPos);
         timestamp = bigramListBuffer->readUintAndAdvancePosition(
                 Ver4DictConstants::TIME_STAMP_FIELD_SIZE, bigramEntryPos);
         level = bigramListBuffer->readUintAndAdvancePosition(
@@ -56,7 +56,8 @@
         count = bigramListBuffer->readUintAndAdvancePosition(
                 Ver4DictConstants::WORD_COUNT_FIELD_SIZE, bigramEntryPos);
     } else {
-        probability = bigramFlags & Ver4DictConstants::BIGRAM_PROBABILITY_MASK;
+        probability = bigramListBuffer->readUintAndAdvancePosition(
+                Ver4DictConstants::PROBABILITY_SIZE, bigramEntryPos);
     }
     const int encodedTargetTerminalId = bigramListBuffer->readUintAndAdvancePosition(
             Ver4DictConstants::BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE, bigramEntryPos);
@@ -74,21 +75,13 @@
 bool BigramDictContent::writeBigramEntryAndAdvancePosition(
         const BigramEntry *const bigramEntryToWrite, int *const entryWritingPos) {
     BufferWithExtendableBuffer *const bigramListBuffer = getWritableContentBuffer();
-    const int bigramFlags = createAndGetBigramFlags(
-            mHasHistoricalInfo ? 0 : bigramEntryToWrite->getProbability(),
-            bigramEntryToWrite->hasNext());
+    const int bigramFlags = createAndGetBigramFlags(bigramEntryToWrite->hasNext());
     if (!bigramListBuffer->writeUintAndAdvancePosition(bigramFlags,
             Ver4DictConstants::BIGRAM_FLAGS_FIELD_SIZE, entryWritingPos)) {
         AKLOGE("Cannot write bigram flags. pos: %d, flags: %x", *entryWritingPos, bigramFlags);
         return false;
     }
     if (mHasHistoricalInfo) {
-        if (!bigramListBuffer->writeUintAndAdvancePosition(bigramEntryToWrite->getProbability(),
-                Ver4DictConstants::PROBABILITY_SIZE, entryWritingPos)) {
-            AKLOGE("Cannot write bigram probability. pos: %d, probability: %d", *entryWritingPos,
-                    bigramEntryToWrite->getProbability());
-            return false;
-        }
         const HistoricalInfo *const historicalInfo = bigramEntryToWrite->getHistoricalInfo();
         if (!bigramListBuffer->writeUintAndAdvancePosition(historicalInfo->getTimeStamp(),
                 Ver4DictConstants::TIME_STAMP_FIELD_SIZE, entryWritingPos)) {
@@ -108,6 +101,13 @@
                     historicalInfo->getCount());
             return false;
         }
+    } else {
+        if (!bigramListBuffer->writeUintAndAdvancePosition(bigramEntryToWrite->getProbability(),
+                Ver4DictConstants::PROBABILITY_SIZE, entryWritingPos)) {
+            AKLOGE("Cannot write bigram probability. pos: %d, probability: %d", *entryWritingPos,
+                    bigramEntryToWrite->getProbability());
+            return false;
+        }
     }
     const int targetTerminalIdToWrite =
             (bigramEntryToWrite->getTargetTerminalId() == Ver4DictConstants::NOT_A_TERMINAL_ID) ?
@@ -219,6 +219,6 @@
     return true;
 }
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_dict_content.h
similarity index 78%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_dict_content.h
index f9c474b..b554e56 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_dict_content.h
@@ -21,18 +21,18 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/bigram_dict_content.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_BIGRAM_DICT_CONTENT_H
-#define LATINIME_BACKWARD_V401_BIGRAM_DICT_CONTENT_H
+#ifndef LATINIME_BACKWARD_V402_BIGRAM_DICT_CONTENT_H
+#define LATINIME_BACKWARD_V402_BIGRAM_DICT_CONTENT_H
 
 #include "defines.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_entry.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_entry.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class BigramDictContent : public SparseTableDictContent {
  public:
@@ -104,9 +104,22 @@
  private:
     DISALLOW_COPY_AND_ASSIGN(BigramDictContent);
 
-    int createAndGetBigramFlags(const int probability, const bool hasNext) const {
-        return (probability & Ver4DictConstants::BIGRAM_PROBABILITY_MASK)
-                | (hasNext ? Ver4DictConstants::BIGRAM_HAS_NEXT_MASK : 0);
+    int createAndGetBigramFlags(const bool hasNext) const {
+        return hasNext ? Ver4DictConstants::BIGRAM_HAS_NEXT_MASK : 0;
+    }
+
+    int getBigramEntrySize() const {
+        if (mHasHistoricalInfo) {
+            return Ver4DictConstants::BIGRAM_FLAGS_FIELD_SIZE
+                    + Ver4DictConstants::TIME_STAMP_FIELD_SIZE
+                    + Ver4DictConstants::WORD_LEVEL_FIELD_SIZE
+                    + Ver4DictConstants::WORD_COUNT_FIELD_SIZE
+                    + Ver4DictConstants::BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE;
+        } else {
+            return Ver4DictConstants::BIGRAM_FLAGS_FIELD_SIZE
+                    + Ver4DictConstants::PROBABILITY_SIZE
+                    + Ver4DictConstants::BIGRAM_TARGET_TERMINAL_ID_FIELD_SIZE;
+        }
     }
 
     bool runGCBigramList(const int bigramListPos,
@@ -116,7 +129,7 @@
 
     bool mHasHistoricalInfo;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_BIGRAM_DICT_CONTENT_H */
+#endif /* LATINIME_BACKWARD_V402_BIGRAM_DICT_CONTENT_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_entry.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_entry.h
similarity index 93%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_entry.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_entry.h
index 82c4b53..40968b4 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_entry.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_entry.h
@@ -21,16 +21,16 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/bigram_entry.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_BIGRAM_ENTRY_H
-#define LATINIME_BACKWARD_V401_BIGRAM_ENTRY_H
+#ifndef LATINIME_BACKWARD_V402_BIGRAM_ENTRY_H
+#define LATINIME_BACKWARD_V402_BIGRAM_ENTRY_H
 
 #include "defines.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
 #include "suggest/policyimpl/dictionary/utils/historical_info.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class BigramEntry {
  public:
@@ -104,7 +104,7 @@
     const HistoricalInfo mHistoricalInfo;
     const int mTargetTerminalId;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_BIGRAM_ENTRY_H */
+#endif /* LATINIME_BACKWARD_V402_BIGRAM_ENTRY_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/dict_content.h
similarity index 85%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/dict_content.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/dict_content.h
index 39e2900..0f2f255 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/dict_content.h
@@ -21,14 +21,14 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/dict_content.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_DICT_CONTENT_H
-#define LATINIME_BACKWARD_V401_DICT_CONTENT_H
+#ifndef LATINIME_BACKWARD_V402_DICT_CONTENT_H
+#define LATINIME_BACKWARD_V402_DICT_CONTENT_H
 
 #include "defines.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class DictContent {
  public:
@@ -41,7 +41,7 @@
  private:
     DISALLOW_COPY_AND_ASSIGN(DictContent);
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_DICT_CONTENT_H */
+#endif /* LATINIME_BACKWARD_V402_DICT_CONTENT_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/probability_dict_content.cpp
similarity index 95%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/probability_dict_content.cpp
index 337b97c..c671647 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/probability_dict_content.cpp
@@ -21,16 +21,16 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/probability_dict_content.h"
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/probability_entry.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 const ProbabilityEntry ProbabilityDictContent::getProbabilityEntry(const int terminalId) const {
     if (terminalId < 0 || terminalId >= mSize) {
@@ -166,6 +166,6 @@
     return true;
 }
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/probability_dict_content.h
similarity index 84%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/probability_dict_content.h
index db30709..3734797 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/probability_dict_content.h
@@ -21,18 +21,18 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/probability_dict_content.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_PROBABILITY_DICT_CONTENT_H
-#define LATINIME_BACKWARD_V401_PROBABILITY_DICT_CONTENT_H
+#ifndef LATINIME_BACKWARD_V402_PROBABILITY_DICT_CONTENT_H
+#define LATINIME_BACKWARD_V402_PROBABILITY_DICT_CONTENT_H
 
 #include "defines.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/single_dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/single_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class ProbabilityEntry;
 
@@ -68,7 +68,7 @@
     bool mHasHistoricalInfo;
     int mSize;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_PROBABILITY_DICT_CONTENT_H */
+#endif /* LATINIME_BACKWARD_V402_PROBABILITY_DICT_CONTENT_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/probability_entry.h
similarity index 91%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/probability_entry.h
index d341e7b..8ccfa33 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/probability_entry.h
@@ -21,16 +21,16 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_PROBABILITY_ENTRY_H
-#define LATINIME_BACKWARD_V401_PROBABILITY_ENTRY_H
+#ifndef LATINIME_BACKWARD_V402_PROBABILITY_ENTRY_H
+#define LATINIME_BACKWARD_V402_PROBABILITY_ENTRY_H
 
 #include "defines.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
 #include "suggest/policyimpl/dictionary/utils/historical_info.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class ProbabilityEntry {
  public:
@@ -84,7 +84,7 @@
     const int mProbability;
     const HistoricalInfo mHistoricalInfo;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_PROBABILITY_ENTRY_H */
+#endif /* LATINIME_BACKWARD_V402_PROBABILITY_ENTRY_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/shortcut_dict_content.cpp
similarity index 98%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/shortcut_dict_content.cpp
index 3214807..56bc8b9 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/shortcut_dict_content.cpp
@@ -21,13 +21,13 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/shortcut_dict_content.h"
 
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 void ShortcutDictContent::getShortcutEntryAndAdvancePosition(const int maxCodePointCount,
         int *const outCodePoint, int *const outCodePointCount, int *const outProbability,
@@ -194,6 +194,6 @@
             | (hasNext ? Ver4DictConstants::SHORTCUT_HAS_NEXT_MASK : 0);
 }
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/shortcut_dict_content.h
similarity index 90%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/shortcut_dict_content.h
index 75fd4f3..179cec5 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/shortcut_dict_content.h
@@ -21,17 +21,17 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/shortcut_dict_content.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_SHORTCUT_DICT_CONTENT_H
-#define LATINIME_BACKWARD_V401_SHORTCUT_DICT_CONTENT_H
+#ifndef LATINIME_BACKWARD_V402_SHORTCUT_DICT_CONTENT_H
+#define LATINIME_BACKWARD_V402_SHORTCUT_DICT_CONTENT_H
 
 #include "defines.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class ShortcutDictContent : public SparseTableDictContent {
  public:
@@ -95,7 +95,7 @@
 
     int createAndGetShortcutFlags(const int probability, const bool hasNext) const;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_SHORTCUT_DICT_CONTENT_H */
+#endif /* LATINIME_BACKWARD_V402_SHORTCUT_DICT_CONTENT_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/single_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/single_dict_content.h
similarity index 89%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/single_dict_content.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/single_dict_content.h
index a519cd8..6433650 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/single_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/single_dict_content.h
@@ -21,19 +21,19 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/single_dict_content.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_SINGLE_DICT_CONTENT_H
-#define LATINIME_BACKWARD_V401_SINGLE_DICT_CONTENT_H
+#ifndef LATINIME_BACKWARD_V402_SINGLE_DICT_CONTENT_H
+#define LATINIME_BACKWARD_V402_SINGLE_DICT_CONTENT_H
 
 #include "defines.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 #include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
 #include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class SingleDictContent : public DictContent {
  public:
@@ -80,7 +80,7 @@
     BufferWithExtendableBuffer mExpandableContentBuffer;
     const bool mIsValid;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_SINGLE_DICT_CONTENT_H */
+#endif /* LATINIME_BACKWARD_V402_SINGLE_DICT_CONTENT_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.cpp
similarity index 94%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.cpp
index 638132c..7c9b496 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.cpp
@@ -21,11 +21,11 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 bool SparseTableDictContent::flush(const char *const dictPath,
         const char *const lookupTableFileNameSuffix, const char *const addressTableFileNameSuffix,
@@ -45,6 +45,6 @@
     return true;
 }
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.h
similarity index 93%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.h
index b95de2e..c7233ed 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/sparse_table_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/sparse_table_dict_content.h
@@ -21,12 +21,12 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/sparse_table_dict_content.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_SPARSE_TABLE_DICT_CONTENT_H
-#define LATINIME_BACKWARD_V401_SPARSE_TABLE_DICT_CONTENT_H
+#ifndef LATINIME_BACKWARD_V402_SPARSE_TABLE_DICT_CONTENT_H
+#define LATINIME_BACKWARD_V402_SPARSE_TABLE_DICT_CONTENT_H
 
 #include "defines.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 #include "suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h"
 #include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h"
@@ -34,7 +34,7 @@
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 // TODO: Support multiple contents.
 class SparseTableDictContent : public DictContent {
@@ -116,7 +116,7 @@
     SparseTable mAddressLookupTable;
     const bool mIsValid;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_SPARSE_TABLE_DICT_CONTENT_H */
+#endif /* LATINIME_BACKWARD_V402_SPARSE_TABLE_DICT_CONTENT_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.cpp
similarity index 96%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.cpp
index ab8a3ae..a9f8417 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.cpp
@@ -21,14 +21,14 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.h"
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_reading_utils.h"
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 int TerminalPositionLookupTable::getTerminalPtNodePosition(const int terminalId) const {
     if (terminalId < 0 || terminalId >= mSize) {
@@ -106,6 +106,6 @@
     return true;
 }
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.h
similarity index 85%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.h
index dbf0e60..eadfe0f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.h
@@ -21,18 +21,18 @@
  *   suggest/policyimpl/dictionary/structure/v4/content/terminal_position_lookup_table.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_TERMINAL_POSITION_LOOKUP_TABLE_H
-#define LATINIME_BACKWARD_V401_TERMINAL_POSITION_LOOKUP_TABLE_H
+#ifndef LATINIME_BACKWARD_V402_TERMINAL_POSITION_LOOKUP_TABLE_H
+#define LATINIME_BACKWARD_V402_TERMINAL_POSITION_LOOKUP_TABLE_H
 
 #include <unordered_map>
 
 #include "defines.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/single_dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/single_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class TerminalPositionLookupTable : public SingleDictContent {
  public:
@@ -67,7 +67,7 @@
 
     int mSize;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif // LATINIME_BACKWARD_V401_TERMINAL_POSITION_LOOKUP_TABLE_H
+#endif // LATINIME_BACKWARD_V402_TERMINAL_POSITION_LOOKUP_TABLE_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/shortcut/ver4_shortcut_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/shortcut/ver4_shortcut_list_policy.h
similarity index 93%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/shortcut/ver4_shortcut_list_policy.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/shortcut/ver4_shortcut_list_policy.h
index 6a4e83c..941fda7 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/shortcut/ver4_shortcut_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/shortcut/ver4_shortcut_list_policy.h
@@ -22,18 +22,18 @@
  *   suggest/policyimpl/dictionary/structure/v4/shortcut/ver4_shortcut_list_policy.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_VER4_SHORTCUT_LIST_POLICY_H
-#define LATINIME_BACKWARD_V401_VER4_SHORTCUT_LIST_POLICY_H
+#ifndef LATINIME_BACKWARD_V402_VER4_SHORTCUT_LIST_POLICY_H
+#define LATINIME_BACKWARD_V402_VER4_SHORTCUT_LIST_POLICY_H
 
 #include "defines.h"
 #include "suggest/core/policy/dictionary_shortcuts_structure_policy.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/shortcut_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class Ver4ShortcutListPolicy : public DictionaryShortcutsStructurePolicy {
  public:
@@ -112,7 +112,7 @@
 
     ShortcutDictContent *const mShortcutDictContent;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif // LATINIME_BACKWARD_V401_VER4_SHORTCUT_LIST_POLICY_H
+#endif // LATINIME_BACKWARD_V402_VER4_SHORTCUT_LIST_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.cpp
similarity index 97%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.cpp
index 55ead01..93f1929 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.cpp
@@ -21,7 +21,7 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.h"
 
 #include <cerrno>
 #include <cstring>
@@ -33,7 +33,7 @@
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 /* static */ Ver4DictBuffers::Ver4DictBuffersPtr Ver4DictBuffers::openVer4DictBuffers(
         const char *const dictPath, MmappedBuffer::MmappedBufferPtr headerBuffer,
@@ -65,6 +65,7 @@
             return false;
         }
     }
+    umask(S_IWGRP | S_IWOTH);
     if (mkdir(tmpDirPath, S_IRWXU) == -1) {
         AKLOGE("Cannot create directory: %s. errno: %d.", tmpDirPath, errno);
         return false;
@@ -150,6 +151,6 @@
           mBigramDictContent(headerPolicy->hasHistoricalInfoOfWords()), mShortcutDictContent(),
           mIsUpdatable(true) {}
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.h
similarity index 90%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.h
index 716ed93..e775be5 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.h
@@ -21,24 +21,24 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_VER4_DICT_BUFFER_H
-#define LATINIME_BACKWARD_V401_VER4_DICT_BUFFER_H
+#ifndef LATINIME_BACKWARD_V402_VER4_DICT_BUFFER_H
+#define LATINIME_BACKWARD_V402_VER4_DICT_BUFFER_H
 
 #include <memory>
 
 #include "defines.h"
 #include "suggest/policyimpl/dictionary/header/header_policy.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/bigram_dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/shortcut_dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/bigram_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/probability_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/shortcut_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 #include "suggest/policyimpl/dictionary/utils/mmapped_buffer.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class Ver4DictBuffers {
  public:
@@ -146,7 +146,7 @@
     ShortcutDictContent mShortcutDictContent;
     const int mIsUpdatable;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_VER4_DICT_BUFFER_H */
+#endif /* LATINIME_BACKWARD_V402_VER4_DICT_BUFFER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.cpp
similarity index 97%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.cpp
index 793b44e..81d85f4 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.cpp
@@ -21,11 +21,11 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 // These values MUST match the definitions in FormatSpec.java.
 const char *const Ver4DictConstants::TRIE_FILE_EXTENSION = ".trie";
@@ -76,6 +76,6 @@
 const int Ver4DictConstants::SHORTCUT_PROBABILITY_MASK = 0x0F;
 const int Ver4DictConstants::SHORTCUT_HAS_NEXT_MASK = 0x80;
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h
similarity index 93%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h
index 17afeb1..88ebd6a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h
@@ -21,14 +21,14 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_VER4_DICT_CONSTANTS_H
-#define LATINIME_BACKWARD_V401_VER4_DICT_CONSTANTS_H
+#ifndef LATINIME_BACKWARD_V402_VER4_DICT_CONSTANTS_H
+#define LATINIME_BACKWARD_V402_VER4_DICT_CONSTANTS_H
 
 #include "defines.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 // TODO: Create PtConstants under the pt_common and move some constant values there.
 // Note that there are corresponding definitions in FormatSpec.java.
@@ -78,7 +78,7 @@
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4DictConstants);
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_VER4_DICT_CONSTANTS_H */
+#endif /* LATINIME_BACKWARD_V402_VER4_DICT_CONSTANTS_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.cpp
similarity index 93%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.cpp
index 80b51b2..82399f1 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.cpp
@@ -21,19 +21,19 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h"
 
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_dict_content.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/probability_dict_content.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/probability_entry.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_reading_utils.h"
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 #include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 const PtNodeParams Ver4PatriciaTrieNodeReader::fetchPtNodeInfoFromBufferAndProcessMovedPtNode(
         const int ptNodePos, const int siblingNodePos) const {
@@ -104,6 +104,6 @@
     }
 }
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h
similarity index 88%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h
index 0531b0a..4032a67 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h
@@ -21,8 +21,8 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_NODE_READER_H
-#define LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_NODE_READER_H
+#ifndef LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_NODE_READER_H
+#define LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_NODE_READER_H
 
 #include "defines.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h"
@@ -30,18 +30,18 @@
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 class BufferWithExtendableBuffer;
 namespace backward {
-namespace v401 {
-} // namespace v401
+namespace v402 {
+} // namespace v402
 } // namespace backward
 class HeaderPolicy;
 namespace backward {
-namespace v401 {
+namespace v402 {
 class ProbabilityDictContent;
 
 /*
@@ -73,7 +73,7 @@
     const PtNodeParams fetchPtNodeInfoFromBufferAndProcessMovedPtNode(const int ptNodePos,
             const int siblingNodePos) const;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_NODE_READER_H */
+#endif /* LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_NODE_READER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp
similarity index 97%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp
index 8de6bac..4220a95 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp
@@ -21,24 +21,24 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h"
 
 #include "suggest/core/dictionary/property/unigram_property.h"
 #include "suggest/policyimpl/dictionary/header/header_policy.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/shortcut/ver4_shortcut_list_policy.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/probability_entry.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/shortcut/ver4_shortcut_list_policy.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.h"
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 #include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 const int Ver4PatriciaTrieNodeWriter::CHILDREN_POSITION_FIELD_SIZE = 3;
 
@@ -424,6 +424,6 @@
     return true;
 }
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h
similarity index 93%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h
index 7f1851d..08226ea 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h
@@ -21,29 +21,29 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_NODE_WRITER_H
-#define LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_NODE_WRITER_H
+#ifndef LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_NODE_WRITER_H
+#define LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_NODE_WRITER_H
 
 #include "defines.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_writer.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/probability_entry.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/probability_entry.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 class BufferWithExtendableBuffer;
 namespace backward {
-namespace v401 {
-} // namespace v401
+namespace v402 {
+} // namespace v402
 } // namespace backward
 class HeaderPolicy;
 namespace backward {
-namespace v401 {
+namespace v402 {
 class Ver4BigramListPolicy;
 class Ver4DictBuffers;
 class Ver4PatriciaTrieNodeReader;
@@ -139,7 +139,7 @@
     Ver4BigramListPolicy *const mBigramPolicy;
     Ver4ShortcutListPolicy *const mShortcutPolicy;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_NODE_WRITER_H */
+#endif /* LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_NODE_WRITER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
similarity index 88%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
index 0f60a89..e571d89 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
@@ -22,7 +22,7 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h"
 
 #include <vector>
 
@@ -33,13 +33,13 @@
 #include "suggest/core/dictionary/property/word_property.h"
 #include "suggest/core/session/prev_words_info.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h"
 #include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h"
 #include "suggest/policyimpl/dictionary/utils/probability_utils.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 // Note that there are corresponding definitions in Java side in BinaryDictionaryTests and
 // BinaryDictionaryDecayingTests.
@@ -70,13 +70,17 @@
             // valid terminal DicNode.
             isTerminal = ptNodeParams.getProbability() != NOT_A_PROBABILITY;
         }
+        readingHelper.readNextSiblingNode(ptNodeParams);
+        if (ptNodeParams.representsNonWordInfo()) {
+            // Skip PtNodes that represent non-word information.
+            continue;
+        }
         childDicNodes->pushLeavingChild(dicNode, ptNodeParams.getHeadPos(),
                 ptNodeParams.getChildrenPos(), ptNodeParams.getProbability(), isTerminal,
                 ptNodeParams.hasChildren(),
                 ptNodeParams.isBlacklisted()
                         || ptNodeParams.isNotAWord() /* isBlacklistedOrNotAWord */,
                 ptNodeParams.getCodePointCount(), ptNodeParams.getCodePoints());
-        readingHelper.readNextSiblingNode(ptNodeParams);
     }
     if (readingHelper.isError()) {
         mIsCorrupted = true;
@@ -122,9 +126,7 @@
         } else if (bigramProbability == NOT_A_PROBABILITY) {
             return ProbabilityUtils::backoff(unigramProbability);
         } else {
-            // bigramProbability is a bigram probability delta.
-            return ProbabilityUtils::computeProbabilityForBigram(unigramProbability,
-                    bigramProbability);
+            return bigramProbability;
         }
     }
 }
@@ -189,9 +191,19 @@
     DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader);
     readingHelper.initWithPtNodeArrayPos(getRootPosition());
     bool addedNewUnigram = false;
-    if (mUpdatingHelper.addUnigramWord(&readingHelper, word, length,
+    int codePointsToAdd[MAX_WORD_LENGTH];
+    int codePointCountToAdd = length;
+    memmove(codePointsToAdd, word, sizeof(int) * length);
+    if (unigramProperty->representsBeginningOfSentence()) {
+        codePointCountToAdd = CharUtils::attachBeginningOfSentenceMarker(codePointsToAdd,
+                codePointCountToAdd, MAX_WORD_LENGTH);
+    }
+    if (codePointCountToAdd <= 0) {
+        return false;
+    }
+    if (mUpdatingHelper.addUnigramWord(&readingHelper, codePointsToAdd, codePointCountToAdd,
             unigramProperty, &addedNewUnigram)) {
-        if (addedNewUnigram) {
+        if (addedNewUnigram && !unigramProperty->representsBeginningOfSentence()) {
             mUnigramCount++;
         }
         if (unigramProperty->getShortcuts().size() > 0) {
@@ -221,8 +233,6 @@
 
 bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
         const BigramProperty *const bigramProperty) {
-    const int length0 = prevWordsInfo->getNthPrevWordCodePointCount(1);
-    const int *word0 = prevWordsInfo->getNthPrevWordCodePoints(1);
     if (!mBuffers->isUpdatable()) {
         AKLOGI("Warning: addNgramEntry() is called for non-updatable dictionary.");
         return false;
@@ -232,15 +242,20 @@
                 mDictBuffer->getTailPosition());
         return false;
     }
-    if (length0 > MAX_WORD_LENGTH
-            || bigramProperty->getTargetCodePoints()->size() > MAX_WORD_LENGTH) {
-        AKLOGE("Either src word or target word is too long to insert the bigram to the dictionary. "
-                "length0: %d, length1: %d", length0, bigramProperty->getTargetCodePoints()->size());
+    if (!prevWordsInfo->isValid()) {
+        AKLOGE("prev words info is not valid for adding n-gram entry to the dictionary.");
         return false;
     }
-    const int word0Pos = getTerminalPtNodePositionOfWord(word0, length0,
-            false /* forceLowerCaseSearch */);
-    if (word0Pos == NOT_A_DICT_POS) {
+    if (bigramProperty->getTargetCodePoints()->size() > MAX_WORD_LENGTH) {
+        AKLOGE("The word is too long to insert the ngram to the dictionary. "
+                "length: %d", bigramProperty->getTargetCodePoints()->size());
+        return false;
+    }
+    int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+    prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos,
+            false /* tryLowerCaseSearch */);
+    // TODO: Support N-gram.
+    if (prevWordsPtNodePos[0] == NOT_A_DICT_POS) {
         return false;
     }
     const int word1Pos = getTerminalPtNodePositionOfWord(
@@ -250,7 +265,8 @@
         return false;
     }
     bool addedNewBigram = false;
-    if (mUpdatingHelper.addBigramWords(word0Pos, word1Pos, bigramProperty, &addedNewBigram)) {
+    if (mUpdatingHelper.addBigramWords(prevWordsPtNodePos[0], word1Pos, bigramProperty,
+            &addedNewBigram)) {
         if (addedNewBigram) {
             mBigramCount++;
         }
@@ -261,11 +277,9 @@
 }
 
 bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
-        const int *const word1, const int length1) {
-    const int length0 = prevWordsInfo->getNthPrevWordCodePointCount(1);
-    const int *word0 = prevWordsInfo->getNthPrevWordCodePoints(1);
+        const int *const word, const int length) {
     if (!mBuffers->isUpdatable()) {
-        AKLOGI("Warning: addBigramWords() is called for non-updatable dictionary.");
+        AKLOGI("Warning: removeNgramEntry() is called for non-updatable dictionary.");
         return false;
     }
     if (mDictBuffer->getTailPosition() >= MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS) {
@@ -273,22 +287,26 @@
                 mDictBuffer->getTailPosition());
         return false;
     }
-    if (length0 > MAX_WORD_LENGTH || length1 > MAX_WORD_LENGTH) {
-        AKLOGE("Either src word or target word is too long to remove the bigram to from the "
-                "dictionary. length0: %d, length1: %d", length0, length1);
+    if (!prevWordsInfo->isValid()) {
+        AKLOGE("prev words info is not valid for removing n-gram entry form the dictionary.");
         return false;
     }
-    const int word0Pos = getTerminalPtNodePositionOfWord(word0, length0,
+    if (length > MAX_WORD_LENGTH) {
+        AKLOGE("word is too long to remove n-gram entry form the dictionary. length: %d", length);
+    }
+    int prevWordsPtNodePos[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
+    prevWordsInfo->getPrevWordsTerminalPtNodePos(this, prevWordsPtNodePos,
+            false /* tryLowerCaseSerch */);
+    // TODO: Support N-gram.
+    if (prevWordsPtNodePos[0] == NOT_A_DICT_POS) {
+        return false;
+    }
+    const int wordPos = getTerminalPtNodePositionOfWord(word, length,
             false /* forceLowerCaseSearch */);
-    if (word0Pos == NOT_A_DICT_POS) {
+    if (wordPos == NOT_A_DICT_POS) {
         return false;
     }
-    const int word1Pos = getTerminalPtNodePositionOfWord(word1, length1,
-            false /* forceLowerCaseSearch */);
-    if (word1Pos == NOT_A_DICT_POS) {
-        return false;
-    }
-    if (mUpdatingHelper.removeBigramWords(word0Pos, word1Pos)) {
+    if (mUpdatingHelper.removeBigramWords(prevWordsPtNodePos[0], wordPos)) {
         mBigramCount--;
         return true;
     } else {
@@ -413,7 +431,7 @@
             const int probability = bigramEntry.hasHistoricalInfo() ?
                     ForgettingCurveUtils::decodeProbability(
                             bigramEntry.getHistoricalInfo(), mHeaderPolicy) :
-                    getProbability(word1Probability, bigramEntry.getProbability());
+                    bigramEntry.getProbability();
             bigrams.emplace_back(&word1, probability,
                     historicalInfo->getTimeStamp(), historicalInfo->getLevel(),
                     historicalInfo->getCount());
@@ -436,7 +454,7 @@
             shortcuts.emplace_back(&target, shortcutProbability);
         }
     }
-    const UnigramProperty unigramProperty(false /* representsBeginningOfSentence */,
+    const UnigramProperty unigramProperty(ptNodeParams.representsBeginningOfSentence(),
             ptNodeParams.isNotAWord(), ptNodeParams.isBlacklisted(), ptNodeParams.getProbability(),
             historicalInfo->getTimeStamp(), historicalInfo->getLevel(),
             historicalInfo->getCount(), &shortcuts);
@@ -479,6 +497,6 @@
     return nextToken;
 }
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h
similarity index 88%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h
index b064aaf..e323652 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h
@@ -22,8 +22,8 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_POLICY_H
-#define LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_POLICY_H
+#ifndef LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_POLICY_H
+#define LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_POLICY_H
 
 #include <vector>
 
@@ -31,29 +31,29 @@
 #include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
 #include "suggest/policyimpl/dictionary/header/header_policy.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/shortcut/ver4_shortcut_list_policy.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/shortcut/ver4_shortcut_list_policy.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_pt_node_array_reader.h"
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 class DicNode;
 namespace backward {
-namespace v401 {
-} // namespace v401
+namespace v402 {
+} // namespace v402
 } // namespace backward
 class DicNodeVector;
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
  public:
@@ -114,8 +114,8 @@
     bool addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
             const BigramProperty *const bigramProperty);
 
-    bool removeNgramEntry(const PrevWordsInfo *const prevWordsInfo, const int *const word,
-            const int length);
+    bool removeNgramEntry(const PrevWordsInfo *const prevWordsInfo, const int *const word1,
+            const int length1);
 
     bool flush(const char *const filePath);
 
@@ -162,7 +162,7 @@
     std::vector<int> mTerminalPtNodePositionsForIteratingWords;
     mutable bool mIsCorrupted;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif // LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_POLICY_H
+#endif // LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_reading_utils.cpp
similarity index 91%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_reading_utils.cpp
index 6cc36fb..80d5311 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_reading_utils.cpp
@@ -21,19 +21,19 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_reading_utils.h"
 
 #include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 /* static */ int Ver4PatriciaTrieReadingUtils::getTerminalIdAndAdvancePosition(
         const uint8_t *const buffer, int *pos) {
     return ByteArrayUtils::readUint32AndAdvancePosition(buffer, pos);
 }
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_reading_utils.h
similarity index 82%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_reading_utils.h
index 7417c26..3579c26 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_reading_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_reading_utils.h
@@ -21,8 +21,8 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_reading_utils.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_READING_UTILS_H
-#define LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_READING_UTILS_H
+#ifndef LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_READING_UTILS_H
+#define LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_READING_UTILS_H
 
 #include <cstdint>
 
@@ -30,13 +30,13 @@
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 class BufferWithExtendableBuffer;
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class Ver4PatriciaTrieReadingUtils {
  public:
@@ -46,7 +46,7 @@
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(Ver4PatriciaTrieReadingUtils);
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_READING_UTILS_H */
+#endif /* LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_READING_UTILS_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.cpp
similarity index 95%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.cpp
index 10f27be..99eed0f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.cpp
@@ -21,26 +21,26 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.h"
 
 #include <cstring>
 #include <queue>
 
 #include "suggest/policyimpl/dictionary/header/header_policy.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/bigram/ver4_bigram_list_policy.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/shortcut/ver4_shortcut_list_policy.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_reader.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_node_writer.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/bigram/ver4_bigram_list_policy.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/shortcut/ver4_shortcut_list_policy.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_pt_node_array_reader.h"
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
 #include "suggest/policyimpl/dictionary/utils/file_utils.h"
 #include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 bool Ver4PatriciaTrieWritingHelper::writeToDictFile(const char *const dictDirPath,
         const int unigramCount, const int bigramCount) const {
@@ -222,13 +222,16 @@
     // Delete unigrams.
     while (static_cast<int>(priorityQueue.size()) > maxUnigramCount) {
         const int ptNodePos = priorityQueue.top().getDictPos();
+        priorityQueue.pop();
         const PtNodeParams ptNodeParams =
                 ptNodeReader->fetchNodeInfoInBufferFromPtNodePos(ptNodePos);
+        if (ptNodeParams.representsNonWordInfo()) {
+            continue;
+        }
         if (!ptNodeWriter->markPtNodeAsWillBecomeNonTerminal(&ptNodeParams)) {
             AKLOGE("Cannot mark PtNode as willBecomeNonterminal. PtNode pos: %d", ptNodePos);
             return false;
         }
-        priorityQueue.pop();
     }
     return true;
 }
@@ -296,6 +299,6 @@
     return mPtNodeWriter->updatePtNodeHasBigramsAndShortcutTargetsFlags(ptNodeParams);
 }
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.h
similarity index 92%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.h
index be44aaa..9034ee6 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_writing_helper.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_writing_helper.h
@@ -21,22 +21,22 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_WRITING_HELPER_H
-#define LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_WRITING_HELPER_H
+#ifndef LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_WRITING_HELPER_H
+#define LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_WRITING_HELPER_H
 
 #include "defines.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_gc_event_listeners.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/content/terminal_position_lookup_table.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/content/terminal_position_lookup_table.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 class HeaderPolicy;
 namespace backward {
-namespace v401 {
+namespace v402 {
 class Ver4DictBuffers;
 class Ver4PatriciaTrieNodeReader;
 class Ver4PatriciaTrieNodeWriter;
@@ -133,8 +133,8 @@
 
     Ver4DictBuffers *const mBuffers;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
 
-#endif /* LATINIME_BACKWARD_V401_VER4_PATRICIA_TRIE_WRITING_HELPER_H */
+#endif /* LATINIME_BACKWARD_V402_VER4_PATRICIA_TRIE_WRITING_HELPER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_pt_node_array_reader.cpp
similarity index 97%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.cpp
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_pt_node_array_reader.cpp
index 33e4e55..537a6d4 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_pt_node_array_reader.cpp
@@ -21,7 +21,7 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.cpp
  */
 
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_pt_node_array_reader.h"
 
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_utils.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h"
@@ -29,7 +29,7 @@
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 bool Ver4PtNodeArrayReader::readPtNodeArrayInfoAndReturnIfValid(const int ptNodeArrayPos,
         int *const outPtNodeCount, int *const outFirstPtNodePos) const {
@@ -85,6 +85,6 @@
     return true;
 }
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_pt_node_array_reader.h
similarity index 86%
rename from native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.h
rename to native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_pt_node_array_reader.h
index 3a7eefa..4f80568 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v401/ver4_pt_node_array_reader.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_pt_node_array_reader.h
@@ -21,21 +21,21 @@
  *   suggest/policyimpl/dictionary/structure/v4/ver4_pt_node_array_reader.h
  */
 
-#ifndef LATINIME_BACKWARD_V401_VER4_PT_NODE_ARRAY_READER_H
-#define LATINIME_BACKWARD_V401_VER4_PT_NODE_ARRAY_READER_H
+#ifndef LATINIME_BACKWARD_V402_VER4_PT_NODE_ARRAY_READER_H
+#define LATINIME_BACKWARD_V402_VER4_PT_NODE_ARRAY_READER_H
 
 #include "defines.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_array_reader.h"
 
 namespace latinime {
 namespace backward {
-namespace v401 {
+namespace v402 {
 
-} // namespace v401
+} // namespace v402
 } // namespace backward
 class BufferWithExtendableBuffer;
 namespace backward {
-namespace v401 {
+namespace v402 {
 
 class Ver4PtNodeArrayReader : public PtNodeArrayReader {
  public:
@@ -51,7 +51,7 @@
 
     const BufferWithExtendableBuffer *const mBuffer;
 };
-} // namespace v401
+} // namespace v402
 } // namespace backward
 } // namespace latinime
-#endif /* LATINIME_BACKWARD_V401_VER4_PT_NODE_ARRAY_READER_H */
+#endif /* LATINIME_BACKWARD_V402_VER4_PT_NODE_ARRAY_READER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
index 93e330a..e4b5fa2 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.cpp
@@ -19,9 +19,9 @@
 #include <climits>
 
 #include "defines.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_constants.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_patricia_trie_policy.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_constants.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h"
 #include "suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h"
 #include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h"
@@ -57,14 +57,13 @@
                 const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap) {
     FormatUtils::FORMAT_VERSION dictFormatVersion = FormatUtils::getFormatVersion(formatVersion);
     switch (dictFormatVersion) {
-        case FormatUtils::VERSION_401: {
-            return newPolicyForOnMemoryV4Dict<backward::v401::Ver4DictConstants,
-                    backward::v401::Ver4DictBuffers,
-                    backward::v401::Ver4DictBuffers::Ver4DictBuffersPtr,
-                    backward::v401::Ver4PatriciaTriePolicy>(
+        case FormatUtils::VERSION_4: {
+            return newPolicyForOnMemoryV4Dict<backward::v402::Ver4DictConstants,
+                    backward::v402::Ver4DictBuffers,
+                    backward::v402::Ver4DictBuffers::Ver4DictBuffersPtr,
+                    backward::v402::Ver4PatriciaTriePolicy>(
                             dictFormatVersion, locale, attributeMap);
         }
-        case FormatUtils::VERSION_4:
         case FormatUtils::VERSION_4_ONLY_FOR_TESTING:
         case FormatUtils::VERSION_4_DEV: {
             return newPolicyForOnMemoryV4Dict<Ver4DictConstants, Ver4DictBuffers,
@@ -116,14 +115,13 @@
         case FormatUtils::VERSION_2:
             AKLOGE("Given path is a directory but the format is version 2. path: %s", path);
             break;
-        case FormatUtils::VERSION_401: {
-            return newPolicyForV4Dict<backward::v401::Ver4DictConstants,
-                    backward::v401::Ver4DictBuffers,
-                    backward::v401::Ver4DictBuffers::Ver4DictBuffersPtr,
-                    backward::v401::Ver4PatriciaTriePolicy>(
+        case FormatUtils::VERSION_4: {
+            return newPolicyForV4Dict<backward::v402::Ver4DictConstants,
+                    backward::v402::Ver4DictBuffers,
+                    backward::v402::Ver4DictBuffers::Ver4DictBuffersPtr,
+                    backward::v402::Ver4PatriciaTriePolicy>(
                             headerFilePath, formatVersion, std::move(mmappedBuffer));
         }
-        case FormatUtils::VERSION_4:
         case FormatUtils::VERSION_4_ONLY_FOR_TESTING:
         case FormatUtils::VERSION_4_DEV: {
             return newPolicyForV4Dict<Ver4DictConstants, Ver4DictBuffers,
@@ -179,7 +177,6 @@
         case FormatUtils::VERSION_2:
             return DictionaryStructureWithBufferPolicy::StructurePolicyPtr(
                     new PatriciaTriePolicy(std::move(mmappedBuffer)));
-        case FormatUtils::VERSION_401:
         case FormatUtils::VERSION_4_ONLY_FOR_TESTING:
         case FormatUtils::VERSION_4:
         case FormatUtils::VERSION_4_DEV:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
index a04551a..4da339b 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
@@ -23,7 +23,7 @@
 #include <sys/types.h>
 
 #include "suggest/policyimpl/dictionary/header/header_policy.h"
-#include "suggest/policyimpl/dictionary/structure/backward/v401/ver4_dict_buffers.h"
+#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_dict_buffers.h"
 #include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_writing_utils.h"
 #include "suggest/policyimpl/dictionary/structure/v4/ver4_dict_buffers.h"
 #include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
@@ -41,12 +41,11 @@
     TimeKeeper::setCurrentTime();
     const FormatUtils::FORMAT_VERSION formatVersion = FormatUtils::getFormatVersion(dictVersion);
     switch (formatVersion) {
-        case FormatUtils::VERSION_401:
-            return createEmptyV4DictFile<backward::v401::Ver4DictConstants,
-                    backward::v401::Ver4DictBuffers,
-                    backward::v401::Ver4DictBuffers::Ver4DictBuffersPtr>(
-                            filePath, localeAsCodePointVector, attributeMap, formatVersion);
         case FormatUtils::VERSION_4:
+            return createEmptyV4DictFile<backward::v402::Ver4DictConstants,
+                    backward::v402::Ver4DictBuffers,
+                    backward::v402::Ver4DictBuffers::Ver4DictBuffersPtr>(
+                            filePath, localeAsCodePointVector, attributeMap, formatVersion);
         case FormatUtils::VERSION_4_ONLY_FOR_TESTING:
         case FormatUtils::VERSION_4_DEV:
             return createEmptyV4DictFile<Ver4DictConstants, Ver4DictBuffers,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp
index 18f5580..1916ea5 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.cpp
@@ -29,8 +29,6 @@
     switch (formatVersion) {
         case VERSION_2:
             return VERSION_2;
-        case VERSION_401:
-            return VERSION_401;
         case VERSION_4_ONLY_FOR_TESTING:
             return VERSION_4_ONLY_FOR_TESTING;
         case VERSION_4:
@@ -52,7 +50,7 @@
     const uint32_t magicNumber = ByteArrayUtils::readUint32(dict, 0);
     switch (magicNumber) {
         case MAGIC_NUMBER:
-            // Version 2 header is as follows:
+            // The layout of the header is as follows:
             // Magic number (4 bytes) 0x9B 0xC1 0x3A 0xFE
             // Dictionary format version number (2 bytes)
             // Options (2 bytes)
@@ -60,19 +58,7 @@
             // Conceptually this converts the hardcoded value of the bytes in the file into
             // the symbolic value we use in the code. But we want the constants to be the
             // same so we use them for both here.
-            if (ByteArrayUtils::readUint16(dict, 4) == VERSION_2) {
-                return VERSION_2;
-            } else if (ByteArrayUtils::readUint16(dict, 4) == VERSION_401) {
-                return VERSION_401;
-            } else if (ByteArrayUtils::readUint16(dict, 4) == VERSION_4_ONLY_FOR_TESTING) {
-                return VERSION_4_ONLY_FOR_TESTING;
-            } else if (ByteArrayUtils::readUint16(dict, 4) == VERSION_4) {
-                return VERSION_4;
-            } else if (ByteArrayUtils::readUint16(dict, 4) == VERSION_4_DEV) {
-                return VERSION_4_DEV;
-            } else {
-                return UNKNOWN_VERSION;
-            }
+            return getFormatVersion(ByteArrayUtils::readUint16(dict, 4));
         default:
             return UNKNOWN_VERSION;
     }
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h
index b05cb2f..55ad579 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/format_utils.h
@@ -32,7 +32,6 @@
         // These MUST have the same values as the relevant constants in FormatSpec.java.
         VERSION_2 = 2,
         VERSION_4_ONLY_FOR_TESTING = 399,
-        VERSION_401 = 401,
         VERSION_4 = 402,
         VERSION_4_DEV = 403,
         UNKNOWN_VERSION = -1
diff --git a/tests/src/com/android/inputmethod/latin/WordComposerTests.java b/tests/src/com/android/inputmethod/latin/WordComposerTests.java
index 274555a..c44544f 100644
--- a/tests/src/com/android/inputmethod/latin/WordComposerTests.java
+++ b/tests/src/com/android/inputmethod/latin/WordComposerTests.java
@@ -40,8 +40,7 @@
         final int[] COORDINATES_WITHIN_BMP =
                 CoordinateUtils.newCoordinateArray(CODEPOINTS_WITHIN_BMP.length,
                         Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
-        final PrevWordsInfo PREV_WORDS_INFO = new PrevWordsInfo("prevword");
-        wc.setComposingWord(CODEPOINTS_WITHIN_BMP, COORDINATES_WITHIN_BMP, PREV_WORDS_INFO);
+        wc.setComposingWord(CODEPOINTS_WITHIN_BMP, COORDINATES_WITHIN_BMP);
         assertEquals(wc.size(), STR_WITHIN_BMP.codePointCount(0, STR_WITHIN_BMP.length()));
         assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
         wc.setCursorPositionWithinWord(2);
@@ -56,15 +55,12 @@
         // Move the cursor to after the 'f'
         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1));
         assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
-        // Check the previous word is still there
-        assertEquals(PREV_WORDS_INFO, wc.getPrevWordsInfoForSuggestion());
         // Move the cursor past the end of the word
         assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(1));
         assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(15));
         // Do what LatinIME does when the cursor is moved outside of the word,
         // and check the behavior is correct.
         wc.reset();
-        assertNull(wc.getPrevWordsInfoForSuggestion().mPrevWord);
 
         // \uD861\uDED7 is 𨛗, a character outside the BMP
         final String STR_WITH_SUPPLEMENTARY_CHAR = "abcde\uD861\uDED7fgh";
@@ -73,8 +69,8 @@
         final int[] COORDINATES_WITH_SUPPLEMENTARY_CHAR =
                 CoordinateUtils.newCoordinateArray(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length,
                         Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
-        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
-                PrevWordsInfo.EMPTY_PREV_WORDS_INFO);
+        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
+                COORDINATES_WITH_SUPPLEMENTARY_CHAR);
         assertEquals(wc.size(), CODEPOINTS_WITH_SUPPLEMENTARY_CHAR.length);
         assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
         wc.setCursorPositionWithinWord(3);
@@ -83,55 +79,43 @@
         assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1));
         assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
-        assertNull(wc.getPrevWordsInfoForSuggestion().mPrevWord);
 
-        final PrevWordsInfo PREV_WORDS_INFO_STR_WITHIN_BMP = new PrevWordsInfo(STR_WITHIN_BMP);
-        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
-                PREV_WORDS_INFO_STR_WITHIN_BMP);
+        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
+                COORDINATES_WITH_SUPPLEMENTARY_CHAR);
         wc.setCursorPositionWithinWord(3);
         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7));
-        assertEquals(PREV_WORDS_INFO_STR_WITHIN_BMP, wc.getPrevWordsInfoForSuggestion());
 
-        final PrevWordsInfo PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR =
-                new PrevWordsInfo(STR_WITH_SUPPLEMENTARY_CHAR);
-        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
-                PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR);
+        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
+                COORDINATES_WITH_SUPPLEMENTARY_CHAR);
         wc.setCursorPositionWithinWord(3);
         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7));
-        assertEquals(PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR,
-                wc.getPrevWordsInfoForSuggestion());
 
-        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
-                PREV_WORDS_INFO_STR_WITHIN_BMP);
+        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
+                COORDINATES_WITH_SUPPLEMENTARY_CHAR);
         wc.setCursorPositionWithinWord(3);
         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-3));
         assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-1));
-        assertEquals(PREV_WORDS_INFO_STR_WITHIN_BMP, wc.getPrevWordsInfoForSuggestion());
 
 
-        final PrevWordsInfo PREV_WORDS_INFO_NULL = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
-        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
-                PREV_WORDS_INFO_NULL);
+        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
+                COORDINATES_WITH_SUPPLEMENTARY_CHAR);
         wc.setCursorPositionWithinWord(3);
         assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-9));
-        assertNull(wc.getPrevWordsInfoForSuggestion().mPrevWord);
 
-        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
-                PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR);
+        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
+                COORDINATES_WITH_SUPPLEMENTARY_CHAR);
         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-10));
-        assertEquals(PREV_WORDS_INFO_STR_WITH_SUPPLEMENTARY_CHAR,
-                wc.getPrevWordsInfoForSuggestion());
 
-        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
-                PREV_WORDS_INFO_NULL);
+        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
+                COORDINATES_WITH_SUPPLEMENTARY_CHAR);
         assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-11));
 
-        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
-                PREV_WORDS_INFO_NULL);
+        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
+                COORDINATES_WITH_SUPPLEMENTARY_CHAR);
         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0));
 
-        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR, COORDINATES_WITH_SUPPLEMENTARY_CHAR,
-                PREV_WORDS_INFO_NULL);
+        wc.setComposingWord(CODEPOINTS_WITH_SUPPLEMENTARY_CHAR,
+                COORDINATES_WITH_SUPPLEMENTARY_CHAR);
         wc.setCursorPositionWithinWord(2);
         assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0));
     }
diff --git a/tests/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerServiceTest.java b/tests/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerServiceTest.java
index 995d7f0..2272d6b 100644
--- a/tests/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerServiceTest.java
+++ b/tests/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerServiceTest.java
@@ -39,7 +39,7 @@
         // it yields 5).
         assertTrue(suggestions.length >= 2);
         // We also assume the top suggestion should be "this".
-        assertEquals("", "this", suggestions[0]);
+        assertEquals("Test basic spell checking", "this", suggestions[0]);
     }
 
     public void testRussianSpellchecker() {
@@ -62,4 +62,21 @@
         // Russian dictionary.
         assertEquals("", "года", suggestions[0]);
     }
+
+    public void testSpellcheckWithPeriods() {
+        changeLanguage("en_US");
+        mEditText.setText("I'm.sure ");
+        mEditText.setSelection(mEditText.getText().length());
+        mEditText.onAttachedToWindow();
+        sleep(1000);
+        runMessages();
+        sleep(1000);
+
+        final SpanGetter span = new SpanGetter(mEditText.getText(), SuggestionSpan.class);
+        // If no span, the following will crash
+        final String[] suggestions = span.getSuggestions();
+        // The first suggestion should be "I'm sure".
+        assertEquals("Test spell checking of mistyped period for space", "I'm sure",
+                suggestions[0]);
+    }
 }
diff --git a/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java b/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java
index bdc608a..cd9a983 100644
--- a/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/utils/StringAndJsonUtilsTests.java
@@ -285,20 +285,6 @@
         assertTrue(bytesStr.equals(bytesStr2));
     }
 
-    public void testContainsOnlyWhitespace() {
-        assertTrue(StringUtils.containsOnlyWhitespace("   "));
-        assertTrue(StringUtils.containsOnlyWhitespace(""));
-        assertTrue(StringUtils.containsOnlyWhitespace("  \n\t\t"));
-        // U+2002 : EN SPACE
-        // U+2003 : EM SPACE
-        // U+3000 : IDEOGRAPHIC SPACE (commonly "double-width space")
-        assertTrue(StringUtils.containsOnlyWhitespace("\u2002\u2003\u3000"));
-        assertFalse(StringUtils.containsOnlyWhitespace("  a "));
-        assertFalse(StringUtils.containsOnlyWhitespace(". "));
-        assertFalse(StringUtils.containsOnlyWhitespace("."));
-        assertTrue(StringUtils.containsOnlyWhitespace(""));
-    }
-
     public void testJsonUtils() {
         final Object[] objs = new Object[] { 1, "aaa", "bbb", 3 };
         final List<Object> objArray = Arrays.asList(objs);