Merge "Reorder suggestions result according to auto correction threshold" 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/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/latin/AdditionalSubtypeSettings.java b/java/src/com/android/inputmethod/latin/AdditionalSubtypeSettings.java
index be807ab..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> {
@@ -131,6 +139,7 @@
 
     private interface SubtypeDialogProxy {
         public void onRemovePressed(SubtypePreference subtypePref);
+        public void onAddPressed(SubtypePreference subtypePref);
         public SubtypeLocaleAdapter getSubtypeLocaleAdapter();
         public KeyboardLayoutSetAdapter getKeyboardLayoutSetAdapter();
     }
@@ -241,6 +250,7 @@
             super.onClick(dialog, which);
             switch (which) {
             case DialogInterface.BUTTON_POSITIVE:
+                final boolean addPressed = isIncomplete();
                 final SubtypeLocaleItem locale =
                         (SubtypeLocaleItem) mSubtypeLocaleSpinner.getSelectedItem();
                 final KeyboardLayoutSetItem layout =
@@ -249,6 +259,9 @@
                         locale.first, layout.first, ASCII_CAPABLE);
                 setSubtype(subtype);
                 notifyChanged();
+                if (addPressed) {
+                    mProxy.onAddPressed(this);
+                }
                 break;
             case DialogInterface.BUTTON_NEUTRAL:
                 // Nothing to do
@@ -363,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);
         }
     }
 
@@ -391,6 +420,15 @@
         }
 
         @Override
+        public void onAddPressed(SubtypePreference subtypePref) {
+            mIsAddingNewSubtype = false;
+            setAdditionalInputMethodSubtypes(getPrefSubtypes());
+            mSubtypePreferenceKeyForSubtypeEnabler = subtypePref.getKey();
+            mSubtypeEnablerNotificationDialog = createDialog(subtypePref);
+            mSubtypeEnablerNotificationDialog.show();
+        }
+
+        @Override
         public SubtypeLocaleAdapter getSubtypeLocaleAdapter() {
             return mSubtypeLocaleAdapter;
         }
@@ -401,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();
@@ -448,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/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/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index ad2004a..d7cd057 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 =
@@ -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() {
@@ -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) {
@@ -475,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;
@@ -562,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/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
index 830fbf0..563f8a9 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java
@@ -765,14 +765,39 @@
             bigramFrequency = unigramFrequency;
         }
         // We compute the difference between 255 (which means probability = 1) and the
-        // unigram score. We split this into discrete 16 steps, and this is the value
-        // we store into the 4 bits of the bigrams frequency.
-        final float bigramRatio = (float)(bigramFrequency - unigramFrequency)
-                / (MAX_TERMINAL_FREQUENCY - unigramFrequency);
-        // TODO: if the bigram freq is very close to the unigram frequency, we don't want
-        // to include the bigram in the binary dictionary at all.
-        final int discretizedFrequency = Math.round(bigramRatio * MAX_BIGRAM_FREQUENCY);
-        bigramFlags += discretizedFrequency & FLAG_ATTRIBUTE_FREQUENCY;
+        // unigram score. We split this into a number of discrete steps.
+        // Now, the steps are numbered 0~15; 0 represents an increase of 1 step while 15
+        // represents an increase of 16 steps: a value of 15 will be interpreted as the median
+        // value of the 16th step. In all justice, if the bigram frequency is low enough to be
+        // rounded below the first step (which means it is less than half a step higher than the
+        // unigram frequency) then the unigram frequency itself is the best approximation of the
+        // bigram freq that we could possibly supply, hence we should *not* include this bigram
+        // in the file at all.
+        // until this is done, we'll write 0 and slightly overestimate this case.
+        // In other words, 0 means "between 0.5 step and 1.5 step", 1 means "between 1.5 step
+        // and 2.5 steps", and 15 means "between 15.5 steps and 16.5 steps". So we want to
+        // divide our range [unigramFreq..MAX_TERMINAL_FREQUENCY] in 16.5 steps to get the
+        // step size. Then we compute the start of the first step (the one where value 0 starts)
+        // by adding half-a-step to the unigramFrequency. From there, we compute the integer
+        // number of steps to the bigramFrequency. One last thing: we want our steps to include
+        // 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.
+        final double stepSize =
+                (double)(MAX_TERMINAL_FREQUENCY - unigramFrequency) / (1.5 + MAX_BIGRAM_FREQUENCY);
+        final double firstStepStart = 1 + unigramFrequency + (stepSize / 2.0);
+        final int discretizedFrequency = (int)((bigramFrequency - firstStepStart) / stepSize);
+        // If the bigram freq is less than half-a-step higher than the unigram freq, we get -1
+        // here. The best approximation would be the unigram freq itself, so we should not
+        // include this bigram in the dictionary. For now, register as 0, and live with the
+        // small over-estimation that we get in this case. TODO: actually remove this bigram
+        // if discretizedFrequency < 0.
+        final int finalBigramFrequency = discretizedFrequency > 0 ? discretizedFrequency : 0;
+        bigramFlags += finalBigramFrequency & FLAG_ATTRIBUTE_FREQUENCY;
         return bigramFlags;
     }
 
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 6f7f0c3..0c9f9fb 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -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/src/correction.cpp b/native/jni/src/correction.cpp
index 376e9a1..a1f8129 100644
--- a/native/jni/src/correction.cpp
+++ b/native/jni/src/correction.cpp
@@ -344,8 +344,10 @@
                 mDistances[mOutputIndex] =
                         mProximityInfo->getNormalizedSquaredDistance(mInputIndex, proximityIndex);
             }
-            incrementInputIndex();
-            incremented = true;
+            if (!isQuote(c)) {
+                incrementInputIndex();
+                incremented = true;
+            }
         }
         return processSkipChar(c, isTerminal, incremented);
     }
@@ -710,7 +712,7 @@
         ed = max(0, ed - quoteDiffCount);
         adjustedProximityMatchedCount = min(max(0, ed - (outputLength - inputLength)),
                 proximityMatchedCount);
-        if (transposedCount < 1) {
+        if (transposedCount <= 0) {
             if (ed == 1 && (inputLength == outputLength - 1 || inputLength == outputLength + 1)) {
                 // Promote a word with just one skipped or excessive char
                 if (sameLength) {