merge in jb-mr1-release history after reset to jb-mr1-dev
diff --git a/java/res/values-en/whitelist.xml b/java/res/values-en/whitelist.xml
deleted file mode 100644
index 2620179..0000000
--- a/java/res/values-en/whitelist.xml
+++ /dev/null
@@ -1,411 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, 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.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!--
-        An entry of the whitelist word should be:
-        1. (int)frequency
-        2. (String)before
-        3. (String)after
-     -->
-    <string-array name="wordlist_whitelist" translatable="false">
-
-        <item>255</item>
-        <item>ill</item>
-        <item>I\'ll</item>
-
-        <!-- TODO: Trim down more entries by removing ones that get auto-corrected by the
-             Android keyboard's own typing error correction algorithms. -->
-
-        <item>255</item>
-        <item>acomodate</item>
-        <item>accommodate</item>
-
-        <item>255</item>
-        <item>aint</item>
-        <item>ain\'t</item>
-
-        <item>255</item>
-        <item>alot</item>
-        <item>a lot</item>
-
-        <item>255</item>
-        <item>andteh</item>
-        <item>and the</item>
-
-        <item>255</item>
-        <item>arent</item>
-        <item>aren\'t</item>
-
-        <item>255</item>
-        <item>bot</item>
-        <item>not</item>
-
-        <item>255</item>
-        <item>bern</item>
-        <item>been</item>
-
-        <item>255</item>
-        <item>bot</item>
-        <item>not</item>
-
-        <item>255</item>
-        <item>bur</item>
-        <item>but</item>
-
-        <item>255</item>
-        <item>cam</item>
-        <item>can</item>
-
-        <item>255</item>
-        <item>cant</item>
-        <item>can\'t</item>
-
-        <item>255</item>
-        <item>dame</item>
-        <item>same</item>
-
-        <item>255</item>
-        <item>didint</item>
-        <item>didn\'t</item>
-
-        <item>255</item>
-        <item>dormer</item>
-        <item>former</item>
-
-        <item>255</item>
-        <item>dud</item>
-        <item>did</item>
-
-        <item>255</item>
-        <item>fay</item>
-        <item>day</item>
-
-        <item>255</item>
-        <item>fife</item>
-        <item>five</item>
-
-        <item>255</item>
-        <item>foo</item>
-        <item>for</item>
-
-        <item>255</item>
-        <item>fora</item>
-        <item>for a</item>
-
-        <item>255</item>
-        <item>galled</item>
-        <item>called</item>
-
-        <item>255</item>
-        <item>goo</item>
-        <item>too</item>
-
-        <item>255</item>
-        <item>hed</item>
-        <item>he\'d</item>
-
-        <item>255</item>
-        <item>hel</item>
-        <item>he\'ll</item>
-
-        <item>255</item>
-        <item>heres</item>
-        <item>here\'s</item>
-
-        <item>255</item>
-        <item>hew</item>
-        <item>new</item>
-
-        <item>255</item>
-        <item>hoe</item>
-        <item>how</item>
-
-        <item>255</item>
-        <item>hoes</item>
-        <item>how\'s</item>
-
-        <item>255</item>
-        <item>howd</item>
-        <item>how\'d</item>
-
-        <item>255</item>
-        <item>howll</item>
-        <item>how\'ll</item>
-
-        <item>255</item>
-        <item>hows</item>
-        <item>how\'s</item>
-
-        <item>255</item>
-        <item>howve</item>
-        <item>how\'ve</item>
-
-        <item>255</item>
-        <item>hum</item>
-        <item>him</item>
-
-        <item>255</item>
-        <item>i</item>
-        <item>I</item>
-
-        <item>255</item>
-        <item>ifs</item>
-        <item>its</item>
-
-        <item>255</item>
-        <item>il</item>
-        <item>I\'ll</item>
-
-        <item>255</item>
-        <item>im</item>
-        <item>I\'m</item>
-
-        <item>255</item>
-        <item>inteh</item>
-        <item>in the</item>
-
-        <item>255</item>
-        <item>itd</item>
-        <item>it\'d</item>
-
-        <item>255</item>
-        <item>itsa</item>
-        <item>it\'s a</item>
-
-        <item>255</item>
-        <item>lets</item>
-        <item>let\'s</item>
-
-        <item>255</item>
-        <item>maam</item>
-        <item>ma\'am</item>
-
-        <item>255</item>
-        <item>manu</item>
-        <item>many</item>
-
-        <item>255</item>
-        <item>mare</item>
-        <item>made</item>
-
-        <item>255</item>
-        <item>mew</item>
-        <item>new</item>
-
-        <item>255</item>
-        <item>mire</item>
-        <item>more</item>
-
-        <item>255</item>
-        <item>moat</item>
-        <item>most</item>
-
-        <item>255</item>
-        <item>mot</item>
-        <item>not</item>
-
-        <item>255</item>
-        <item>mote</item>
-        <item>note</item>
-
-        <item>255</item>
-        <item>motes</item>
-        <item>notes</item>
-
-        <item>255</item>
-        <item>mow</item>
-        <item>now</item>
-
-        <item>255</item>
-        <item>namer</item>
-        <item>named</item>
-
-        <item>255</item>
-        <item>nave</item>
-        <item>have</item>
-
-        <item>255</item>
-        <item>nee</item>
-        <item>new</item>
-
-        <item>255</item>
-        <item>nigh</item>
-        <item>high</item>
-
-        <item>255</item>
-        <item>nit</item>
-        <item>not</item>
-
-        <item>255</item>
-        <item>oft</item>
-        <item>off</item>
-
-        <item>255</item>
-        <item>os</item>
-        <item>is</item>
-
-        <item>255</item>
-        <item>pater</item>
-        <item>later</item>
-
-        <item>255</item>
-        <item>rook</item>
-        <item>took</item>
-
-        <item>255</item>
-        <item>shel</item>
-        <item>she\'ll</item>
-
-        <item>255</item>
-        <item>shouldent</item>
-        <item>shouldn\'t</item>
-
-        <item>255</item>
-        <item>sill</item>
-        <item>will</item>
-
-        <item>255</item>
-        <item>sown</item>
-        <item>down</item>
-
-        <item>255</item>
-        <item>thatd</item>
-        <item>that\'d</item>
-
-        <item>255</item>
-        <item>tine</item>
-        <item>time</item>
-
-        <item>255</item>
-        <item>thong</item>
-        <item>thing</item>
-
-        <item>255</item>
-        <item>tome</item>
-        <item>time</item>
-
-        <!-- through additional proximity, 'uf' becomes 'of'. 'o' is not next to 'u' so anyone
-             typing 'uf' probably meant 'if', but 'of' is much more common and should be left
-             higher than 'if', hence the need for this entry. -->
-        <item>255</item>
-        <item>uf</item>
-        <item>if</item>
-
-        <!-- 'un' becomes 'UN' because of perfect match ; even if we remove 'UN', then 'un'
-             will become 'on' for the same reason as above. So list this here. -->
-        <item>255</item>
-        <item>un</item>
-        <item>in</item>
-
-        <!-- does it really make any sense to have the following here? -->
-        <item>255</item>
-        <item>UnitedStates</item>
-        <item>United States</item>
-
-        <item>255</item>
-        <item>unitedstates</item>
-        <item>United States</item>
-
-        <item>255</item>
-        <item>visavis</item>
-        <item>vis-a-vis</item>
-
-        <item>255</item>
-        <item>wierd</item>
-        <item>weird</item>
-
-        <item>255</item>
-        <item>wel</item>
-        <item>we\'ll</item>
-
-        <item>255</item>
-        <item>wer</item>
-        <item>we\'re</item>
-
-        <item>255</item>
-        <item>whatd</item>
-        <item>what\'d</item>
-
-        <item>255</item>
-        <item>whatm</item>
-        <item>what\'m</item>
-
-        <item>255</item>
-        <item>whatre</item>
-        <item>what\'re</item>
-
-        <item>255</item>
-        <item>whats</item>
-        <item>what\'s</item>
-
-        <item>255</item>
-        <item>whens</item>
-        <item>when\'s</item>
-
-        <item>255</item>
-        <item>whered</item>
-        <item>where\'d</item>
-
-        <item>255</item>
-        <item>wherell</item>
-        <item>where\'ll</item>
-
-        <item>255</item>
-        <item>wheres</item>
-        <item>where\'s</item>
-
-        <item>255</item>
-        <item>wholl</item>
-        <item>who\'ll</item>
-
-        <item>255</item>
-        <item>whove</item>
-        <item>who\'ve</item>
-
-        <item>255</item>
-        <item>whyd</item>
-        <item>why\'d</item>
-
-        <item>255</item>
-        <item>whyll</item>
-        <item>why\'ll</item>
-
-        <item>255</item>
-        <item>whys</item>
-        <item>why\'s</item>
-
-        <item>255</item>
-        <item>whyve</item>
-        <item>why\'ve</item>
-
-        <item>255</item>
-        <item>wont</item>
-        <item>won\'t</item>
-
-        <item>255</item>
-        <item>yall</item>
-        <item>y\'all</item>
-
-        <item>255</item>
-        <item>youd</item>
-        <item>you\'d</item>
-
-    </string-array>
-</resources>
diff --git a/java/res/values-is/strings.xml b/java/res/values-is/strings.xml
new file mode 100644
index 0000000..8d5b007
--- /dev/null
+++ b/java/res/values-is/strings.xml
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for aosp_android_keyboard_ime_name (7877134937939182296) -->
+    <skip />
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <!-- no translation found for english_ime_research_log (8492602295696577851) -->
+    <skip />
+    <!-- no translation found for aosp_spell_checker_service_name (6985142605330377819) -->
+    <skip />
+    <!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
+    <skip />
+    <!-- no translation found for use_contacts_for_spellchecking_option_summary (8754413382543307713) -->
+    <skip />
+    <!-- no translation found for vibrate_on_keypress (5258079494276955460) -->
+    <skip />
+    <!-- no translation found for sound_on_keypress (6093592297198243644) -->
+    <skip />
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <!-- no translation found for general_category (1859088467017573195) -->
+    <skip />
+    <!-- no translation found for correction_category (2236750915056607613) -->
+    <skip />
+    <!-- no translation found for misc_category (6894192814868233453) -->
+    <skip />
+    <!-- no translation found for advanced_settings (362895144495591463) -->
+    <skip />
+    <!-- no translation found for advanced_settings_summary (4487980456152830271) -->
+    <skip />
+    <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
+    <skip />
+    <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
+    <skip />
+    <!-- no translation found for suppress_language_switch_key (8003788410354806368) -->
+    <skip />
+    <!-- no translation found for key_preview_popup_dismiss_delay (6213164897443068248) -->
+    <skip />
+    <!-- no translation found for key_preview_popup_dismiss_no_delay (2096123151571458064) -->
+    <skip />
+    <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) -->
+    <skip />
+    <!-- no translation found for use_contacts_dict (4435317977804180815) -->
+    <skip />
+    <!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
+    <skip />
+    <!-- no translation found for auto_cap (1719746674854628252) -->
+    <skip />
+    <!-- no translation found for configure_dictionaries_title (4238652338556902049) -->
+    <skip />
+    <!-- no translation found for main_dictionary (4798763781818361168) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions (8026799663445531637) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for auto_correction (4979925752001319458) -->
+    <skip />
+    <!-- no translation found for auto_correction_summary (5625751551134658006) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_very_aggeressive (3386782235540547678) -->
+    <skip />
+    <!-- no translation found for bigram_prediction (5809665643352206540) -->
+    <skip />
+    <!-- no translation found for bigram_prediction_summary (3253961591626441019) -->
+    <skip />
+    <!-- no translation found for gesture_input (3310827802759290774) -->
+    <skip />
+    <!-- no translation found for gesture_input_summary (7019742443455085809) -->
+    <skip />
+    <!-- no translation found for gesture_preview_trail (3802333369335722221) -->
+    <skip />
+    <!-- no translation found for gesture_floating_preview_text (6859416520117939680) -->
+    <skip />
+    <!-- no translation found for gesture_floating_preview_text_summary (3333754126434989709) -->
+    <skip />
+    <!-- no translation found for added_word (8993883354622484372) -->
+    <skip />
+    <string name="label_go_key" msgid="1635148082137219148">"Áfram"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Næsta"</string>
+    <string name="label_previous_key" msgid="1211868118071386787">"Fyrra"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Lokið"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Senda"</string>
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <!-- no translation found for label_to_symbol_with_microphone_key (9035925553010061906) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <!-- no translation found for spoken_use_headphones (896961781287283493) -->
+    <skip />
+    <!-- no translation found for spoken_current_text_is (2485723011272583845) -->
+    <skip />
+    <!-- no translation found for spoken_no_text_entered (7479685225597344496) -->
+    <skip />
+    <!-- no translation found for spoken_description_unknown (3197434010402179157) -->
+    <skip />
+    <!-- no translation found for spoken_description_shift (244197883292549308) -->
+    <skip />
+    <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) -->
+    <skip />
+    <!-- no translation found for spoken_description_caps_lock (3276478269526304432) -->
+    <skip />
+    <!-- no translation found for spoken_description_delete (8740376944276199801) -->
+    <skip />
+    <!-- no translation found for spoken_description_to_symbol (5486340107500448969) -->
+    <skip />
+    <!-- no translation found for spoken_description_to_alpha (23129338819771807) -->
+    <skip />
+    <!-- no translation found for spoken_description_to_numeric (591752092685161732) -->
+    <skip />
+    <!-- no translation found for spoken_description_settings (4627462689603838099) -->
+    <skip />
+    <!-- no translation found for spoken_description_tab (2667716002663482248) -->
+    <skip />
+    <!-- no translation found for spoken_description_space (2582521050049860859) -->
+    <skip />
+    <!-- no translation found for spoken_description_mic (615536748882611950) -->
+    <skip />
+    <!-- no translation found for spoken_description_smiley (2256309826200113918) -->
+    <skip />
+    <!-- no translation found for spoken_description_return (8178083177238315647) -->
+    <skip />
+    <!-- no translation found for spoken_description_search (1247236163755920808) -->
+    <skip />
+    <!-- no translation found for spoken_description_dot (40711082435231673) -->
+    <skip />
+    <!-- no translation found for spoken_description_language_switch (5507091328222331316) -->
+    <skip />
+    <!-- no translation found for spoken_description_action_next (8636078276664150324) -->
+    <skip />
+    <!-- no translation found for spoken_description_action_previous (800872415009336208) -->
+    <skip />
+    <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) -->
+    <skip />
+    <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) -->
+    <skip />
+    <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_phone (6520207943132026264) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) -->
+    <skip />
+    <!-- no translation found for voice_input (3583258583521397548) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
+    <skip />
+    <!-- no translation found for configure_input_method (373356270290742459) -->
+    <skip />
+    <!-- no translation found for language_selection_title (1651299598555326750) -->
+    <skip />
+    <!-- no translation found for select_language (3693815588777926848) -->
+    <skip />
+    <!-- no translation found for hint_add_to_dictionary (573678656946085380) -->
+    <skip />
+    <!-- no translation found for has_dictionary (6071847973466625007) -->
+    <skip />
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (8451164783510487501) -->
+    <skip />
+    <!-- no translation found for subtype_en_GB (88170601942311355) -->
+    <skip />
+    <!-- no translation found for subtype_en_US (6160452336634534239) -->
+    <skip />
+    <!-- no translation found for subtype_with_layout_en_GB (2179097748724725906) -->
+    <skip />
+    <!-- no translation found for subtype_with_layout_en_US (1362581347576714579) -->
+    <skip />
+    <!-- no translation found for subtype_no_language (141420857808801746) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_qwertz (1177848172397202890) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_azerty (8721460968141187394) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_dvorak (3122976737669823935) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_colemak (4205992994906097244) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_pcqwerty (8840928374394180189) -->
+    <skip />
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
+    <!-- no translation found for custom_input_style_note_message (8826731320846363423) -->
+    <skip />
+    <!-- no translation found for enable (5031294444630523247) -->
+    <skip />
+    <!-- no translation found for not_now (6172462888202790482) -->
+    <skip />
+    <!-- no translation found for custom_input_style_already_exists (8008728952215449707) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (1261130555134595254) -->
+    <skip />
+    <!-- no translation found for prefs_keypress_vibration_duration_settings (1829950405285211668) -->
+    <skip />
+    <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) -->
+    <skip />
+</resources>
diff --git a/java/res/values-ka/strings.xml b/java/res/values-ka/strings.xml
new file mode 100644
index 0000000..fcb666d
--- /dev/null
+++ b/java/res/values-ka/strings.xml
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for aosp_android_keyboard_ime_name (7877134937939182296) -->
+    <skip />
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <!-- no translation found for english_ime_research_log (8492602295696577851) -->
+    <skip />
+    <!-- no translation found for aosp_spell_checker_service_name (6985142605330377819) -->
+    <skip />
+    <!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
+    <skip />
+    <!-- no translation found for use_contacts_for_spellchecking_option_summary (8754413382543307713) -->
+    <skip />
+    <!-- no translation found for vibrate_on_keypress (5258079494276955460) -->
+    <skip />
+    <!-- no translation found for sound_on_keypress (6093592297198243644) -->
+    <skip />
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <!-- no translation found for general_category (1859088467017573195) -->
+    <skip />
+    <!-- no translation found for correction_category (2236750915056607613) -->
+    <skip />
+    <!-- no translation found for misc_category (6894192814868233453) -->
+    <skip />
+    <!-- no translation found for advanced_settings (362895144495591463) -->
+    <skip />
+    <!-- no translation found for advanced_settings_summary (4487980456152830271) -->
+    <skip />
+    <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
+    <skip />
+    <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
+    <skip />
+    <!-- no translation found for suppress_language_switch_key (8003788410354806368) -->
+    <skip />
+    <!-- no translation found for key_preview_popup_dismiss_delay (6213164897443068248) -->
+    <skip />
+    <!-- no translation found for key_preview_popup_dismiss_no_delay (2096123151571458064) -->
+    <skip />
+    <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) -->
+    <skip />
+    <!-- no translation found for use_contacts_dict (4435317977804180815) -->
+    <skip />
+    <!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
+    <skip />
+    <!-- no translation found for auto_cap (1719746674854628252) -->
+    <skip />
+    <!-- no translation found for configure_dictionaries_title (4238652338556902049) -->
+    <skip />
+    <!-- no translation found for main_dictionary (4798763781818361168) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions (8026799663445531637) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for auto_correction (4979925752001319458) -->
+    <skip />
+    <!-- no translation found for auto_correction_summary (5625751551134658006) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_very_aggeressive (3386782235540547678) -->
+    <skip />
+    <!-- no translation found for bigram_prediction (5809665643352206540) -->
+    <skip />
+    <!-- no translation found for bigram_prediction_summary (3253961591626441019) -->
+    <skip />
+    <!-- no translation found for gesture_input (3310827802759290774) -->
+    <skip />
+    <!-- no translation found for gesture_input_summary (7019742443455085809) -->
+    <skip />
+    <!-- no translation found for gesture_preview_trail (3802333369335722221) -->
+    <skip />
+    <!-- no translation found for gesture_floating_preview_text (6859416520117939680) -->
+    <skip />
+    <!-- no translation found for gesture_floating_preview_text_summary (3333754126434989709) -->
+    <skip />
+    <!-- no translation found for added_word (8993883354622484372) -->
+    <skip />
+    <string name="label_go_key" msgid="1635148082137219148">"გადასვლა"</string>
+    <string name="label_next_key" msgid="362972844525672568">"შემდეგი"</string>
+    <string name="label_previous_key" msgid="1211868118071386787">"წინა"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"შესრულებულია"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"გაგზავნა"</string>
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <!-- no translation found for label_to_symbol_with_microphone_key (9035925553010061906) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <!-- no translation found for spoken_use_headphones (896961781287283493) -->
+    <skip />
+    <!-- no translation found for spoken_current_text_is (2485723011272583845) -->
+    <skip />
+    <!-- no translation found for spoken_no_text_entered (7479685225597344496) -->
+    <skip />
+    <!-- no translation found for spoken_description_unknown (3197434010402179157) -->
+    <skip />
+    <!-- no translation found for spoken_description_shift (244197883292549308) -->
+    <skip />
+    <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) -->
+    <skip />
+    <!-- no translation found for spoken_description_caps_lock (3276478269526304432) -->
+    <skip />
+    <!-- no translation found for spoken_description_delete (8740376944276199801) -->
+    <skip />
+    <!-- no translation found for spoken_description_to_symbol (5486340107500448969) -->
+    <skip />
+    <!-- no translation found for spoken_description_to_alpha (23129338819771807) -->
+    <skip />
+    <!-- no translation found for spoken_description_to_numeric (591752092685161732) -->
+    <skip />
+    <!-- no translation found for spoken_description_settings (4627462689603838099) -->
+    <skip />
+    <!-- no translation found for spoken_description_tab (2667716002663482248) -->
+    <skip />
+    <!-- no translation found for spoken_description_space (2582521050049860859) -->
+    <skip />
+    <!-- no translation found for spoken_description_mic (615536748882611950) -->
+    <skip />
+    <!-- no translation found for spoken_description_smiley (2256309826200113918) -->
+    <skip />
+    <!-- no translation found for spoken_description_return (8178083177238315647) -->
+    <skip />
+    <!-- no translation found for spoken_description_search (1247236163755920808) -->
+    <skip />
+    <!-- no translation found for spoken_description_dot (40711082435231673) -->
+    <skip />
+    <!-- no translation found for spoken_description_language_switch (5507091328222331316) -->
+    <skip />
+    <!-- no translation found for spoken_description_action_next (8636078276664150324) -->
+    <skip />
+    <!-- no translation found for spoken_description_action_previous (800872415009336208) -->
+    <skip />
+    <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) -->
+    <skip />
+    <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) -->
+    <skip />
+    <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_phone (6520207943132026264) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) -->
+    <skip />
+    <!-- no translation found for voice_input (3583258583521397548) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
+    <skip />
+    <!-- no translation found for configure_input_method (373356270290742459) -->
+    <skip />
+    <!-- no translation found for language_selection_title (1651299598555326750) -->
+    <skip />
+    <!-- no translation found for select_language (3693815588777926848) -->
+    <skip />
+    <!-- no translation found for hint_add_to_dictionary (573678656946085380) -->
+    <skip />
+    <!-- no translation found for has_dictionary (6071847973466625007) -->
+    <skip />
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (8451164783510487501) -->
+    <skip />
+    <!-- no translation found for subtype_en_GB (88170601942311355) -->
+    <skip />
+    <!-- no translation found for subtype_en_US (6160452336634534239) -->
+    <skip />
+    <!-- no translation found for subtype_with_layout_en_GB (2179097748724725906) -->
+    <skip />
+    <!-- no translation found for subtype_with_layout_en_US (1362581347576714579) -->
+    <skip />
+    <!-- no translation found for subtype_no_language (141420857808801746) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_qwertz (1177848172397202890) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_azerty (8721460968141187394) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_dvorak (3122976737669823935) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_colemak (4205992994906097244) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_pcqwerty (8840928374394180189) -->
+    <skip />
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
+    <!-- no translation found for custom_input_style_note_message (8826731320846363423) -->
+    <skip />
+    <!-- no translation found for enable (5031294444630523247) -->
+    <skip />
+    <!-- no translation found for not_now (6172462888202790482) -->
+    <skip />
+    <!-- no translation found for custom_input_style_already_exists (8008728952215449707) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (1261130555134595254) -->
+    <skip />
+    <!-- no translation found for prefs_keypress_vibration_duration_settings (1829950405285211668) -->
+    <skip />
+    <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) -->
+    <skip />
+</resources>
diff --git a/java/res/values-mk/strings.xml b/java/res/values-mk/strings.xml
new file mode 100644
index 0000000..7f293e4
--- /dev/null
+++ b/java/res/values-mk/strings.xml
@@ -0,0 +1,263 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for aosp_android_keyboard_ime_name (7877134937939182296) -->
+    <skip />
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <!-- no translation found for english_ime_research_log (8492602295696577851) -->
+    <skip />
+    <!-- no translation found for aosp_spell_checker_service_name (6985142605330377819) -->
+    <skip />
+    <!-- no translation found for use_contacts_for_spellchecking_option_title (5374120998125353898) -->
+    <skip />
+    <!-- no translation found for use_contacts_for_spellchecking_option_summary (8754413382543307713) -->
+    <skip />
+    <!-- no translation found for vibrate_on_keypress (5258079494276955460) -->
+    <skip />
+    <!-- no translation found for sound_on_keypress (6093592297198243644) -->
+    <skip />
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <!-- no translation found for general_category (1859088467017573195) -->
+    <skip />
+    <!-- no translation found for correction_category (2236750915056607613) -->
+    <skip />
+    <!-- no translation found for misc_category (6894192814868233453) -->
+    <skip />
+    <!-- no translation found for advanced_settings (362895144495591463) -->
+    <skip />
+    <!-- no translation found for advanced_settings_summary (4487980456152830271) -->
+    <skip />
+    <!-- no translation found for include_other_imes_in_language_switch_list (4533689960308565519) -->
+    <skip />
+    <!-- no translation found for include_other_imes_in_language_switch_list_summary (840637129103317635) -->
+    <skip />
+    <!-- no translation found for suppress_language_switch_key (8003788410354806368) -->
+    <skip />
+    <!-- no translation found for key_preview_popup_dismiss_delay (6213164897443068248) -->
+    <skip />
+    <!-- no translation found for key_preview_popup_dismiss_no_delay (2096123151571458064) -->
+    <skip />
+    <!-- no translation found for key_preview_popup_dismiss_default_delay (2166964333903906734) -->
+    <skip />
+    <!-- no translation found for use_contacts_dict (4435317977804180815) -->
+    <skip />
+    <!-- no translation found for use_contacts_dict_summary (6599983334507879959) -->
+    <skip />
+    <!-- no translation found for auto_cap (1719746674854628252) -->
+    <skip />
+    <!-- no translation found for configure_dictionaries_title (4238652338556902049) -->
+    <skip />
+    <!-- no translation found for main_dictionary (4798763781818361168) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions (8026799663445531637) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for auto_correction (4979925752001319458) -->
+    <skip />
+    <!-- no translation found for auto_correction_summary (5625751551134658006) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_off (8470882665417944026) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_modest (8788366690620799097) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_aggeressive (3524029103734923819) -->
+    <skip />
+    <!-- no translation found for auto_correction_threshold_mode_very_aggeressive (3386782235540547678) -->
+    <skip />
+    <!-- no translation found for bigram_prediction (5809665643352206540) -->
+    <skip />
+    <!-- no translation found for bigram_prediction_summary (3253961591626441019) -->
+    <skip />
+    <!-- no translation found for gesture_input (3310827802759290774) -->
+    <skip />
+    <!-- no translation found for gesture_input_summary (7019742443455085809) -->
+    <skip />
+    <!-- no translation found for gesture_preview_trail (3802333369335722221) -->
+    <skip />
+    <!-- no translation found for gesture_floating_preview_text (6859416520117939680) -->
+    <skip />
+    <!-- no translation found for gesture_floating_preview_text_summary (3333754126434989709) -->
+    <skip />
+    <!-- no translation found for added_word (8993883354622484372) -->
+    <skip />
+    <string name="label_go_key" msgid="1635148082137219148">"Оди"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Следно"</string>
+    <string name="label_previous_key" msgid="1211868118071386787">"Претходно"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Испрати"</string>
+    <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <!-- no translation found for label_to_symbol_with_microphone_key (9035925553010061906) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <!-- no translation found for spoken_use_headphones (896961781287283493) -->
+    <skip />
+    <!-- no translation found for spoken_current_text_is (2485723011272583845) -->
+    <skip />
+    <!-- no translation found for spoken_no_text_entered (7479685225597344496) -->
+    <skip />
+    <!-- no translation found for spoken_description_unknown (3197434010402179157) -->
+    <skip />
+    <!-- no translation found for spoken_description_shift (244197883292549308) -->
+    <skip />
+    <!-- no translation found for spoken_description_shift_shifted (1681877323344195035) -->
+    <skip />
+    <!-- no translation found for spoken_description_caps_lock (3276478269526304432) -->
+    <skip />
+    <!-- no translation found for spoken_description_delete (8740376944276199801) -->
+    <skip />
+    <!-- no translation found for spoken_description_to_symbol (5486340107500448969) -->
+    <skip />
+    <!-- no translation found for spoken_description_to_alpha (23129338819771807) -->
+    <skip />
+    <!-- no translation found for spoken_description_to_numeric (591752092685161732) -->
+    <skip />
+    <!-- no translation found for spoken_description_settings (4627462689603838099) -->
+    <skip />
+    <!-- no translation found for spoken_description_tab (2667716002663482248) -->
+    <skip />
+    <!-- no translation found for spoken_description_space (2582521050049860859) -->
+    <skip />
+    <!-- no translation found for spoken_description_mic (615536748882611950) -->
+    <skip />
+    <!-- no translation found for spoken_description_smiley (2256309826200113918) -->
+    <skip />
+    <!-- no translation found for spoken_description_return (8178083177238315647) -->
+    <skip />
+    <!-- no translation found for spoken_description_search (1247236163755920808) -->
+    <skip />
+    <!-- no translation found for spoken_description_dot (40711082435231673) -->
+    <skip />
+    <!-- no translation found for spoken_description_language_switch (5507091328222331316) -->
+    <skip />
+    <!-- no translation found for spoken_description_action_next (8636078276664150324) -->
+    <skip />
+    <!-- no translation found for spoken_description_action_previous (800872415009336208) -->
+    <skip />
+    <!-- no translation found for spoken_description_shiftmode_on (5700440798609574589) -->
+    <skip />
+    <!-- no translation found for spoken_description_shiftmode_locked (593175803181701830) -->
+    <skip />
+    <!-- no translation found for spoken_description_shiftmode_off (657219998449174808) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_symbol (7183343879909747642) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_alpha (3528307674390156956) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_phone (6520207943132026264) -->
+    <skip />
+    <!-- no translation found for spoken_description_mode_phone_shift (5499629753962641227) -->
+    <skip />
+    <!-- no translation found for voice_input (3583258583521397548) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_main_keyboard (3360660341121083174) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_symbols_keyboard (7203213240786084067) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_off (3745699748218082014) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_summary_main_keyboard (6586544292900314339) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_summary_symbols_keyboard (5233725927281932391) -->
+    <skip />
+    <!-- no translation found for voice_input_modes_summary_off (63875609591897607) -->
+    <skip />
+    <!-- no translation found for configure_input_method (373356270290742459) -->
+    <skip />
+    <!-- no translation found for language_selection_title (1651299598555326750) -->
+    <skip />
+    <!-- no translation found for select_language (3693815588777926848) -->
+    <skip />
+    <!-- no translation found for hint_add_to_dictionary (573678656946085380) -->
+    <skip />
+    <!-- no translation found for has_dictionary (6071847973466625007) -->
+    <skip />
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (8451164783510487501) -->
+    <skip />
+    <!-- no translation found for subtype_en_GB (88170601942311355) -->
+    <skip />
+    <!-- no translation found for subtype_en_US (6160452336634534239) -->
+    <skip />
+    <!-- no translation found for subtype_with_layout_en_GB (2179097748724725906) -->
+    <skip />
+    <!-- no translation found for subtype_with_layout_en_US (1362581347576714579) -->
+    <skip />
+    <!-- no translation found for subtype_no_language (141420857808801746) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_qwerty (2956121451616633133) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_qwertz (1177848172397202890) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_azerty (8721460968141187394) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_dvorak (3122976737669823935) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_colemak (4205992994906097244) -->
+    <skip />
+    <!-- no translation found for subtype_no_language_pcqwerty (8840928374394180189) -->
+    <skip />
+    <!-- no translation found for custom_input_styles_title (8429952441821251512) -->
+    <skip />
+    <!-- no translation found for add_style (6163126614514489951) -->
+    <skip />
+    <!-- no translation found for add (8299699805688017798) -->
+    <skip />
+    <!-- no translation found for remove (4486081658752944606) -->
+    <skip />
+    <!-- no translation found for save (7646738597196767214) -->
+    <skip />
+    <!-- no translation found for subtype_locale (8576443440738143764) -->
+    <skip />
+    <!-- no translation found for keyboard_layout_set (4309233698194565609) -->
+    <skip />
+    <!-- no translation found for custom_input_style_note_message (8826731320846363423) -->
+    <skip />
+    <!-- no translation found for enable (5031294444630523247) -->
+    <skip />
+    <!-- no translation found for not_now (6172462888202790482) -->
+    <skip />
+    <!-- no translation found for custom_input_style_already_exists (8008728952215449707) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (1261130555134595254) -->
+    <skip />
+    <!-- no translation found for prefs_keypress_vibration_duration_settings (1829950405285211668) -->
+    <skip />
+    <!-- no translation found for prefs_keypress_sound_volume_settings (5875933757082305040) -->
+    <skip />
+</resources>
diff --git a/java/res/values/whitelist.xml b/java/res/values/whitelist.xml
deleted file mode 100644
index d4ecbfa..0000000
--- a/java/res/values/whitelist.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, 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.
-*/
--->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!--
-        An entry of the whitelist word should be:
-        1. (int)frequency
-        2. (String)before
-        3. (String)after
-     -->
-    <string-array name="wordlist_whitelist">
-    </string-array>
-</resources>
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 9198500..489cc37 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -283,9 +283,10 @@
             public void load(String[] data) {
                 final int dataLength = data.length;
                 if (dataLength % TOUCH_POSITION_CORRECTION_RECORD_SIZE != 0) {
-                    if (LatinImeLogger.sDBG)
+                    if (LatinImeLogger.sDBG) {
                         throw new RuntimeException(
                                 "the size of touch position correction data is invalid");
+                    }
                     return;
                 }
 
@@ -324,7 +325,7 @@
 
             public boolean isValid() {
                 return mEnabled && mXs != null && mYs != null && mRadii != null
-                    && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0;
+                        && mXs.length > 0 && mYs.length > 0 && mRadii.length > 0;
             }
         }
 
@@ -870,10 +871,12 @@
             final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
                     R.styleable.Keyboard);
             try {
-                if (a.hasValue(R.styleable.Keyboard_horizontalGap))
+                if (a.hasValue(R.styleable.Keyboard_horizontalGap)) {
                     throw new XmlParseUtils.IllegalAttribute(parser, "horizontalGap");
-                if (a.hasValue(R.styleable.Keyboard_verticalGap))
+                }
+                if (a.hasValue(R.styleable.Keyboard_verticalGap)) {
                     throw new XmlParseUtils.IllegalAttribute(parser, "verticalGap");
+                }
                 return new Row(mResources, mParams, parser, mCurrentY);
             } finally {
                 a.recycle();
@@ -921,7 +924,9 @@
                 throws XmlPullParserException, IOException {
             if (skip) {
                 XmlParseUtils.checkEndTag(TAG_KEY, parser);
-                if (DEBUG) startEndTag("<%s /> skipped", TAG_KEY);
+                if (DEBUG) {
+                    startEndTag("<%s /> skipped", TAG_KEY);
+                }
             } else {
                 final Key key = new Key(mResources, mParams, row, parser);
                 if (DEBUG) {
@@ -1099,9 +1104,9 @@
 
         private boolean parseCaseCondition(XmlPullParser parser) {
             final KeyboardId id = mParams.mId;
-            if (id == null)
+            if (id == null) {
                 return true;
-
+            }
             final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
                     R.styleable.Keyboard_Case);
             try {
@@ -1205,9 +1210,9 @@
             // If <case> does not have "index" attribute, that means this <case> is wild-card for
             // the attribute.
             final TypedValue v = a.peekValue(index);
-            if (v == null)
+            if (v == null) {
                 return true;
-
+            }
             if (isIntegerValue(v)) {
                 return intValue == a.getInt(index, 0);
             } else if (isStringValue(v)) {
@@ -1218,8 +1223,9 @@
 
         private static boolean stringArrayContains(String[] array, String value) {
             for (final String elem : array) {
-                if (elem.equals(value))
+                if (elem.equals(value)) {
                     return true;
+                }
             }
             return false;
         }
@@ -1242,16 +1248,18 @@
             TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser),
                     R.styleable.Keyboard_Key);
             try {
-                if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName))
+                if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName)) {
                     throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE
                             + "/> needs styleName attribute", parser);
+                }
                 if (DEBUG) {
                     startEndTag("<%s styleName=%s />%s", TAG_KEY_STYLE,
-                        keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName),
-                        skip ? " skipped" : "");
+                            keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName),
+                            skip ? " skipped" : "");
                 }
-                if (!skip)
+                if (!skip) {
                     mParams.mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser);
+                }
             } finally {
                 keyStyleAttr.recycle();
                 keyAttrs.recycle();
@@ -1272,8 +1280,9 @@
         }
 
         private void endRow(Row row) {
-            if (mCurrentRow == null)
+            if (mCurrentRow == null) {
                 throw new InflateException("orphan end row tag");
+            }
             if (mRightEdgeKey != null) {
                 mRightEdgeKey.markAsRightEdge(mParams);
                 mRightEdgeKey = null;
@@ -1309,8 +1318,9 @@
         public static float getDimensionOrFraction(TypedArray a, int index, int base,
                 float defValue) {
             final TypedValue value = a.peekValue(index);
-            if (value == null)
+            if (value == null) {
                 return defValue;
+            }
             if (isFractionValue(value)) {
                 return a.getFraction(index, base, base, defValue);
             } else if (isDimensionValue(value)) {
@@ -1321,8 +1331,9 @@
 
         public static int getEnumValue(TypedArray a, int index, int defValue) {
             final TypedValue value = a.peekValue(index);
-            if (value == null)
+            if (value == null) {
                 return defValue;
+            }
             if (isIntegerValue(value)) {
                 return a.getInt(index, defValue);
             }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index fcf97b9..ccbb081 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -362,9 +362,9 @@
 
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
-
         mKeyDrawParams = new KeyDrawParams(a);
         mKeyPreviewDrawParams = new KeyPreviewDrawParams(a, mKeyDrawParams);
+        mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout;
         mKeyPreviewLayoutId = a.getResourceId(R.styleable.KeyboardView_keyPreviewLayout, 0);
         if (mKeyPreviewLayoutId == 0) {
             mShowKeyPreviewPopup = false;
@@ -373,11 +373,9 @@
                 R.styleable.KeyboardView_verticalCorrection, 0);
         mMoreKeysLayout = a.getResourceId(R.styleable.KeyboardView_moreKeysLayout, 0);
         mBackgroundDimAlpha = a.getInt(R.styleable.KeyboardView_backgroundDimAlpha, 0);
-        mPreviewPlacerView = new PreviewPlacerView(context, a);
         a.recycle();
 
-        mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout;
-
+        mPreviewPlacerView = new PreviewPlacerView(context, attrs);
         mPaint.setAntiAlias(true);
     }
 
@@ -462,12 +460,7 @@
         if (bufferNeedsUpdates || mOffscreenBuffer == null) {
             if (maybeAllocateOffscreenBuffer()) {
                 mInvalidateAllKeys = true;
-                // TODO: Stop using the offscreen canvas even when in software rendering
-                if (mOffscreenCanvas != null) {
-                    mOffscreenCanvas.setBitmap(mOffscreenBuffer);
-                } else {
-                    mOffscreenCanvas = new Canvas(mOffscreenBuffer);
-                }
+                maybeCreateOffscreenCanvas();
             }
             onDrawKeyboard(mOffscreenCanvas);
         }
@@ -496,6 +489,15 @@
         }
     }
 
+    private void maybeCreateOffscreenCanvas() {
+        // TODO: Stop using the offscreen canvas even when in software rendering
+        if (mOffscreenCanvas != null) {
+            mOffscreenCanvas.setBitmap(mOffscreenBuffer);
+        } else {
+            mOffscreenCanvas = new Canvas(mOffscreenBuffer);
+        }
+    }
+
     private void onDrawKeyboard(final Canvas canvas) {
         if (mKeyboard == null) return;
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
index d0fecf0..59a92d6 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
@@ -23,6 +23,7 @@
 import android.graphics.Paint.Align;
 import android.os.Message;
 import android.text.TextUtils;
+import android.util.AttributeSet;
 import android.util.SparseArray;
 import android.widget.RelativeLayout;
 
@@ -49,6 +50,9 @@
     private final SparseArray<PointerTracker> mPointers = new SparseArray<PointerTracker>();
 
     private String mGestureFloatingPreviewText;
+    private int mLastPointerX;
+    private int mLastPointerY;
+
     private boolean mDrawsGesturePreviewTrail;
     private boolean mDrawsGestureFloatingPreviewText;
 
@@ -89,10 +93,16 @@
         }
     }
 
-    public PreviewPlacerView(Context context, TypedArray keyboardViewAttr) {
+    public PreviewPlacerView(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.keyboardViewStyle);
+    }
+
+    public PreviewPlacerView(Context context, AttributeSet attrs, int defStyle) {
         super(context);
         setWillNotDraw(false);
 
+        final TypedArray keyboardViewAttr = context.obtainStyledAttributes(
+                attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
         final int gestureFloatingPreviewTextSize = keyboardViewAttr.getDimensionPixelSize(
                 R.styleable.KeyboardView_gestureFloatingPreviewTextSize, 0);
         mGestureFloatingPreviewTextColor = keyboardViewAttr.getColor(
@@ -117,6 +127,7 @@
                 R.styleable.KeyboardView_gesturePreviewTrailColor, 0);
         final int gesturePreviewTrailWidth = keyboardViewAttr.getDimensionPixelSize(
                 R.styleable.KeyboardView_gesturePreviewTrailWidth, 0);
+        keyboardViewAttr.recycle();
 
         mGesturePaint = new Paint();
         mGesturePaint.setAntiAlias(true);
@@ -146,31 +157,30 @@
     public void invalidatePointer(PointerTracker tracker) {
         synchronized (mPointers) {
             mPointers.put(tracker.mPointerId, tracker);
-            // TODO: Should narrow the invalidate region.
-            invalidate();
         }
+        mLastPointerX = tracker.getLastX();
+        mLastPointerY = tracker.getLastY();
+        // TODO: Should narrow the invalidate region.
+        invalidate();
     }
 
     @Override
     public void onDraw(Canvas canvas) {
         super.onDraw(canvas);
-        synchronized (mPointers) {
-            canvas.translate(mXOrigin, mYOrigin);
-            final int trackerCount = mPointers.size();
-            boolean hasDrawnFloatingPreviewText = false;
-            for (int index = 0; index < trackerCount; index++) {
-                final PointerTracker tracker = mPointers.valueAt(index);
-                if (mDrawsGesturePreviewTrail) {
+        canvas.translate(mXOrigin, mYOrigin);
+        if (mDrawsGesturePreviewTrail) {
+            synchronized (mPointers) {
+                final int trackerCount = mPointers.size();
+                for (int index = 0; index < trackerCount; index++) {
+                    final PointerTracker tracker = mPointers.valueAt(index);
                     tracker.drawGestureTrail(canvas, mGesturePaint);
                 }
-                // TODO: Figure out more cleaner way to draw gesture preview text.
-                if (mDrawsGestureFloatingPreviewText && !hasDrawnFloatingPreviewText) {
-                    drawGestureFloatingPreviewText(canvas, tracker, mGestureFloatingPreviewText);
-                    hasDrawnFloatingPreviewText = true;
-                }
             }
-            canvas.translate(-mXOrigin, -mYOrigin);
         }
+        if (mDrawsGestureFloatingPreviewText) {
+            drawGestureFloatingPreviewText(canvas, mGestureFloatingPreviewText);
+        }
+        canvas.translate(-mXOrigin, -mYOrigin);
     }
 
     public void setGestureFloatingPreviewText(String gestureFloatingPreviewText) {
@@ -186,15 +196,16 @@
         mDrawingHandler.cancelAllMessages();
     }
 
-    private void drawGestureFloatingPreviewText(Canvas canvas, PointerTracker tracker,
-            String gestureFloatingPreviewText) {
+    private void drawGestureFloatingPreviewText(Canvas canvas, String gestureFloatingPreviewText) {
         if (TextUtils.isEmpty(gestureFloatingPreviewText)) {
             return;
         }
 
         final Paint paint = mTextPaint;
-        final int lastX = tracker.getLastX();
-        final int lastY = tracker.getLastY();
+        // TODO: Figure out how we should deal with the floating preview text with multiple moving
+        // fingers.
+        final int lastX = mLastPointerX;
+        final int lastY = mLastPointerY;
         final int textSize = (int)paint.getTextSize();
         final int canvasWidth = canvas.getWidth();
 
diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java
index 0481668..01ba300 100644
--- a/java/src/com/android/inputmethod/latin/AutoCorrection.java
+++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java
@@ -39,7 +39,6 @@
         }
         final CharSequence lowerCasedWord = word.toString().toLowerCase();
         for (final String key : dictionaries.keySet()) {
-            if (key.equals(Dictionary.TYPE_WHITELIST)) continue;
             final Dictionary dictionary = dictionaries.get(key);
             // It's unclear how realistically 'dictionary' can be null, but the monkey is somehow
             // managing to get null in here. Presumably the language is changing to a language with
@@ -64,7 +63,6 @@
         }
         int maxFreq = -1;
         for (final String key : dictionaries.keySet()) {
-            if (key.equals(Dictionary.TYPE_WHITELIST)) continue;
             final Dictionary dictionary = dictionaries.get(key);
             if (null == dictionary) continue;
             final int tempFreq = dictionary.getFrequency(word);
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index cdaffa6..2d9e0ce 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -64,18 +64,21 @@
 
     private final SparseArray<DicTraverseSession> mDicTraverseSessions =
             new SparseArray<DicTraverseSession>();
+
+    // TODO: There should be a way to remove used DicTraverseSession objects from
+    // {@code mDicTraverseSessions}.
     private DicTraverseSession getTraverseSession(int traverseSessionId) {
-        DicTraverseSession traverseSession = mDicTraverseSessions.get(traverseSessionId);
-        if (traverseSession == null) {
-            synchronized(mDicTraverseSessions) {
+        synchronized(mDicTraverseSessions) {
+            DicTraverseSession traverseSession = mDicTraverseSessions.get(traverseSessionId);
+            if (traverseSession == null) {
                 traverseSession = mDicTraverseSessions.get(traverseSessionId);
                 if (traverseSession == null) {
                     traverseSession = new DicTraverseSession(mLocale, mNativeDict);
                     mDicTraverseSessions.put(traverseSessionId, traverseSession);
                 }
             }
+            return traverseSession;
         }
-        return traverseSession;
     }
 
     /**
@@ -162,7 +165,7 @@
             if (composerSize > 0 && mOutputScores[j] < 1) break;
             final int start = j * MAX_WORD_LENGTH;
             int len = 0;
-            while (len <  MAX_WORD_LENGTH && mOutputChars[start + len] != 0) {
+            while (len < MAX_WORD_LENGTH && mOutputChars[start + len] != 0) {
                 ++len;
             }
             if (len > 0) {
@@ -209,18 +212,20 @@
     }
 
     @Override
-    public synchronized void close() {
-        for (int i = 0; i < mDicTraverseSessions.size(); ++i) {
-            final int key = mDicTraverseSessions.keyAt(i);
-            final DicTraverseSession traverseSession = mDicTraverseSessions.get(key);
-            if (traverseSession != null) {
-                traverseSession.close();
+    public void close() {
+        synchronized (mDicTraverseSessions) {
+            final int sessionsSize = mDicTraverseSessions.size();
+            for (int index = 0; index < sessionsSize; ++index) {
+                final DicTraverseSession traverseSession = mDicTraverseSessions.valueAt(index);
+                if (traverseSession != null) {
+                    traverseSession.close();
+                }
             }
         }
         closeInternal();
     }
 
-    private void closeInternal() {
+    private synchronized void closeInternal() {
         if (mNativeDict != 0) {
             closeNative(mNativeDict);
             mNativeDict = 0;
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 063243e..dd11aaa 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -16,6 +16,8 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
+
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -23,6 +25,7 @@
 import android.util.Log;
 
 import java.io.File;
+import java.io.RandomAccessFile;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Locale;
@@ -51,6 +54,9 @@
     private static final String MAIN_DICTIONARY_CATEGORY = "main";
     public static final String ID_CATEGORY_SEPARATOR = ":";
 
+    // The key considered to read the version attribute in a dictionary file.
+    private static String VERSION_KEY = "version";
+
     // Prevents this from being instantiated
     private BinaryDictionaryGetter() {}
 
@@ -336,6 +342,42 @@
         return MAIN_DICTIONARY_CATEGORY.equals(idArray[0]);
     }
 
+    // ## HACK ## we prevent usage of a dictionary before version 18 for English only. The reason
+    // for this is, since those do not include whitelist entries, the new code with an old version
+    // of the dictionary would lose whitelist functionality.
+    private static boolean hackCanUseDictionaryFile(final Locale locale, final File f) {
+        // Only for English - other languages didn't have a whitelist, hence this
+        // ad-hock ## HACK ##
+        if (!Locale.ENGLISH.getLanguage().equals(locale.getLanguage())) return true;
+
+        try {
+            // Read the version of the file
+            final RandomAccessFile raf = new RandomAccessFile(f, "r");
+            final int magic = raf.readInt();
+            if (magic != BinaryDictInputOutput.VERSION_2_MAGIC_NUMBER) {
+                return false;
+            }
+            final int formatVersion = raf.readInt();
+            final int headerSize = raf.readInt();
+            final HashMap<String, String> options = new HashMap<String, String>();
+            BinaryDictInputOutput.populateOptionsFromFile(raf, headerSize, options);
+            final String version = options.get(VERSION_KEY);
+            if (null == version) {
+                // No version in the options : the format is unexpected
+                return false;
+            }
+            // Version 18 is the first one to include the whitelist
+            // Obviously this is a big ## HACK ##
+            return Integer.parseInt(version) >= 18;
+        } catch (java.io.FileNotFoundException e) {
+            return false;
+        } catch (java.io.IOException e) {
+            return false;
+        } catch (NumberFormatException e) {
+            return false;
+        }
+    }
+
     /**
      * Returns a list of file addresses for a given locale, trying relevant methods in order.
      *
@@ -366,14 +408,15 @@
         // cachedWordLists may not be null, see doc for getCachedDictionaryList
         for (final File f : cachedWordLists) {
             final String wordListId = getWordListIdFromFileName(f.getName());
-            if (isMainWordListId(wordListId)) {
+            final boolean canUse = f.canRead() && hackCanUseDictionaryFile(locale, f);
+            if (canUse && isMainWordListId(wordListId)) {
                 foundMainDict = true;
             }
             if (!dictPackSettings.isWordListActive(wordListId)) continue;
-            if (f.canRead()) {
+            if (canUse) {
                 fileList.add(AssetFileAddress.makeFromFileName(f.getPath()));
             } else {
-                Log.e(TAG, "Found a cached dictionary file but cannot read it");
+                Log.e(TAG, "Found a cached dictionary file but cannot read or use it");
             }
         }
 
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 2565dfc..88d0c09 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -42,7 +42,6 @@
     public static final String TYPE_USER = "user";
     // User history dictionary internal to LatinIME.
     public static final String TYPE_USER_HISTORY = "history";
-    public static final String TYPE_WHITELIST ="whitelist";
     protected final String mDictType;
 
     public Dictionary(final String dictType) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 884e6db..a7896ad 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1696,6 +1696,7 @@
 
         Utils.Stats.onSeparator((char)primaryCode, x, y);
 
+        mHandler.postUpdateShiftState();
         return didAutoCorrect;
     }
 
@@ -2001,6 +2002,7 @@
 
     private CharSequence addToUserHistoryDictionary(final CharSequence suggestion) {
         if (TextUtils.isEmpty(suggestion)) return null;
+        if (mSuggest == null) return null;
 
         // If correction is not enabled, we don't add words to the user history dictionary.
         // That's to avoid unintended additions in some sensitive fields, or fields that
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 1f43c6d..e931408 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -50,7 +50,6 @@
 
     private Dictionary mMainDictionary;
     private ContactsBinaryDictionary mContactsDict;
-    private WhitelistDictionary mWhiteListDictionary;
     private final ConcurrentHashMap<String, Dictionary> mDictionaries =
             new ConcurrentHashMap<String, Dictionary>();
 
@@ -74,21 +73,11 @@
         mLocale = locale;
         mMainDictionary = mainDict;
         addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_MAIN, mainDict);
-        initWhitelistAndAutocorrectAndPool(context, locale);
-    }
-
-    private void initWhitelistAndAutocorrectAndPool(final Context context, final Locale locale) {
-        mWhiteListDictionary = new WhitelistDictionary(context, locale);
-        addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_WHITELIST, mWhiteListDictionary);
     }
 
     private void initAsynchronously(final Context context, final Locale locale,
             final SuggestInitializationListener listener) {
         resetMainDict(context, locale, listener);
-
-        // TODO: read the whitelist and init the pool asynchronously too.
-        // initPool should be done asynchronously now that the pool is thread-safe.
-        initWhitelistAndAutocorrectAndPool(context, locale);
     }
 
     private static void addOrReplaceDictionary(
@@ -216,15 +205,6 @@
                     wordComposerForLookup, prevWordForBigram, proximityInfo));
         }
 
-        final CharSequence whitelistedWordFromWhitelistDictionary =
-                mWhiteListDictionary.getWhitelistedWord(consideredWord);
-        if (whitelistedWordFromWhitelistDictionary != null) {
-            // MAX_SCORE ensures this will be considered strong enough to be auto-corrected
-            suggestionsSet.add(new SuggestedWordInfo(whitelistedWordFromWhitelistDictionary,
-                    SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_WHITELIST,
-                    Dictionary.TYPE_WHITELIST));
-        }
-
         final CharSequence whitelistedWord;
         if (suggestionsSet.isEmpty()) {
             whitelistedWord = null;
@@ -234,11 +214,6 @@
             whitelistedWord = suggestionsSet.first().mWord;
         }
 
-        // TODO: Change this scheme - a boolean is not enough. A whitelisted word may be "valid"
-        // but still autocorrected from - in the case the whitelist only capitalizes the word.
-        // The whitelist should be case-insensitive, so it's not possible to be consistent with
-        // a boolean flag. Right now this is handled with a slight hack in
-        // WhitelistDictionary#shouldForciblyAutoCorrectFrom.
         final boolean allowsToBeAutoCorrected = (null != whitelistedWord
                 && !whitelistedWord.equals(consideredWord))
                 || AutoCorrection.isNotAWord(mDictionaries, consideredWord,
@@ -320,9 +295,10 @@
 
         // At second character typed, search the unigrams (scores being affected by bigrams)
         for (final String key : mDictionaries.keySet()) {
-            // Skip UserUnigramDictionary and WhitelistDictionary to lookup
-            if (key.equals(Dictionary.TYPE_USER_HISTORY)
-                    || key.equals(Dictionary.TYPE_WHITELIST)) {
+            // Skip User history dictionary for lookup
+            // TODO: The user history dictionary should just override getSuggestionsWithSessionId
+            // to make sure it doesn't return anything and we should remove this test
+            if (key.equals(Dictionary.TYPE_USER_HISTORY)) {
                 continue;
             }
             final Dictionary dictionary = mDictionaries.get(key);
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
index 3bb670c..d516e72 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
@@ -52,14 +52,14 @@
     private static final int FREQUENCY_FOR_TYPED = 2;
 
     /** Maximum number of pairs. Pruning will start when databases goes above this number. */
-    private static int sMaxHistoryBigrams = 10000;
+    public static final int sMaxHistoryBigrams = 10000;
 
     /**
      * When it hits maximum bigram pair, it will delete until you are left with
      * only (sMaxHistoryBigrams - sDeleteHistoryBigrams) pairs.
      * Do not keep this number small to avoid deleting too often.
      */
-    private static int sDeleteHistoryBigrams = 1000;
+    public static final int sDeleteHistoryBigrams = 1000;
 
     /**
      * Database version should increase if the database structure changes
@@ -109,12 +109,8 @@
 
     private static DatabaseHelper sOpenHelper = null;
 
-    public void setDatabaseMax(int maxHistoryBigram) {
-        sMaxHistoryBigrams = maxHistoryBigram;
-    }
-
-    public void setDatabaseDelete(int deleteHistoryBigram) {
-        sDeleteHistoryBigrams = deleteHistoryBigram;
+    public String getLocale() {
+        return mLocale;
     }
 
     public synchronized static UserHistoryDictionary getInstance(
@@ -502,9 +498,11 @@
                                     needsToSave(fc, isValid, addLevel0Bigram)) {
                                 freq = fc;
                             } else {
+                                // Delete this entry
                                 freq = -1;
                             }
                         } else {
+                            // Delete this entry
                             freq = -1;
                         }
                     }
@@ -541,6 +539,7 @@
                                     getContentValues(word1, word2, mLocale));
                             pairId = pairIdLong.intValue();
                         }
+                        // Eliminate freq == 0 because that word is profanity.
                         if (freq > 0) {
                             if (PROFILE_SAVE_RESTORE) {
                                 ++profInsert;
diff --git a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java b/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
deleted file mode 100644
index 14476dc..0000000
--- a/java/src/com/android/inputmethod/latin/WhitelistDictionary.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.inputmethod.latin;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.inputmethod.keyboard.ProximityInfo;
-import com.android.inputmethod.latin.LocaleUtils.RunInLocale;
-import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Locale;
-
-public class WhitelistDictionary extends ExpandableDictionary {
-
-    private static final boolean DBG = LatinImeLogger.sDBG;
-    private static final String TAG = WhitelistDictionary.class.getSimpleName();
-
-    private final HashMap<String, Pair<Integer, String>> mWhitelistWords =
-            new HashMap<String, Pair<Integer, String>>();
-
-    // TODO: Conform to the async load contact of ExpandableDictionary
-    public WhitelistDictionary(final Context context, final Locale locale) {
-        super(context, Dictionary.TYPE_WHITELIST);
-        // TODO: Move whitelist dictionary into main dictionary.
-        final RunInLocale<Void> job = new RunInLocale<Void>() {
-            @Override
-            protected Void job(Resources res) {
-                initWordlist(res.getStringArray(R.array.wordlist_whitelist));
-                return null;
-            }
-        };
-        job.runInLocale(context.getResources(), locale);
-    }
-
-    private void initWordlist(String[] wordlist) {
-        mWhitelistWords.clear();
-        final int N = wordlist.length;
-        if (N % 3 != 0) {
-            if (DBG) {
-                Log.d(TAG, "The number of the whitelist is invalid.");
-            }
-            return;
-        }
-        try {
-            for (int i = 0; i < N; i += 3) {
-                final int score = Integer.valueOf(wordlist[i]);
-                final String before = wordlist[i + 1];
-                final String after = wordlist[i + 2];
-                if (before != null && after != null) {
-                    mWhitelistWords.put(
-                            before.toLowerCase(), new Pair<Integer, String>(score, after));
-                    addWord(after, null /* shortcut */, score);
-                }
-            }
-        } catch (NumberFormatException e) {
-            if (DBG) {
-                Log.d(TAG, "The score of the word is invalid.");
-            }
-        }
-    }
-
-    public String getWhitelistedWord(String before) {
-        if (before == null) return null;
-        final String lowerCaseBefore = before.toLowerCase();
-        if(mWhitelistWords.containsKey(lowerCaseBefore)) {
-            if (DBG) {
-                Log.d(TAG, "--- found whitelistedWord: " + lowerCaseBefore);
-            }
-            return mWhitelistWords.get(lowerCaseBefore).second;
-        }
-        return null;
-    }
-
-    @Override
-    public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
-            final CharSequence prevWord, final ProximityInfo proximityInfo) {
-        // Whitelist does not supply any suggestions or predictions.
-        return null;
-    }
-
-    // See LatinIME#updateSuggestions. This breaks in the (queer) case that the whitelist
-    // lists that word a should autocorrect to word b, and word c would autocorrect to
-    // an upper-cased version of a. In this case, the way this return value is used would
-    // remove the first candidate when the user typed the upper-cased version of A.
-    // Example : abc -> def  and  xyz -> Abc
-    // A user typing Abc would experience it being autocorrected to something else (not
-    // necessarily def).
-    // There is no such combination in the whitelist at the time and there probably won't
-    // ever be - it doesn't make sense. But still.
-    public boolean shouldForciblyAutoCorrectFrom(CharSequence word) {
-        if (TextUtils.isEmpty(word)) return false;
-        final String correction = getWhitelistedWord(word.toString());
-        if (TextUtils.isEmpty(correction)) return false;
-        return !correction.equals(word);
-    }
-
-    // Leave implementation of getWords and isValidWord to the superclass.
-    // The words have been added to the ExpandableDictionary with addWord() inside initWordlist.
-}
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
index 2c3eee7..b23b7db 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
@@ -124,7 +124,7 @@
      */
 
     private static final int VERSION_1_MAGIC_NUMBER = 0x78B1;
-    private static final int VERSION_2_MAGIC_NUMBER = 0x9BC13AFE;
+    public static final int VERSION_2_MAGIC_NUMBER = 0x9BC13AFE;
     private static final int MINIMUM_SUPPORTED_VERSION = 1;
     private static final int MAXIMUM_SUPPORTED_VERSION = 2;
     private static final int NOT_A_VERSION_NUMBER = -1;
@@ -783,10 +783,10 @@
         // their lower bound and exclude their higher bound so we need to have the first step
         // start at exactly 1 unit higher than floor(unigramFreq + half a step).
         // Note : to reconstruct the score, the dictionary reader will need to divide
-        // MAX_TERMINAL_FREQUENCY - unigramFreq by 16.5 likewise, and add
-        // (discretizedFrequency + 0.5) times this value to get the median value of the step,
-        // which is the best approximation. This is how we get the most precise result with
-        // only four bits.
+        // MAX_TERMINAL_FREQUENCY - unigramFreq by 16.5 likewise to get the value of the step,
+        // and add (discretizedFrequency + 0.5 + 0.5) times this value to get the best
+        // approximation. (0.5 to get the first step start, and 0.5 to get the middle of the
+        // step pointed by the discretized frequency.
         final float stepSize =
                 (MAX_TERMINAL_FREQUENCY - unigramFrequency) / (1.5f + MAX_BIGRAM_FREQUENCY);
         final float firstStepStart = 1 + unigramFrequency + (stepSize / 2.0f);
@@ -1328,6 +1328,21 @@
     }
 
     /**
+     * Reads options from a file and populate a map with their contents.
+     *
+     * The file is read at the current file pointer, so the caller must take care the pointer
+     * is in the right place before calling this.
+     */
+    public static void populateOptionsFromFile(final RandomAccessFile source, final long headerSize,
+            final HashMap<String, String> options) throws IOException {
+        while (source.getFilePointer() < headerSize) {
+            final String key = CharEncoding.readString(source);
+            final String value = CharEncoding.readString(source);
+            options.put(key, value);
+        }
+    }
+
+    /**
      * Reads a random access file and returns the memory representation of the dictionary.
      *
      * This high-level method takes a binary file and reads its contents, populating a
@@ -1358,11 +1373,7 @@
         } else {
             headerSize = (source.readUnsignedByte() << 24) + (source.readUnsignedByte() << 16)
                     + (source.readUnsignedByte() << 8) + source.readUnsignedByte();
-            while (source.getFilePointer() < headerSize) {
-                final String key = CharEncoding.readString(source);
-                final String value = CharEncoding.readString(source);
-                options.put(key, value);
-            }
+            populateOptionsFromFile(source, headerSize, options);
             source.seek(headerSize);
         }
 
@@ -1410,4 +1421,22 @@
             return false;
         }
     }
+
+    /**
+     * Calculate bigram frequency from compressed value
+     *
+     * @see #makeBigramFlags
+     *
+     * @param unigramFrequency
+     * @param bigramFrequency compressed frequency
+     * @return approximate bigram frequency
+     */
+    public static int reconstructBigramFrequency(final int unigramFrequency,
+            final int bigramFrequency) {
+        final float stepSize = (MAX_TERMINAL_FREQUENCY - unigramFrequency)
+                / (1.5f + MAX_BIGRAM_FREQUENCY);
+        final float resultFreqFloat = (float)unigramFrequency
+                + stepSize * (bigramFrequency + 1.0f);
+        return (int)resultFreqFloat;
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
index 2601551..7c15ba5 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
@@ -532,6 +532,7 @@
         } while (null != node && index < s.length());
 
         if (index < s.length()) return null;
+        if (!currentGroup.isTerminal()) return null;
         if (DBG && !s.equals(checker.toString())) return null;
         return currentGroup;
     }
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 3bdfe1f..d05dc02 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -35,7 +35,6 @@
 import com.android.inputmethod.latin.SynchronouslyLoadedContactsBinaryDictionary;
 import com.android.inputmethod.latin.SynchronouslyLoadedUserBinaryDictionary;
 import com.android.inputmethod.latin.UserBinaryDictionary;
-import com.android.inputmethod.latin.WhitelistDictionary;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -67,8 +66,6 @@
             Collections.synchronizedMap(new TreeMap<String, DictionaryPool>());
     private Map<String, UserBinaryDictionary> mUserDictionaries =
             Collections.synchronizedMap(new TreeMap<String, UserBinaryDictionary>());
-    private Map<String, Dictionary> mWhitelistDictionaries =
-            Collections.synchronizedMap(new TreeMap<String, Dictionary>());
     private ContactsBinaryDictionary mContactsDictionary;
 
     // The threshold for a candidate to be offered as a suggestion.
@@ -366,8 +363,6 @@
         final Map<String, UserBinaryDictionary> oldUserDictionaries = mUserDictionaries;
         mUserDictionaries =
                 Collections.synchronizedMap(new TreeMap<String, UserBinaryDictionary>());
-        final Map<String, Dictionary> oldWhitelistDictionaries = mWhitelistDictionaries;
-        mWhitelistDictionaries = Collections.synchronizedMap(new TreeMap<String, Dictionary>());
         new Thread("spellchecker_close_dicts") {
             @Override
             public void run() {
@@ -377,9 +372,6 @@
                 for (Dictionary dict : oldUserDictionaries.values()) {
                     dict.close();
                 }
-                for (Dictionary dict : oldWhitelistDictionaries.values()) {
-                    dict.close();
-                }
                 synchronized (mUseContactsLock) {
                     if (null != mContactsDictionary) {
                         // The synchronously loaded contacts dictionary should have been in one
@@ -423,12 +415,6 @@
             mUserDictionaries.put(localeStr, userDictionary);
         }
         dictionaryCollection.addDictionary(userDictionary);
-        Dictionary whitelistDictionary = mWhitelistDictionaries.get(localeStr);
-        if (null == whitelistDictionary) {
-            whitelistDictionary = new WhitelistDictionary(this, locale);
-            mWhitelistDictionaries.put(localeStr, whitelistDictionary);
-        }
-        dictionaryCollection.addDictionary(whitelistDictionary);
         synchronized (mUseContactsLock) {
             if (mUseContactsDictionary) {
                 if (null == mContactsDictionary) {
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 2add7c9..6a0a7c2 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -178,7 +178,7 @@
     memset(outputTypes, 0, outputTypesLength * sizeof(outputTypes[0]));
 
     int count;
-    if (isGesture || arraySize > 1) {
+    if (isGesture || arraySize > 0) {
         count = dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates,
                 times, pointerIds, inputCodePoints, arraySize, prevWordCodePoints,
                 prevWordCodePointsLength, commitPoint, isGesture, useFullEditDistance, outputChars,
diff --git a/native/jni/src/bigram_dictionary.h b/native/jni/src/bigram_dictionary.h
index d676cca..5f11ae8 100644
--- a/native/jni/src/bigram_dictionary.h
+++ b/native/jni/src/bigram_dictionary.h
@@ -29,8 +29,6 @@
     BigramDictionary(const unsigned char *dict, int maxWordLength, int maxPredictions);
     int getBigrams(const int32_t *word, int length, int *inputCodes, int codesSize,
             unsigned short *outWords, int *frequencies, int *outputTypes) const;
-    int getBigramListPositionForWord(const int32_t *prevWord, const int prevWordLength,
-            const bool forceLowerCaseSearch) const;
     void fillBigramAddressToFrequencyMapAndFilter(const int32_t *prevWord, const int prevWordLength,
             std::map<int, int> *map, uint8_t *filter) const;
     bool isValidBigram(const int32_t *word1, int length1, const int32_t *word2, int length2) const;
@@ -45,6 +43,8 @@
     bool getFirstBitOfByte(int *pos) { return (DICT[*pos] & 0x80) > 0; }
     bool getSecondBitOfByte(int *pos) { return (DICT[*pos] & 0x40) > 0; }
     bool checkFirstCharacter(unsigned short *word, int *inputCodes) const;
+    int getBigramListPositionForWord(const int32_t *prevWord, const int prevWordLength,
+            const bool forceLowerCaseSearch) const;
 
     const unsigned char *DICT;
     const int MAX_WORD_LENGTH;
diff --git a/native/jni/src/binary_format.h b/native/jni/src/binary_format.h
index 4cabc84..d8f3e83 100644
--- a/native/jni/src/binary_format.h
+++ b/native/jni/src/binary_format.h
@@ -61,13 +61,6 @@
     static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES = 0x20;
     static const int FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES = 0x30;
 
- private:
-    DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryFormat);
-    const static int32_t MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20;
-    const static int32_t CHARACTER_ARRAY_TERMINATOR = 0x1F;
-    const static int MULTIPLE_BYTE_CHARACTER_ADDITIONAL_SIZE = 2;
-
- public:
     const static int UNKNOWN_FORMAT = -1;
     // Originally, format version 1 had a 16-bit magic number, then the version number `01'
     // then options that must be 0. Hence the first 32-bits of the format are always as follow
@@ -94,7 +87,6 @@
     static int skipFrequency(const uint8_t flags, const int pos);
     static int skipShortcuts(const uint8_t *const dict, const uint8_t flags, const int pos);
     static int skipBigrams(const uint8_t *const dict, const uint8_t flags, const int pos);
-    static int skipAllAttributes(const uint8_t *const dict, const uint8_t flags, const int pos);
     static int skipChildrenPosAndAttributes(const uint8_t *const dict, const uint8_t flags,
             const int pos);
     static int readChildrenPosition(const uint8_t *const dict, const uint8_t flags, const int pos);
@@ -118,6 +110,13 @@
         REQUIRES_FRENCH_LIGATURES_PROCESSING = 0x4
     };
     const static unsigned int NO_FLAGS = 0;
+
+ private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryFormat);
+    const static int32_t MINIMAL_ONE_BYTE_CHARACTER_VALUE = 0x20;
+    const static int32_t CHARACTER_ARRAY_TERMINATOR = 0x1F;
+    const static int MULTIPLE_BYTE_CHARACTER_ADDITIONAL_SIZE = 2;
+    static int skipAllAttributes(const uint8_t *const dict, const uint8_t flags, const int pos);
 };
 
 inline int BinaryFormat::detectFormat(const uint8_t *const dict) {
diff --git a/native/jni/src/char_utils.cpp b/native/jni/src/char_utils.cpp
index 223291f..9d886da31 100644
--- a/native/jni/src/char_utils.cpp
+++ b/native/jni/src/char_utils.cpp
@@ -889,7 +889,7 @@
             - static_cast<int>((static_cast<const struct LatinCapitalSmallPair *>(b))->capital);
 }
 
-unsigned short latin_tolower(unsigned short c) {
+unsigned short latin_tolower(const unsigned short c) {
     struct LatinCapitalSmallPair *p =
             static_cast<struct LatinCapitalSmallPair *>(bsearch(&c, SORTED_CHAR_MAP,
                     sizeof(SORTED_CHAR_MAP) / sizeof(SORTED_CHAR_MAP[0]),
diff --git a/native/jni/src/char_utils.h b/native/jni/src/char_utils.h
index edd96bb..b30677f 100644
--- a/native/jni/src/char_utils.h
+++ b/native/jni/src/char_utils.h
@@ -17,21 +17,23 @@
 #ifndef LATINIME_CHAR_UTILS_H
 #define LATINIME_CHAR_UTILS_H
 
+#include <cctype>
+
 namespace latinime {
 
-inline static int isAsciiUpper(unsigned short c) {
-    return c >= 'A' && c <= 'Z';
+inline static bool isAsciiUpper(unsigned short c) {
+    return isupper(static_cast<int>(c)) != 0;
 }
 
 inline static unsigned short toAsciiLower(unsigned short c) {
     return c - 'A' + 'a';
 }
 
-inline static int isAscii(unsigned short c) {
-    return c <= 127;
+inline static bool isAscii(unsigned short c) {
+    return isascii(static_cast<int>(c)) != 0;
 }
 
-unsigned short latin_tolower(unsigned short c);
+unsigned short latin_tolower(const unsigned short c);
 
 /**
  * Table mapping most combined Latin, Greek, and Cyrillic characters
diff --git a/native/jni/src/correction.cpp b/native/jni/src/correction.cpp
index 7513b30..71f8a4f 100644
--- a/native/jni/src/correction.cpp
+++ b/native/jni/src/correction.cpp
@@ -181,10 +181,6 @@
     const int outputIndex = mTerminalOutputIndex;
     const int inputIndex = mTerminalInputIndex;
     *wordLength = outputIndex + 1;
-    if (outputIndex < MIN_SUGGEST_DEPTH) {
-        return NOT_A_PROBABILITY;
-    }
-
     *word = mWord;
     int finalProbability= Correction::RankingAlgorithm::calculateFinalProbability(
             inputIndex, outputIndex, probability, mEditDistanceTable, this, inputLength);
diff --git a/native/jni/src/debug.h b/native/jni/src/debug.h
index 4e21640..8f6b69d 100644
--- a/native/jni/src/debug.h
+++ b/native/jni/src/debug.h
@@ -22,7 +22,7 @@
 static inline unsigned char *convertToUnibyteString(unsigned short *input, unsigned char *output,
         const unsigned int length) {
     unsigned int i = 0;
-    for (; i <= length && input[i] != 0; ++i)
+    for (; i < length && input[i] != 0; ++i)
         output[i] = input[i] & 0xFF;
     output[i] = 0;
     return output;
@@ -31,7 +31,7 @@
 static inline unsigned char *convertToUnibyteStringAndReplaceLastChar(unsigned short *input,
         unsigned char *output, const unsigned int length, unsigned char c) {
     unsigned int i = 0;
-    for (; i <= length && input[i] != 0; ++i)
+    for (; i < length && input[i] != 0; ++i)
         output[i] = input[i] & 0xFF;
     if (i > 0) output[i-1] = c;
     output[i] = 0;
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index 484fc6b..929b303 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -298,8 +298,6 @@
 // word in the dictionary for languages with digraphs, like German and French
 #define DEFAULT_MAX_DIGRAPH_SEARCH_DEPTH 5
 
-// Minimum suggest depth for one word for all cases except for missing space suggestions.
-#define MIN_SUGGEST_DEPTH 1
 #define MIN_USER_TYPED_LENGTH_FOR_MULTIPLE_WORD_SUGGESTION 3
 #define MIN_USER_TYPED_LENGTH_FOR_EXCESSIVE_CHARACTER_SUGGESTION 3
 
diff --git a/native/jni/src/unigram_dictionary.cpp b/native/jni/src/unigram_dictionary.cpp
index cc6d39a..705defc 100644
--- a/native/jni/src/unigram_dictionary.cpp
+++ b/native/jni/src/unigram_dictionary.cpp
@@ -390,43 +390,42 @@
         WordsPriorityQueue *masterQueue = queuePool->getMasterQueue();
         const int finalProbability =
                 correction->getFinalProbability(probability, &wordPointer, &wordLength);
-        if (finalProbability != NOT_A_PROBABILITY) {
-            if (0 != finalProbability) {
-                // If the probability is 0, we don't want to add this word. However we still
-                // want to add its shortcuts (including a possible whitelist entry) if any.
-                addWord(wordPointer, wordLength, finalProbability, masterQueue,
-                        Dictionary::KIND_CORRECTION);
-            }
 
-            const int shortcutProbability = finalProbability > 0 ? finalProbability - 1 : 0;
-            // Please note that the shortcut candidates will be added to the master queue only.
-            TerminalAttributes::ShortcutIterator iterator =
-                    terminalAttributes.getShortcutIterator();
-            while (iterator.hasNextShortcutTarget()) {
-                // TODO: addWord only supports weak ordering, meaning we have no means
-                // to control the order of the shortcuts relative to one another or to the word.
-                // We need to either modulate the probability of each shortcut according
-                // to its own shortcut probability or to make the queue
-                // so that the insert order is protected inside the queue for words
-                // with the same score. For the moment we use -1 to make sure the shortcut will
-                // never be in front of the word.
-                uint16_t shortcutTarget[MAX_WORD_LENGTH_INTERNAL];
-                int shortcutFrequency;
-                const int shortcutTargetStringLength = iterator.getNextShortcutTarget(
-                        MAX_WORD_LENGTH_INTERNAL, shortcutTarget, &shortcutFrequency);
-                int shortcutScore;
-                int kind;
-                if (shortcutFrequency == BinaryFormat::WHITELIST_SHORTCUT_FREQUENCY
-                        && correction->sameAsTyped()) {
-                    shortcutScore = S_INT_MAX;
-                    kind = Dictionary::KIND_WHITELIST;
-                } else {
-                    shortcutScore = shortcutProbability;
-                    kind = Dictionary::KIND_CORRECTION;
-                }
-                addWord(shortcutTarget, shortcutTargetStringLength, shortcutScore,
-                        masterQueue, kind);
+        if (0 != finalProbability) {
+            // If the probability is 0, we don't want to add this word. However we still
+            // want to add its shortcuts (including a possible whitelist entry) if any.
+            addWord(wordPointer, wordLength, finalProbability, masterQueue,
+                    Dictionary::KIND_CORRECTION);
+        }
+
+        const int shortcutProbability = finalProbability > 0 ? finalProbability - 1 : 0;
+        // Please note that the shortcut candidates will be added to the master queue only.
+        TerminalAttributes::ShortcutIterator iterator =
+                terminalAttributes.getShortcutIterator();
+        while (iterator.hasNextShortcutTarget()) {
+            // TODO: addWord only supports weak ordering, meaning we have no means
+            // to control the order of the shortcuts relative to one another or to the word.
+            // We need to either modulate the probability of each shortcut according
+            // to its own shortcut probability or to make the queue
+            // so that the insert order is protected inside the queue for words
+            // with the same score. For the moment we use -1 to make sure the shortcut will
+            // never be in front of the word.
+            uint16_t shortcutTarget[MAX_WORD_LENGTH_INTERNAL];
+            int shortcutFrequency;
+            const int shortcutTargetStringLength = iterator.getNextShortcutTarget(
+                    MAX_WORD_LENGTH_INTERNAL, shortcutTarget, &shortcutFrequency);
+            int shortcutScore;
+            int kind;
+            if (shortcutFrequency == BinaryFormat::WHITELIST_SHORTCUT_FREQUENCY
+                    && correction->sameAsTyped()) {
+                shortcutScore = S_INT_MAX;
+                kind = Dictionary::KIND_WHITELIST;
+            } else {
+                shortcutScore = shortcutProbability;
+                kind = Dictionary::KIND_CORRECTION;
             }
+            addWord(shortcutTarget, shortcutTargetStringLength, shortcutScore,
+                    masterQueue, kind);
         }
     }
 
diff --git a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java
index e3f7583..8ecdcc3 100644
--- a/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/FusionDictionaryTests.java
@@ -38,5 +38,11 @@
         dict.add("aa", 10, null);
         assertNull(FusionDictionary.findWordInTree(dict.mRoot, "aaa"));
         assertNotNull(FusionDictionary.findWordInTree(dict.mRoot, "aa"));
+
+        dict.add("babcd", 10, null);
+        dict.add("bacde", 10, null);
+        assertNull(FusionDictionary.findWordInTree(dict.mRoot, "ba"));
+        assertNotNull(FusionDictionary.findWordInTree(dict.mRoot, "babcd"));
+        assertNotNull(FusionDictionary.findWordInTree(dict.mRoot, "bacde"));
     }
 }
diff --git a/tools/dicttool/Android.mk b/tools/dicttool/Android.mk
index df8cb10..b0b47af 100644
--- a/tools/dicttool/Android.mk
+++ b/tools/dicttool/Android.mk
@@ -26,7 +26,6 @@
 LOCAL_JAR_MANIFEST := etc/manifest.txt
 LOCAL_MODULE := dicttool_aosp
 LOCAL_JAVA_LIBRARIES := junit
-LOCAL_MODULE_TAGS := eng
 
 include $(BUILD_HOST_JAVA_LIBRARY)
 include $(LOCAL_PATH)/etc/Android.mk
diff --git a/tools/dicttool/etc/Android.mk b/tools/dicttool/etc/Android.mk
index 8952827..0c611b7 100644
--- a/tools/dicttool/etc/Android.mk
+++ b/tools/dicttool/etc/Android.mk
@@ -15,6 +15,5 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := eng
 LOCAL_PREBUILT_EXECUTABLES := dicttool_aosp makedict_aosp
 include $(BUILD_HOST_PREBUILT)
diff --git a/tools/maketext/Android.mk b/tools/maketext/Android.mk
index 98731b7..77914ca 100644
--- a/tools/maketext/Android.mk
+++ b/tools/maketext/Android.mk
@@ -19,7 +19,6 @@
 LOCAL_SRC_FILES += $(call all-java-files-under,src)
 LOCAL_JAR_MANIFEST := etc/manifest.txt
 LOCAL_JAVA_RESOURCE_DIRS := res
-LOCAL_MODULE_TAGS := eng
 LOCAL_MODULE := maketext
 
 include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/maketext/etc/Android.mk b/tools/maketext/etc/Android.mk
index 4fa194b..475676b 100644
--- a/tools/maketext/etc/Android.mk
+++ b/tools/maketext/etc/Android.mk
@@ -15,7 +15,6 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := eng
-
 LOCAL_PREBUILT_EXECUTABLES := maketext
+
 include $(BUILD_HOST_PREBUILT)