Merge "Make LatinIME keys accessibility focusable, clickable." into jb-dev
diff --git a/java/res/drawable-hdpi/sym_keyboard_voice_holo.png b/java/res/drawable-hdpi/sym_keyboard_voice_holo.png
index bc9f908..8a6336a 100644
--- a/java/res/drawable-hdpi/sym_keyboard_voice_holo.png
+++ b/java/res/drawable-hdpi/sym_keyboard_voice_holo.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_voice_off_holo.png b/java/res/drawable-hdpi/sym_keyboard_voice_off_holo.png
index e852eec..edf1379 100644
--- a/java/res/drawable-hdpi/sym_keyboard_voice_off_holo.png
+++ b/java/res/drawable-hdpi/sym_keyboard_voice_off_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_voice_holo.png b/java/res/drawable-mdpi/sym_keyboard_voice_holo.png
index 960c608..0795fcc 100644
--- a/java/res/drawable-mdpi/sym_keyboard_voice_holo.png
+++ b/java/res/drawable-mdpi/sym_keyboard_voice_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_voice_off_holo.png b/java/res/drawable-mdpi/sym_keyboard_voice_off_holo.png
index 72086a9..f76da57 100644
--- a/java/res/drawable-mdpi/sym_keyboard_voice_off_holo.png
+++ b/java/res/drawable-mdpi/sym_keyboard_voice_off_holo.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_voice_holo.png b/java/res/drawable-xhdpi/sym_keyboard_voice_holo.png
index d338cf2..b2bb9b8 100644
--- a/java/res/drawable-xhdpi/sym_keyboard_voice_holo.png
+++ b/java/res/drawable-xhdpi/sym_keyboard_voice_holo.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_voice_off_holo.png b/java/res/drawable-xhdpi/sym_keyboard_voice_off_holo.png
index 0c913e1..23e75bf 100644
--- a/java/res/drawable-xhdpi/sym_keyboard_voice_off_holo.png
+++ b/java/res/drawable-xhdpi/sym_keyboard_voice_off_holo.png
Binary files differ
diff --git a/java/res/values-en/whitelist.xml b/java/res/values-en/whitelist.xml
index 79d6ade..9c10858 100644
--- a/java/res/values-en/whitelist.xml
+++ b/java/res/values-en/whitelist.xml
@@ -170,6 +170,14 @@
         <item>believe</item>
 
         <item>255</item>
+        <item>bot</item>
+        <item>not</item>
+
+        <item>255</item>
+        <item>bur</item>
+        <item>but</item>
+
+        <item>255</item>
         <item>butthe</item>
         <item>but the</item>
 
@@ -402,6 +410,10 @@
         <item>I\'ve</item>
 
         <item>255</item>
+        <item>jot</item>
+        <item>not</item>
+
+        <item>255</item>
         <item>lets</item>
         <item>let\'s</item>
 
@@ -426,6 +438,10 @@
         <item>Monday</item>
 
         <item>255</item>
+        <item>mot</item>
+        <item>not</item>
+
+        <item>255</item>
         <item>mustnt</item>
         <item>mustn\'t</item>
 
@@ -760,6 +776,10 @@
         <item>y\'all</item>
 
         <item>255</item>
+        <item>yo</item>
+        <item>to</item>
+
+        <item>255</item>
         <item>youd</item>
         <item>you\'d</item>
 
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
index 3e87049..298534d 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -64,7 +64,7 @@
     <string name="bigram_suggestion" msgid="8169311444438922902">"다음 추천 검색어"</string>
     <string name="bigram_suggestion_summary" msgid="6635527607242625713">"이전 단어를 사용하여 추천 검색어 개선"</string>
     <string name="bigram_prediction" msgid="3216364899483135294">"다음 예상 검색어"</string>
-    <string name="bigram_prediction_summary" msgid="1747261921174300098">"이전 단어를 사용하여 예상 검색어를 표시합니다."</string>
+    <string name="bigram_prediction_summary" msgid="1747261921174300098">"이전 단어를 사용하여 예상 검색어 표시"</string>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: 저장됨"</string>
     <string name="label_go_key" msgid="1635148082137219148">"이동"</string>
     <string name="label_next_key" msgid="362972844525672568">"다음"</string>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
index c0c8433..7c8e2bd 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -118,7 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Motív klávesnice"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"Anglická klávesnica (UK)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"Anglická klávesnica (US)"</string>
-    <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"angličtina (VB) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
+    <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"angličtina (UK) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
     <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"angličtina (USA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
     <string name="subtype_no_language" msgid="141420857808801746">"Žiadny jazyk"</string>
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Žiadny jazyk (QWERTY)"</string>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index 9b5da75..6d919b2 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -118,7 +118,7 @@
     <string name="keyboard_layout" msgid="8451164783510487501">"Tema tipkovnice"</string>
     <string name="subtype_en_GB" msgid="88170601942311355">"angleščina (Združeno kraljestvo)"</string>
     <string name="subtype_en_US" msgid="6160452336634534239">"angleščina (ZDA)"</string>
-    <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Angleška (VB) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
+    <string name="subtype_with_layout_en_GB" msgid="2179097748724725906">"Angleška (Zdr. kralj.) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
     <string name="subtype_with_layout_en_US" msgid="1362581347576714579">"Angleška (ZDA) (<xliff:g id="LAYOUT">%s</xliff:g>)"</string>
     <string name="subtype_no_language" msgid="141420857808801746">"Ni jezika"</string>
     <string name="subtype_no_language_qwerty" msgid="2956121451616633133">"Ni jezika (QWERTY)"</string>
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index a6fd22e..21010b3 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -23,8 +23,7 @@
     <bool name="config_enable_show_voice_key_option">true</bool>
     <bool name="config_enable_show_popup_on_keypress_option">true</bool>
     <bool name="config_enable_next_word_suggestions_option">true</bool>
-    <!-- TODO: Disable the following configuration for production. -->
-    <bool name="config_enable_usability_study_mode_option">true</bool>
+    <bool name="config_enable_usability_study_mode_option">false</bool>
     <!-- Whether or not Popup on key press is enabled by default -->
     <bool name="config_default_popup_preview">true</bool>
     <!-- Default value for next word suggestion: while showing suggestions for a word should we weigh
diff --git a/java/res/values/keypress-volumes.xml b/java/res/values/keypress-volumes.xml
index 1bec6a3..3b433e4 100644
--- a/java/res/values/keypress-volumes.xml
+++ b/java/res/values/keypress-volumes.xml
@@ -23,5 +23,6 @@
         <item>herring,0.5</item>
         <item>tuna,0.5</item>
         <item>stingray,0.4</item>
+        <item>grouper,0.3</item>
     </string-array>
 </resources>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index cb458a4..8b03379 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -275,18 +275,24 @@
 
     <!-- Title of the preference settings for custom input styles (language and keyboard layout pairs) [CHAR LIMIT=35]-->
     <string name="custom_input_styles_title">Custom input styles</string>
-    <!-- Title of the option menu to add a new style entry in the preference settings [CHAR_LIMIT=16] -->
+    <!-- Title of the option menu to add a new style entry in the preference settings [CHAR LIMIT=16] -->
     <string name="add_style">Add style</string>
-    <!-- Title of the button to add custom style entry in the settings dialog [CHAR_LIMIT=12]  -->
+    <!-- Title of the button to add custom style entry in the settings dialog [CHAR LIMIT=12] -->
     <string name="add">Add</string>
-    <!-- Title of the button to remove a custom style entry in the settings dialog [CHAR_LIMIT=12]  -->
+    <!-- Title of the button to remove a custom style entry in the settings dialog [CHAR LIMIT=12] -->
     <string name="remove">Remove</string>
-    <!-- Title of the button to save a custom style entry in the settings dialog [CHAR_LIMIT=12]  -->
+    <!-- Title of the button to save a custom style entry in the settings dialog [CHAR LIMIT=12] -->
     <string name="save">Save</string>
-    <!-- Title of the spinner for choosing a language of custom style in the settings dialog [CHAR_LIMIT=12]  -->
+    <!-- Title of the spinner for choosing a language of custom style in the settings dialog [CHAR LIMIT=12] -->
     <string name="subtype_locale">Language</string>
-    <!-- Title of the spinner for choosing a keyboard layout of custom style in the settings dialog [CHAR_LIMIT=12]  -->
+    <!-- Title of the spinner for choosing a keyboard layout of custom style in the settings dialog [CHAR LIMIT=12] -->
     <string name="keyboard_layout_set">Layout</string>
+    <!-- The message of the dialog to note that a custom input style needs to be enabled. [CHAR LIMIT=64] -->
+    <string name="custom_input_style_note_message">"Your custom input style needs to be enabled before you start using it. Do you want to enable it now?"</string>
+    <!-- Title of the button to enable a custom input style entry in the settings dialog [CHAR LIMIT=12] -->
+    <string name="enable">Enable</string>
+    <!-- Title of the button to postpone enabling a custom input style entry in the settings dialog [CHAR LIMIT=12] -->
+    <string name="not_now">Not now</string>
 
     <!-- Title of an option for usability study mode -->
     <string name="prefs_usability_study_mode">Usability study mode</string>
diff --git a/java/res/xml/rows_bulgarian_bds.xml b/java/res/xml/rows_bulgarian_bds.xml
index 9a2f0bc..b4f3f12 100644
--- a/java/res/xml/rows_bulgarian_bds.xml
+++ b/java/res/xml/rows_bulgarian_bds.xml
@@ -36,7 +36,7 @@
             latin:keyboardLayout="@xml/rowkeys_bulgarian_bds2" />
     </Row>
     <Row
-        latin:keyWidth="9.091%p"
+        latin:keyWidth="8.711%p"
     >
         <Key
             latin:keyStyle="shiftKeyStyle"
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 4d7fe3d..c3f5e7d 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -571,9 +571,13 @@
         return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_EMBEDDED_MORE_KEY) != 0;
     }
 
-    public Drawable getIcon(KeyboardIconsSet iconSet) {
+    public Drawable getIcon(KeyboardIconsSet iconSet, int alpha) {
         final int iconId = mEnabled ? mIconId : mDisabledIconId;
-        return iconSet.getIconDrawable(iconId);
+        final Drawable icon = iconSet.getIconDrawable(iconId);
+        if (icon != null) {
+            icon.setAlpha(alpha);
+        }
+        return icon;
     }
 
     public Drawable getPreviewIcon(KeyboardIconsSet iconSet) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 9be193b..c0d5b67 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -560,10 +560,7 @@
         }
 
         // Draw key label.
-        final Drawable icon = key.getIcon(mKeyboard.mIconsSet);
-        if (icon != null) {
-            icon.setAlpha(params.mAnimAlpha);
-        }
+        final Drawable icon = key.getIcon(mKeyboard.mIconsSet, params.mAnimAlpha);
         float positionX = centerX;
         if (key.mLabel != null) {
             final String label = key.mLabel;
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 337ae9c..cb37672 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -459,7 +459,8 @@
         mMoreKeysPanelCache.clear();
 
         mSpaceKey = keyboard.getKey(Keyboard.CODE_SPACE);
-        mSpaceIcon = (mSpaceKey != null) ? mSpaceKey.getIcon(keyboard.mIconsSet) : null;
+        mSpaceIcon = (mSpaceKey != null)
+                ? mSpaceKey.getIcon(keyboard.mIconsSet, ALPHA_OPAQUE) : null;
         final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
         mSpacebarTextSize = keyHeight * mSpacebarTextRatio;
         if (ProductionFlag.IS_EXPERIMENTAL) {
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index b6a06e1..a3741a2 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -289,8 +289,6 @@
             final int dividerWidth;
             if (parentKey.needsDividersInMoreKeys()) {
                 mDivider = mResources.getDrawable(R.drawable.more_keys_divider);
-                // TODO: Drawable itself should have an alpha value.
-                mDivider.setAlpha(128);
                 dividerWidth = (int)(width * DIVIDER_RATIO);
             } else {
                 mDivider = null;
@@ -333,8 +331,11 @@
             }
 
             @Override
-            public Drawable getIcon(KeyboardIconsSet iconSet) {
-                // KeyboardIconsSet is unused. Use the icon that has been passed to the constructor.
+            public Drawable getIcon(KeyboardIconsSet iconSet, int alpha) {
+                // KeyboardIconsSet and alpha are unused. Use the icon that has been passed to the
+                // constructor.
+                // TODO: Drawable itself should have an alpha value.
+                mIcon.setAlpha(128);
                 return mIcon;
             }
         }
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 90394ce..5ea28ab 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -18,6 +18,7 @@
 
 import android.graphics.Rect;
 import android.text.TextUtils;
+import android.util.FloatMath;
 
 import com.android.inputmethod.keyboard.Keyboard.Params.TouchPositionCorrection;
 import com.android.inputmethod.latin.JniUtils;
@@ -147,7 +148,7 @@
                     final float radius = touchPositionCorrection.mRadii[row];
                     sweetSpotCenterXs[i] = hitBoxCenterX + x * hitBoxWidth;
                     sweetSpotCenterYs[i] = hitBoxCenterY + y * hitBoxHeight;
-                    sweetSpotRadii[i] = radius * (float) Math.sqrt(
+                    sweetSpotRadii[i] = radius * FloatMath.sqrt(
                             hitBoxWidth * hitBoxWidth + hitBoxHeight * hitBoxHeight);
                 }
             }
diff --git a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
index 0bde2c0..a8115fb 100644
--- a/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
+++ b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
@@ -22,6 +22,7 @@
 import android.app.Dialog;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -41,6 +42,8 @@
 import android.widget.Spinner;
 import android.widget.SpinnerAdapter;
 
+import com.android.inputmethod.compat.CompatUtils;
+
 import java.util.TreeSet;
 
 public class AdditionalSubtypeSettings extends PreferenceFragment {
@@ -49,9 +52,14 @@
     private KeyboardLayoutSetAdapter mKeyboardLayoutSetAdapter;
 
     private boolean mIsAddingNewSubtype;
+    private AlertDialog mSubtypeEnablerNotificationDialog;
+    private String mSubtypePreferenceKeyForSubtypeEnabler;
 
     private static final int MENU_ADD_SUBTYPE = Menu.FIRST;
-    private static final String SAVE_IS_ADDING_NEW_SUBTYPE = "is_adding_new_subtype";
+    private static final String KEY_IS_ADDING_NEW_SUBTYPE = "is_adding_new_subtype";
+    private static final String KEY_IS_SUBTYPE_ENABLER_NOTIFICATION_DIALOG_OPEN =
+            "is_subtype_enabler_notification_dialog_open";
+    private static final String KEY_SUBTYPE_FOR_SUBTYPE_ENABLER = "subtype_for_subtype_enabler";
 
     static class SubtypeLocaleItem extends Pair<String, String>
             implements Comparable<SubtypeLocaleItem> {
@@ -368,20 +376,36 @@
         setPrefSubtypes(prefSubtypes, context);
 
         mIsAddingNewSubtype = (savedInstanceState != null)
-                && savedInstanceState.containsKey(SAVE_IS_ADDING_NEW_SUBTYPE);
+                && savedInstanceState.containsKey(KEY_IS_ADDING_NEW_SUBTYPE);
         if (mIsAddingNewSubtype) {
             getPreferenceScreen().addPreference(
                     SubtypePreference.newIncompleteSubtypePreference(context, mSubtypeProxy));
         }
 
         super.onActivityCreated(savedInstanceState);
+
+        if (savedInstanceState != null && savedInstanceState.containsKey(
+                KEY_IS_SUBTYPE_ENABLER_NOTIFICATION_DIALOG_OPEN)) {
+            mSubtypePreferenceKeyForSubtypeEnabler = savedInstanceState.getString(
+                    KEY_SUBTYPE_FOR_SUBTYPE_ENABLER);
+            final SubtypePreference subtypePref = (SubtypePreference)findPreference(
+                    mSubtypePreferenceKeyForSubtypeEnabler);
+            mSubtypeEnablerNotificationDialog = createDialog(subtypePref);
+            mSubtypeEnablerNotificationDialog.show();
+        }
     }
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
         if (mIsAddingNewSubtype) {
-            outState.putBoolean(SAVE_IS_ADDING_NEW_SUBTYPE, true);
+            outState.putBoolean(KEY_IS_ADDING_NEW_SUBTYPE, true);
+        }
+        if (mSubtypeEnablerNotificationDialog != null
+                && mSubtypeEnablerNotificationDialog.isShowing()) {
+            outState.putBoolean(KEY_IS_SUBTYPE_ENABLER_NOTIFICATION_DIALOG_OPEN, true);
+            outState.putString(
+                    KEY_SUBTYPE_FOR_SUBTYPE_ENABLER, mSubtypePreferenceKeyForSubtypeEnabler);
         }
     }
 
@@ -398,6 +422,10 @@
         @Override
         public void onAddPressed(SubtypePreference subtypePref) {
             mIsAddingNewSubtype = false;
+            setAdditionalInputMethodSubtypes(getPrefSubtypes());
+            mSubtypePreferenceKeyForSubtypeEnabler = subtypePref.getKey();
+            mSubtypeEnablerNotificationDialog = createDialog(subtypePref);
+            mSubtypeEnablerNotificationDialog.show();
         }
 
         @Override
@@ -411,6 +439,29 @@
         }
     };
 
+    private AlertDialog createDialog(SubtypePreference subtypePref) {
+        final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+        builder.setTitle(R.string.custom_input_styles_title)
+                .setMessage(R.string.custom_input_style_note_message)
+                .setNegativeButton(R.string.not_now, null)
+                .setPositiveButton(R.string.enable, new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        final Intent intent = CompatUtils.getInputLanguageSelectionIntent(
+                                ImfUtils.getInputMethodIdOfThisIme(getActivity()),
+                                Intent.FLAG_ACTIVITY_NEW_TASK
+                                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+                                | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                        // TODO: Add newly adding subtype to extra value of the intent as a hint
+                        // for the input language selection activity.
+                        // intent.putExtra("newlyAddedSubtype", subtypePref.getSubtype());
+                        startActivity(intent);
+                    }
+                });
+
+        return builder.create();
+    }
+
     private void setPrefSubtypes(String prefSubtypes, Context context) {
         final PreferenceGroup group = getPreferenceScreen();
         group.removeAll();
@@ -458,6 +509,10 @@
         } finally {
             editor.apply();
         }
+        setAdditionalInputMethodSubtypes(prefSubtypes);
+    }
+
+    private void setAdditionalInputMethodSubtypes(final String prefSubtypes) {
         final InputMethodSubtype[] subtypes =
                 AdditionalSubtype.createAdditionalSubtypesArray(prefSubtypes);
         ImfUtils.setAdditionalInputMethodSubtypes(getActivity(), subtypes);
diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java
index 38444a1..da1936a 100644
--- a/java/src/com/android/inputmethod/latin/AutoCorrection.java
+++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java
@@ -35,7 +35,7 @@
     public static CharSequence computeAutoCorrectionWord(
             HashMap<String, Dictionary> dictionaries,
             WordComposer wordComposer, ArrayList<SuggestedWordInfo> suggestions,
-            CharSequence consideredWord, double autoCorrectionThreshold,
+            CharSequence consideredWord, float autoCorrectionThreshold,
             CharSequence whitelistedWord) {
         if (hasAutoCorrectionForWhitelistedWord(whitelistedWord)) {
             return whitelistedWord;
@@ -100,14 +100,14 @@
 
     private static boolean hasAutoCorrectionForBinaryDictionary(WordComposer wordComposer,
             ArrayList<SuggestedWordInfo> suggestions,
-            CharSequence consideredWord, double autoCorrectionThreshold) {
+            CharSequence consideredWord, float autoCorrectionThreshold) {
         if (wordComposer.size() > 1 && suggestions.size() > 0) {
             final SuggestedWordInfo autoCorrectionSuggestion = suggestions.get(0);
             //final int autoCorrectionSuggestionScore = sortedScores[0];
             final int autoCorrectionSuggestionScore = autoCorrectionSuggestion.mScore;
             // TODO: when the normalized score of the first suggestion is nearly equals to
             //       the normalized score of the second suggestion, behave less aggressive.
-            final double normalizedScore = BinaryDictionary.calcNormalizedScore(
+            final float normalizedScore = BinaryDictionary.calcNormalizedScore(
                     consideredWord.toString(), autoCorrectionSuggestion.mWord.toString(),
                     autoCorrectionSuggestionScore);
             if (DBG) {
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index cc20f42..e18aee6 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -92,7 +92,7 @@
     private native int getBigramsNative(long dict, int[] prevWord, int prevWordLength,
             int[] inputCodes, int inputCodesLength, char[] outputChars, int[] scores,
             int maxWordLength, int maxBigrams);
-    private static native double calcNormalizedScoreNative(
+    private static native float calcNormalizedScoreNative(
             char[] before, int beforeLength, char[] after, int afterLength, int score);
     private static native int editDistanceNative(
             char[] before, int beforeLength, char[] after, int afterLength);
@@ -189,7 +189,7 @@
                 prevWordCodePointArray, mUseFullEditDistance, outputChars, scores);
     }
 
-    public static double calcNormalizedScore(String before, String after, int score) {
+    public static float calcNormalizedScore(String before, String after, int score) {
         return calcNormalizedScoreNative(before.toCharArray(), before.length(),
                 after.toCharArray(), after.length(), score);
     }
diff --git a/java/src/com/android/inputmethod/latin/DictionaryCollection.java b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
index 37deb0c..f3aa27a 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryCollection.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryCollection.java
@@ -70,6 +70,10 @@
         return false;
     }
 
+    public boolean isEmpty() {
+        return mDictionaries.isEmpty();
+    }
+
     @Override
     public void close() {
         for (final Dictionary dict : mDictionaries)
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
index f5dc7b3..4cd1b38 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java
@@ -36,7 +36,7 @@
             DictionaryFactory.class.getPackage().getName();
 
     /**
-     * Initializes a dictionary from a dictionary pack, with explicit flags.
+     * Initializes a main dictionary collection from a dictionary pack, with explicit flags.
      *
      * This searches for a content provider providing a dictionary pack for the specified
      * locale. If none is found, it falls back to the built-in dictionary - if any.
@@ -45,7 +45,7 @@
      * @param useFullEditDistance whether to use the full edit distance in suggestions
      * @return an initialized instance of DictionaryCollection
      */
-    public static DictionaryCollection createDictionaryFromManager(final Context context,
+    public static DictionaryCollection createMainDictionaryFromManager(final Context context,
             final Locale locale, final boolean useFullEditDistance) {
         if (null == locale) {
             Log.e(TAG, "No locale defined for dictionary");
@@ -73,7 +73,7 @@
     }
 
     /**
-     * Initializes a dictionary from a dictionary pack, with default flags.
+     * Initializes a main dictionary collection from a dictionary pack, with default flags.
      *
      * This searches for a content provider providing a dictionary pack for the specified
      * locale. If none is found, it falls back to the built-in dictionary, if any.
@@ -81,9 +81,9 @@
      * @param locale the locale for which to create the dictionary
      * @return an initialized instance of DictionaryCollection
      */
-    public static DictionaryCollection createDictionaryFromManager(final Context context,
+    public static DictionaryCollection createMainDictionaryFromManager(final Context context,
             final Locale locale) {
-        return createDictionaryFromManager(context, locale, false /* useFullEditDistance */);
+        return createMainDictionaryFromManager(context, locale, false /* useFullEditDistance */);
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 55b896f..932920a 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -77,7 +77,7 @@
     public final float mFxVolume;
     public final int mKeyPreviewPopupDismissDelay;
     public final boolean mAutoCorrectEnabled;
-    public final double mAutoCorrectionThreshold;
+    public final float mAutoCorrectionThreshold;
     private final boolean mVoiceKeyEnabled;
     private final boolean mVoiceKeyOnMain;
 
@@ -255,21 +255,21 @@
                 R.bool.config_default_next_word_prediction));
     }
 
-    private static double getAutoCorrectionThreshold(final Resources resources,
+    private static float getAutoCorrectionThreshold(final Resources resources,
             final String currentAutoCorrectionSetting) {
         final String[] autoCorrectionThresholdValues = resources.getStringArray(
                 R.array.auto_correction_threshold_values);
         // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off.
-        double autoCorrectionThreshold = Double.MAX_VALUE;
+        float autoCorrectionThreshold = Float.MAX_VALUE;
         try {
             final int arrayIndex = Integer.valueOf(currentAutoCorrectionSetting);
             if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) {
-                autoCorrectionThreshold = Double.parseDouble(
+                autoCorrectionThreshold = Float.parseFloat(
                         autoCorrectionThresholdValues[arrayIndex]);
             }
         } catch (NumberFormatException e) {
             // Whenever the threshold settings are correct, never come here.
-            autoCorrectionThreshold = Double.MAX_VALUE;
+            autoCorrectionThreshold = Float.MAX_VALUE;
             Log.w(TAG, "Cannot load auto correction threshold setting."
                     + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting
                     + ", autoCorrectionThresholdValues: "
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 845df81..9e478fa 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -43,20 +43,6 @@
     public static final int CORRECTION_FULL = 1;
     public static final int CORRECTION_FULL_BIGRAM = 2;
 
-    /**
-     * Words that appear in both bigram and unigram data gets multiplier ranging from
-     * BIGRAM_MULTIPLIER_MIN to BIGRAM_MULTIPLIER_MAX depending on the score from
-     * bigram data.
-     */
-    public static final double BIGRAM_MULTIPLIER_MIN = 1.2;
-    public static final double BIGRAM_MULTIPLIER_MAX = 1.5;
-
-    /**
-     * Maximum possible bigram frequency. Will depend on how many bits are being used in data
-     * structure. Maximum bigram frequency will get the BIGRAM_MULTIPLIER_MAX as the multiplier.
-     */
-    public static final int MAXIMUM_BIGRAM_FREQUENCY = 127;
-
     // It seems the following values are only used for logging.
     public static final int DIC_USER_TYPED = 0;
     public static final int DIC_MAIN = 1;
@@ -79,7 +65,7 @@
 
     private static final boolean DBG = LatinImeLogger.sDBG;
 
-    private Dictionary mMainDict;
+    private boolean mHasMainDictionary;
     private Dictionary mContactsDict;
     private WhitelistDictionary mWhiteListDictionary;
     private final HashMap<String, Dictionary> mUnigramDictionaries =
@@ -91,7 +77,7 @@
 
     private static final int PREF_MAX_BIGRAMS = 60;
 
-    private double mAutoCorrectionThreshold;
+    private float mAutoCorrectionThreshold;
 
     private ArrayList<SuggestedWordInfo> mSuggestions = new ArrayList<SuggestedWordInfo>();
     private ArrayList<SuggestedWordInfo> mBigramSuggestions = new ArrayList<SuggestedWordInfo>();
@@ -110,8 +96,12 @@
 
     /* package for test */ Suggest(final Context context, final File dictionary,
             final long startOffset, final long length, final Locale locale) {
-        initSynchronously(context, DictionaryFactory.createDictionaryForTest(context, dictionary,
-                startOffset, length /* useFullEditDistance */, false, locale), locale);
+        final Dictionary mainDict = DictionaryFactory.createDictionaryForTest(context, dictionary,
+                startOffset, length /* useFullEditDistance */, false, locale);
+        mHasMainDictionary = null != mainDict;
+        addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_MAIN, mainDict);
+        addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_MAIN, mainDict);
+        initWhitelistAndAutocorrectAndPool(context, locale);
     }
 
     private void initWhitelistAndAutocorrectAndPool(final Context context, final Locale locale) {
@@ -127,14 +117,6 @@
         initWhitelistAndAutocorrectAndPool(context, locale);
     }
 
-    private void initSynchronously(final Context context, final Dictionary mainDict,
-            final Locale locale) {
-        mMainDict = mainDict;
-        addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_MAIN, mainDict);
-        addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_MAIN, mainDict);
-        initWhitelistAndAutocorrectAndPool(context, locale);
-    }
-
     private static void addOrReplaceDictionary(HashMap<String, Dictionary> dictionaries, String key,
             Dictionary dict) {
         final Dictionary oldDict = (dict == null)
@@ -146,13 +128,13 @@
     }
 
     public void resetMainDict(final Context context, final Locale locale) {
-        mMainDict = null;
+        mHasMainDictionary = false;
         new Thread("InitializeBinaryDictionary") {
             @Override
             public void run() {
-                final Dictionary newMainDict = DictionaryFactory.createDictionaryFromManager(
-                        context, locale);
-                mMainDict = newMainDict;
+                final DictionaryCollection newMainDict =
+                        DictionaryFactory.createMainDictionaryFromManager(context, locale);
+                mHasMainDictionary = null != newMainDict && !newMainDict.isEmpty();
                 addOrReplaceDictionary(mUnigramDictionaries, DICT_KEY_MAIN, newMainDict);
                 addOrReplaceDictionary(mBigramDictionaries, DICT_KEY_MAIN, newMainDict);
             }
@@ -162,7 +144,7 @@
     // The main dictionary could have been loaded asynchronously.  Don't cache the return value
     // of this method.
     public boolean hasMainDictionary() {
-        return mMainDict != null;
+        return mHasMainDictionary;
     }
 
     public Dictionary getContactsDictionary() {
@@ -203,7 +185,7 @@
                 userHistoryDictionary);
     }
 
-    public void setAutoCorrectionThreshold(double threshold) {
+    public void setAutoCorrectionThreshold(float threshold) {
         mAutoCorrectionThreshold = threshold;
     }
 
@@ -376,7 +358,13 @@
         // a boolean flag. Right now this is handled with a slight hack in
         // WhitelistDictionary#shouldForciblyAutoCorrectFrom.
         final boolean allowsToBeAutoCorrected = AutoCorrection.allowsToBeAutoCorrected(
-                getUnigramDictionaries(), consideredWord, wordComposer.isFirstCharCapitalized());
+                getUnigramDictionaries(), consideredWord, wordComposer.isFirstCharCapitalized())
+        // If we don't have a main dictionary, we never want to auto-correct. The reason for this
+        // is, the user may have a contact whose name happens to match a valid word in their
+        // language, and it will unexpectedly auto-correct. For example, if the user types in
+        // English with no dictionary and has a "Will" in their contact list, "will" would
+        // always auto-correct to "Will" which is unwanted. Hence, no main dict => no auto-correct.
+                && mHasMainDictionary;
 
         boolean autoCorrectionAvailable = hasAutoCorrection;
         if (correctionMode == CORRECTION_FULL || correctionMode == CORRECTION_FULL_BIGRAM) {
@@ -420,8 +408,6 @@
             final String typedWord, final ArrayList<SuggestedWordInfo> suggestions) {
         final SuggestedWordInfo typedWordInfo = suggestions.get(0);
         typedWordInfo.setDebugString("+");
-        double normalizedScore = BinaryDictionary.calcNormalizedScore(
-                typedWord, typedWordInfo.toString(), typedWordInfo.mScore);
         final int suggestionsSize = suggestions.size();
         final ArrayList<SuggestedWordInfo> suggestionsList =
                 new ArrayList<SuggestedWordInfo>(suggestionsSize);
@@ -430,10 +416,11 @@
         // than i because we added the typed word to mSuggestions without touching mScores.
         for (int i = 0; i < suggestionsSize - 1; ++i) {
             final SuggestedWordInfo cur = suggestions.get(i + 1);
+            final float normalizedScore = BinaryDictionary.calcNormalizedScore(
+                    typedWord, cur.toString(), cur.mScore);
             final String scoreInfoString;
             if (normalizedScore > 0) {
                 scoreInfoString = String.format("%d (%4.2f)", cur.mScore, normalizedScore);
-                normalizedScore = 0.0;
             } else {
                 scoreInfoString = Integer.toString(cur.mScore);
             }
@@ -476,25 +463,6 @@
                 }
             }
         } else {
-            if (dataType == Dictionary.UNIGRAM) {
-                // Check if the word was already added before (by bigram data)
-                int bigramSuggestion = searchBigramSuggestion(word,offset,length);
-                if(bigramSuggestion >= 0) {
-                    dataTypeForLog = Dictionary.BIGRAM;
-                    // turn freq from bigram into multiplier specified above
-                    double multiplier = (((double) mBigramSuggestions.get(bigramSuggestion).mScore)
-                            / MAXIMUM_BIGRAM_FREQUENCY)
-                            * (BIGRAM_MULTIPLIER_MAX - BIGRAM_MULTIPLIER_MIN)
-                            + BIGRAM_MULTIPLIER_MIN;
-                    /* Log.d(TAG,"bigram num: " + bigramSuggestion
-                            + "  wordB: " + mBigramSuggestions.get(bigramSuggestion).toString()
-                            + "  currentScore: " + score + "  bigramScore: "
-                            + mBigramScores[bigramSuggestion]
-                            + "  multiplier: " + multiplier); */
-                    score = (int)Math.round((score * multiplier));
-                }
-            }
-
             // Check the last one's score and bail
             if (suggestions.size() >= prefMaxSuggestions
                     && suggestions.get(prefMaxSuggestions - 1).mScore >= score) return true;
@@ -563,7 +531,7 @@
         for (final Dictionary dictionary : dictionaries) {
             dictionary.close();
         }
-        mMainDict = null;
+        mHasMainDictionary = false;
     }
 
     // TODO: Resolve the inconsistencies between the native auto correction algorithms and
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 6f7f0c3..d7c8e38 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -79,9 +79,9 @@
     private Dictionary mContactsDictionary;
 
     // The threshold for a candidate to be offered as a suggestion.
-    private double mSuggestionThreshold;
+    private float mSuggestionThreshold;
     // The threshold for a suggestion to be considered "recommended".
-    private double mRecommendedThreshold;
+    private float mRecommendedThreshold;
     // Whether to use the contacts dictionary
     private boolean mUseContactsDictionary;
     private final Object mUseContactsLock = new Object();
@@ -113,9 +113,9 @@
     @Override public void onCreate() {
         super.onCreate();
         mSuggestionThreshold =
-                Double.parseDouble(getString(R.string.spellchecker_suggestion_threshold_value));
+                Float.parseFloat(getString(R.string.spellchecker_suggestion_threshold_value));
         mRecommendedThreshold =
-                Double.parseDouble(getString(R.string.spellchecker_recommended_threshold_value));
+                Float.parseFloat(getString(R.string.spellchecker_recommended_threshold_value));
         final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
         prefs.registerOnSharedPreferenceChangeListener(this);
         onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY);
@@ -207,8 +207,8 @@
         private final ArrayList<CharSequence> mSuggestions;
         private final int[] mScores;
         private final String mOriginalText;
-        private final double mSuggestionThreshold;
-        private final double mRecommendedThreshold;
+        private final float mSuggestionThreshold;
+        private final float mRecommendedThreshold;
         private final int mMaxLength;
         private int mLength = 0;
 
@@ -217,8 +217,8 @@
         private String mBestSuggestion = null;
         private int mBestScore = Integer.MIN_VALUE; // As small as possible
 
-        SuggestionsGatherer(final String originalText, final double suggestionThreshold,
-                final double recommendedThreshold, final int maxLength) {
+        SuggestionsGatherer(final String originalText, final float suggestionThreshold,
+                final float recommendedThreshold, final int maxLength) {
             mOriginalText = originalText;
             mSuggestionThreshold = suggestionThreshold;
             mRecommendedThreshold = recommendedThreshold;
@@ -261,7 +261,7 @@
             // Compute the normalized score and skip this word if it's normalized score does not
             // make the threshold.
             final String wordString = new String(word, wordOffset, wordLength);
-            final double normalizedScore =
+            final float normalizedScore =
                     BinaryDictionary.calcNormalizedScore(mOriginalText, wordString, score);
             if (normalizedScore < mSuggestionThreshold) {
                 if (DBG) Log.i(TAG, wordString + " does not make the score threshold");
@@ -295,7 +295,7 @@
                     hasRecommendedSuggestions = false;
                 } else {
                     gatheredSuggestions = EMPTY_STRING_ARRAY;
-                    final double normalizedScore = BinaryDictionary.calcNormalizedScore(
+                    final float normalizedScore = BinaryDictionary.calcNormalizedScore(
                             mOriginalText, mBestSuggestion, mBestScore);
                     hasRecommendedSuggestions = (normalizedScore > mRecommendedThreshold);
                 }
@@ -329,7 +329,7 @@
 
                 final int bestScore = mScores[mLength - 1];
                 final CharSequence bestSuggestion = mSuggestions.get(0);
-                final double normalizedScore =
+                final float normalizedScore =
                         BinaryDictionary.calcNormalizedScore(
                                 mOriginalText, bestSuggestion.toString(), bestScore);
                 hasRecommendedSuggestions = (normalizedScore > mRecommendedThreshold);
@@ -398,7 +398,7 @@
                 SpellCheckerProximityInfo.PROXIMITY_GRID_WIDTH,
                 SpellCheckerProximityInfo.PROXIMITY_GRID_HEIGHT);
         final DictionaryCollection dictionaryCollection =
-                DictionaryFactory.createDictionaryFromManager(this, locale,
+                DictionaryFactory.createMainDictionaryFromManager(this, locale,
                         true /* useFullEditDistance */);
         final String localeStr = locale.toString();
         Dictionary userDictionary = mUserDictionaries.get(localeStr);
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index dd83a0c..c6fe43b 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -56,8 +56,6 @@
                 clearKeys();
                 final Resources res = view.getContext().getResources();
                 mDivider = res.getDrawable(R.drawable.more_suggestions_divider);
-                // TODO: Drawable itself should have an alpha value.
-                mDivider.setAlpha(128);
                 mDividerWidth = mDivider.getIntrinsicWidth();
                 final int padding = (int) res.getDimension(
                         R.dimen.more_suggestions_key_horizontal_padding);
@@ -195,7 +193,11 @@
             }
 
             @Override
-            public Drawable getIcon(KeyboardIconsSet iconSet) {
+            public Drawable getIcon(KeyboardIconsSet iconSet, int alpha) {
+                // KeyboardIconsSet and alpha are unused. Use the icon that has been passed to the
+                // constructor.
+                // TODO: Drawable itself should have an alpha value.
+                mIcon.setAlpha(128);
                 return mIcon;
             }
         }
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index b8f4ec7..f130062 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -20,6 +20,7 @@
 #include "binary_format.h"
 #include "correction.h"
 #include "com_android_inputmethod_latin_BinaryDictionary.h"
+#include "defines.h"
 #include "dictionary.h"
 #include "jni.h"
 #include "jni_common.h"
@@ -196,11 +197,11 @@
     return result;
 }
 
-static jdouble latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jobject object,
+static jfloat latinime_BinaryDictionary_calcNormalizedScore(JNIEnv *env, jobject object,
         jcharArray before, jint beforeLength, jcharArray after, jint afterLength, jint score) {
     jchar *beforeChars = env->GetCharArrayElements(before, 0);
     jchar *afterChars = env->GetCharArrayElements(after, 0);
-    jdouble result = Correction::RankingAlgorithm::calcNormalizedScore((unsigned short*)beforeChars,
+    jfloat result = Correction::RankingAlgorithm::calcNormalizedScore((unsigned short*)beforeChars,
             beforeLength, (unsigned short*)afterChars, afterLength, score);
     env->ReleaseCharArrayElements(after, afterChars, JNI_ABORT);
     env->ReleaseCharArrayElements(before, beforeChars, JNI_ABORT);
@@ -255,7 +256,7 @@
     {"isValidWordNative", "(J[II)Z", (void*)latinime_BinaryDictionary_isValidWord},
     {"isValidBigramNative", "(J[I[I)Z", (void*)latinime_BinaryDictionary_isValidBigram},
     {"getBigramsNative", "(J[II[II[C[III)I", (void*)latinime_BinaryDictionary_getBigrams},
-    {"calcNormalizedScoreNative", "([CI[CII)D",
+    {"calcNormalizedScoreNative", "([CI[CII)F",
             (void*)latinime_BinaryDictionary_calcNormalizedScore},
     {"editDistanceNative", "([CI[CI)I", (void*)latinime_BinaryDictionary_editDistance}
 };
diff --git a/native/jni/jni_common.cpp b/native/jni/jni_common.cpp
index 85d2683..b9e2c32 100644
--- a/native/jni/jni_common.cpp
+++ b/native/jni/jni_common.cpp
@@ -19,6 +19,7 @@
 
 #include "com_android_inputmethod_keyboard_ProximityInfo.h"
 #include "com_android_inputmethod_latin_BinaryDictionary.h"
+#include "defines.h"
 #include "jni.h"
 #include "proximity_info.h"
 
diff --git a/native/jni/src/bigram_dictionary.cpp b/native/jni/src/bigram_dictionary.cpp
index 7ed4dc4..ac2a261 100644
--- a/native/jni/src/bigram_dictionary.cpp
+++ b/native/jni/src/bigram_dictionary.cpp
@@ -22,6 +22,7 @@
 #include "bigram_dictionary.h"
 #include "binary_format.h"
 #include "bloom_filter.h"
+#include "defines.h"
 #include "dictionary.h"
 
 namespace latinime {
diff --git a/native/jni/src/correction.cpp b/native/jni/src/correction.cpp
index a1f8129..5ae34cd 100644
--- a/native/jni/src/correction.cpp
+++ b/native/jni/src/correction.cpp
@@ -1113,7 +1113,7 @@
 // So, we can normalize original score by dividing pow(2, min(b.l(),a.l())) * 255 * 2.
 
 /* static */
-double Correction::RankingAlgorithm::calcNormalizedScore(const unsigned short* before,
+float Correction::RankingAlgorithm::calcNormalizedScore(const unsigned short* before,
         const int beforeLength, const unsigned short* after, const int afterLength,
         const int score) {
     if (0 == beforeLength || 0 == afterLength) {
@@ -1131,14 +1131,14 @@
         return 0;
     }
 
-    const double maxScore = score >= S_INT_MAX ? S_INT_MAX : MAX_INITIAL_SCORE
-            * pow((double)TYPED_LETTER_MULTIPLIER,
-                    (double)min(beforeLength, afterLength - spaceCount)) * FULL_WORD_MULTIPLIER;
+    const float maxScore = score >= S_INT_MAX ? S_INT_MAX : MAX_INITIAL_SCORE
+            * pow((float)TYPED_LETTER_MULTIPLIER,
+                    (float)min(beforeLength, afterLength - spaceCount)) * FULL_WORD_MULTIPLIER;
 
     // add a weight based on edit distance.
     // distance <= max(afterLength, beforeLength) == afterLength,
     // so, 0 <= distance / afterLength <= 1
-    const double weight = 1.0 - (double) distance / afterLength;
+    const float weight = 1.0 - (float) distance / afterLength;
     return (score / maxScore) * weight;
 }
 
diff --git a/native/jni/src/correction.h b/native/jni/src/correction.h
index 1b4e4bf..1ac4b87 100644
--- a/native/jni/src/correction.h
+++ b/native/jni/src/correction.h
@@ -162,7 +162,7 @@
         static int calcFreqForSplitMultipleWords(const int *freqArray, const int *wordLengthArray,
                 const int wordCount, const Correction* correction, const bool isSpaceProximity,
                 const unsigned short *word);
-        static double calcNormalizedScore(const unsigned short* before, const int beforeLength,
+        static float calcNormalizedScore(const unsigned short* before, const int beforeLength,
                 const unsigned short* after, const int afterLength, const int score);
         static int editDistance(const unsigned short* before,
                 const int beforeLength, const unsigned short* after, const int afterLength);
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index cb3dbb1..c6ad66a 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -46,8 +46,8 @@
 #include <time.h>
 
 #define PROF_BUF_SIZE 100
-static double profile_buf[PROF_BUF_SIZE];
-static double profile_old[PROF_BUF_SIZE];
+static float profile_buf[PROF_BUF_SIZE];
+static float profile_old[PROF_BUF_SIZE];
 static unsigned int profile_counter[PROF_BUF_SIZE];
 
 #define PROF_RESET               prof_reset()
@@ -74,8 +74,8 @@
         AKLOGI("Error: You must call PROF_OPEN before PROF_CLOSE.");
     }
     AKLOGI("Total time is %6.3f ms.",
-            profile_buf[PROF_BUF_SIZE - 1] * 1000 / (double)CLOCKS_PER_SEC);
-    double all = 0;
+            profile_buf[PROF_BUF_SIZE - 1] * 1000 / (float)CLOCKS_PER_SEC);
+    float all = 0;
     for (int i = 0; i < PROF_BUF_SIZE - 1; ++i) {
         all += profile_buf[i];
     }
@@ -84,7 +84,7 @@
         if (profile_buf[i] != 0) {
             AKLOGI("(%d): Used %4.2f%%, %8.4f ms. Called %d times.",
                     i, (profile_buf[i] * 100 / all),
-                    profile_buf[i] * 1000 / (double)CLOCKS_PER_SEC, profile_counter[i]);
+                    profile_buf[i] * 1000 / (float)CLOCKS_PER_SEC, profile_counter[i]);
         }
     }
 }
diff --git a/native/jni/src/dictionary.cpp b/native/jni/src/dictionary.cpp
index 8ea7c49..65d0f73 100644
--- a/native/jni/src/dictionary.cpp
+++ b/native/jni/src/dictionary.cpp
@@ -20,6 +20,7 @@
 #define LOG_TAG "LatinIME: dictionary.cpp"
 
 #include "binary_format.h"
+#include "defines.h"
 #include "dictionary.h"
 
 namespace latinime {
diff --git a/native/jni/src/proximity_info.cpp b/native/jni/src/proximity_info.cpp
index c00c4c2..960d401 100644
--- a/native/jni/src/proximity_info.cpp
+++ b/native/jni/src/proximity_info.cpp
@@ -21,6 +21,7 @@
 #define LOG_TAG "LatinIME: proximity_info.cpp"
 
 #include "additional_proximity_chars.h"
+#include "defines.h"
 #include "dictionary.h"
 #include "proximity_info.h"
 
diff --git a/native/jni/src/unigram_dictionary.cpp b/native/jni/src/unigram_dictionary.cpp
index 9234b1b..3c826e9 100644
--- a/native/jni/src/unigram_dictionary.cpp
+++ b/native/jni/src/unigram_dictionary.cpp
@@ -21,6 +21,7 @@
 #define LOG_TAG "LatinIME: unigram_dictionary.cpp"
 
 #include "char_utils.h"
+#include "defines.h"
 #include "dictionary.h"
 #include "unigram_dictionary.h"
 
@@ -202,16 +203,17 @@
 
     PROF_START(20);
     if (DEBUG_DICT) {
-        double ns = queuePool->getMasterQueue()->getHighestNormalizedScore(
+        float ns = queuePool->getMasterQueue()->getHighestNormalizedScore(
                 proximityInfo->getPrimaryInputWord(), codesSize, 0, 0, 0);
         ns += 0;
         AKLOGI("Max normalized score = %f", ns);
     }
     const int suggestedWordsCount =
-            queuePool->getMasterQueue()->outputSuggestions(frequencies, outWords);
+            queuePool->getMasterQueue()->outputSuggestions(
+                    proximityInfo->getPrimaryInputWord(), codesSize, frequencies, outWords);
 
     if (DEBUG_DICT) {
-        double ns = queuePool->getMasterQueue()->getHighestNormalizedScore(
+        float ns = queuePool->getMasterQueue()->getHighestNormalizedScore(
                 proximityInfo->getPrimaryInputWord(), codesSize, 0, 0, 0);
         ns += 0;
         AKLOGI("Returning %d words", suggestedWordsCount);
@@ -254,7 +256,7 @@
     bool hasAutoCorrectionCandidate = false;
     WordsPriorityQueue* masterQueue = queuePool->getMasterQueue();
     if (masterQueue->size() > 0) {
-        double nsForMaster = masterQueue->getHighestNormalizedScore(
+        float nsForMaster = masterQueue->getHighestNormalizedScore(
                 proximityInfo->getPrimaryInputWord(), inputLength, 0, 0, 0);
         hasAutoCorrectionCandidate = (nsForMaster > START_TWO_WORDS_CORRECTION_THRESHOLD);
     }
@@ -283,7 +285,7 @@
                 const int score = sw->mScore;
                 const unsigned short* word = sw->mWord;
                 const int wordLength = sw->mWordLength;
-                double ns = Correction::RankingAlgorithm::calcNormalizedScore(
+                float ns = Correction::RankingAlgorithm::calcNormalizedScore(
                         proximityInfo->getPrimaryInputWord(), i, word, wordLength, score);
                 ns += 0;
                 AKLOGI("--- TOP SUB WORDS for %d --- %d %f [%d]", i, score, ns,
@@ -451,7 +453,7 @@
             return false;
         }
         int score = 0;
-        const double ns = queue->getHighestNormalizedScore(
+        const float ns = queue->getHighestNormalizedScore(
                 proximityInfo->getPrimaryInputWord(), inputWordLength,
                 &tempOutputWord, &score, &nextWordLength);
         if (DEBUG_DICT) {
diff --git a/native/jni/src/words_priority_queue.h b/native/jni/src/words_priority_queue.h
index 249962e..7629251 100644
--- a/native/jni/src/words_priority_queue.h
+++ b/native/jni/src/words_priority_queue.h
@@ -92,10 +92,12 @@
         return sw;
     }
 
-    int outputSuggestions(int *frequencies, unsigned short *outputChars) {
+    int outputSuggestions(const unsigned short* before, const int beforeLength,
+            int *frequencies, unsigned short *outputChars) {
         mHighestSuggestedWord = 0;
         const unsigned int size = min(
               MAX_WORDS, static_cast<unsigned int>(mSuggestions.size()));
+        SuggestedWord* swBuffer[size];
         int index = size - 1;
         while (!mSuggestions.empty() && index >= 0) {
             SuggestedWord* sw = mSuggestions.top();
@@ -103,17 +105,45 @@
                 AKLOGI("dump word. %d", sw->mScore);
                 DUMP_WORD(sw->mWord, sw->mWordLength);
             }
+            swBuffer[index] = sw;
+            mSuggestions.pop();
+            --index;
+        }
+        if (size >= 2) {
+            SuggestedWord* nsMaxSw = 0;
+            unsigned int maxIndex = 0;
+            float maxNs = 0;
+            for (unsigned int i = 0; i < size; ++i) {
+                SuggestedWord* tempSw = swBuffer[i];
+                if (!tempSw) {
+                    continue;
+                }
+                const float tempNs = getNormalizedScore(tempSw, before, beforeLength, 0, 0, 0);
+                if (tempNs >= maxNs) {
+                    maxNs = tempNs;
+                    maxIndex = i;
+                    nsMaxSw = tempSw;
+                }
+            }
+            if (maxIndex > 0 && nsMaxSw) {
+                memmove(&swBuffer[1], &swBuffer[0], maxIndex * sizeof(SuggestedWord*));
+                swBuffer[0] = nsMaxSw;
+            }
+        }
+        for (unsigned int i = 0; i < size; ++i) {
+            SuggestedWord* sw = swBuffer[i];
+            if (!sw) {
+                AKLOGE("SuggestedWord is null %d", i);
+                continue;
+            }
             const unsigned int wordLength = sw->mWordLength;
-            char* targetAdr = (char*) outputChars
-                    + (index) * MAX_WORD_LENGTH * sizeof(short);
-            frequencies[index] = sw->mScore;
+            char* targetAdr = (char*) outputChars + i * MAX_WORD_LENGTH * sizeof(short);
+            frequencies[i] = sw->mScore;
             memcpy(targetAdr, sw->mWord, (wordLength) * sizeof(short));
             if (wordLength < MAX_WORD_LENGTH) {
                 ((unsigned short*) targetAdr)[wordLength] = 0;
             }
             sw->mUsed = false;
-            mSuggestions.pop();
-            --index;
         }
         return size;
     }
@@ -142,26 +172,13 @@
         DUMP_WORD(mHighestSuggestedWord->mWord, mHighestSuggestedWord->mWordLength);
     }
 
-    double getHighestNormalizedScore(const unsigned short* before, const int beforeLength,
+    float getHighestNormalizedScore(const unsigned short* before, const int beforeLength,
             unsigned short** outWord, int *outScore, int *outLength) {
         if (!mHighestSuggestedWord) {
             return 0.0;
         }
-        SuggestedWord* sw = mHighestSuggestedWord;
-        const int score = sw->mScore;
-        unsigned short* word = sw->mWord;
-        const int wordLength = sw->mWordLength;
-        if (outScore) {
-            *outScore = score;
-        }
-        if (outWord) {
-            *outWord = word;
-        }
-        if (outLength) {
-            *outLength = wordLength;
-        }
-        return Correction::RankingAlgorithm::calcNormalizedScore(
-                before, beforeLength, word, wordLength, score);
+        return getNormalizedScore(
+                mHighestSuggestedWord, before, beforeLength, outWord, outScore, outLength);
     }
 
  private:
@@ -182,6 +199,24 @@
         return 0;
     }
 
+    static float getNormalizedScore(SuggestedWord* sw, const unsigned short* before,
+            const int beforeLength, unsigned short** outWord, int *outScore, int *outLength) {
+        const int score = sw->mScore;
+        unsigned short* word = sw->mWord;
+        const int wordLength = sw->mWordLength;
+        if (outScore) {
+            *outScore = score;
+        }
+        if (outWord) {
+            *outWord = word;
+        }
+        if (outLength) {
+            *outLength = wordLength;
+        }
+        return Correction::RankingAlgorithm::calcNormalizedScore(
+                before, beforeLength, word, wordLength, score);
+    }
+
     typedef std::priority_queue<SuggestedWord*, std::vector<SuggestedWord*>,
             wordComparator> Suggestions;
     Suggestions mSuggestions;