diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 834d3ed5346bcb2726e5d15a88df3692b05500dd..dacb8483c2e07d469176ae8e80ca4f8efff26229 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -40,6 +40,9 @@ public final class BinaryDictionary extends Dictionary {
     private static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH;
     // Must be equal to MAX_RESULTS in native/jni/src/defines.h
     private static final int MAX_RESULTS = 18;
+    // Required space count for auto commit.
+    // TODO: Remove this heuristic.
+    private static final int SPACE_COUNT_FOR_AUTO_COMMIT = 3;
 
     private long mNativeDict;
     private final Locale mLocale;
@@ -49,6 +52,7 @@ public final class BinaryDictionary extends Dictionary {
     private final int[] mSpaceIndices = new int[MAX_RESULTS];
     private final int[] mOutputScores = new int[MAX_RESULTS];
     private final int[] mOutputTypes = new int[MAX_RESULTS];
+    private final int[] mOutputAutoCommitFirstWordConfidence = new int[1]; // Only one result
 
     private final NativeSuggestOptions mNativeSuggestOptions = new NativeSuggestOptions();
 
@@ -104,7 +108,8 @@ public final class BinaryDictionary extends Dictionary {
             long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times,
             int[] pointerIds, int[] inputCodePoints, int inputSize, int commitPoint,
             int[] suggestOptions, int[] prevWordCodePointArray,
-            int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes);
+            int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes,
+            int[] outputAutoCommitFirstWordConfidence);
     private static native float calcNormalizedScoreNative(int[] before, int[] after, int score);
     private static native int editDistanceNative(int[] before, int[] after);
     private static native void addUnigramWordNative(long dict, int[] word, int probability);
@@ -157,7 +162,7 @@ public final class BinaryDictionary extends Dictionary {
                 ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodePoints,
                 inputSize, 0 /* commitPoint */, mNativeSuggestOptions.getOptions(),
                 prevWordCodePointArray, mOutputCodePoints, mOutputScores, mSpaceIndices,
-                mOutputTypes);
+                mOutputTypes, mOutputAutoCommitFirstWordConfidence);
         final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
         for (int j = 0; j < count; ++j) {
             final int start = j * MAX_WORD_LENGTH;
@@ -181,7 +186,8 @@ public final class BinaryDictionary extends Dictionary {
                 // flags too and pass mOutputTypes[j] instead of kind
                 suggestions.add(new SuggestedWordInfo(new String(mOutputCodePoints, start, len),
                         score, kind, this /* sourceDict */,
-                        mSpaceIndices[0] /* indexOfTouchPointOfSecondWord */));
+                        mSpaceIndices[0] /* indexOfTouchPointOfSecondWord */,
+                        mOutputAutoCommitFirstWordConfidence[0]));
             }
         }
         return suggestions;
@@ -255,6 +261,22 @@ public final class BinaryDictionary extends Dictionary {
         removeBigramWordsNative(mNativeDict, codePoints0, codePoints1);
     }
 
+    @Override
+    public boolean shouldAutoCommit(final SuggestedWordInfo candidate) {
+        // TODO: actually use the confidence rather than use this completely broken heuristic
+        final String word = candidate.mWord;
+        final int length = word.length();
+        int remainingSpaces = SPACE_COUNT_FOR_AUTO_COMMIT;
+        for (int i = 0; i < length; ++i) {
+            // This is okay because no low-surrogate and no high-surrogate can ever match the
+            // space character, so we don't need to take care of iterating on code points.
+            if (Constants.CODE_SPACE == word.charAt(i)) {
+                if (0 >= --remainingSpaces) return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public void close() {
         synchronized (mDicTraverseSessions) {
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 8a3a884387504d189a9f5140a998ac3df6462486..fa79f5af7ddb56e972aaf1172e16e9cb2db7cefa 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -137,7 +137,10 @@ public abstract class Dictionary {
     }
 
     /**
-     * Whether we think this suggestion should trigger an auto-commit.
+     * Whether we think this suggestion should trigger an auto-commit. prevWord is the word
+     * before the suggestion, so that we can use n-gram frequencies.
+     * @param candidate The candidate suggestion, in whole (not only the first part).
+     * @return whether we should auto-commit or not.
      */
     public boolean shouldAutoCommit(final SuggestedWordInfo candidate) {
         // If we don't have support for auto-commit, or if we don't know, we return false to
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index ba7d1a2b0f08aac5155a421069d594d3a68a076e..d491f988ae082f294ad3649869d196c9ff737678 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -344,7 +344,8 @@ public class ExpandableDictionary extends Dictionary {
             // in the future.
             suggestions.add(new SuggestedWordInfo(new String(word, 0, depth + 1), finalFreq,
                     SuggestedWordInfo.KIND_CORRECTION, this /* sourceDict */,
-                    SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+                    SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                    SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
             if (suggestions.size() >= Suggest.MAX_SUGGESTIONS) return false;
         }
         if (null != node.mShortcutTargets) {
@@ -353,7 +354,8 @@ public class ExpandableDictionary extends Dictionary {
                 final char[] shortcut = node.mShortcutTargets.get(shortcutIndex);
                 suggestions.add(new SuggestedWordInfo(new String(shortcut, 0, shortcut.length),
                         finalFreq, SuggestedWordInfo.KIND_SHORTCUT, this /* sourceDict */,
-                        SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+                        SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                        SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
                 if (suggestions.size() > Suggest.MAX_SUGGESTIONS) return false;
             }
         }
@@ -604,7 +606,8 @@ public class ExpandableDictionary extends Dictionary {
                 suggestions.add(new SuggestedWordInfo(new String(mLookedUpString, index,
                         Constants.DICTIONARY_MAX_WORD_LENGTH - index),
                         freq, SuggestedWordInfo.KIND_CORRECTION, this /* sourceDict */,
-                        SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+                        SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                        SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
             }
         }
     }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5657ed7790f1e51bce77c5d599c23c268a09a78e..d8a47a3076f260e25992afee2788386a33fb278b 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -2702,7 +2702,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                     suggestions.add(new SuggestedWordInfo(s,
                             SuggestionStripView.MAX_SUGGESTIONS - i,
                             SuggestedWordInfo.KIND_RESUMED, Dictionary.DICTIONARY_RESUMED,
-                            SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+                            SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                            SuggestedWordInfo.NOT_A_CONFIDENCE
+                                    /* autoCommitFirstWordConfidence */));
                 }
             }
         }
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 9370757ecc4d62fdf63b61f84fbb25827f9aed6f..7815f4d410de7ce7b3fc2bc7b2e72d3bfae19915 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -327,7 +327,8 @@ public final class Suggest {
             suggestionsContainer.add(0, new SuggestedWordInfo(typedWord,
                     SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_TYPED,
                     Dictionary.DICTIONARY_USER_TYPED,
-                    SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+                    SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                    SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
         }
         SuggestedWordInfo.removeDups(suggestionsContainer);
 
@@ -474,7 +475,8 @@ public final class Suggest {
             sb.appendCodePoint(Constants.CODE_SINGLE_QUOTE);
         }
         return new SuggestedWordInfo(sb.toString(), wordInfo.mScore, wordInfo.mKind,
-                wordInfo.mSourceDict, wordInfo.mIndexOfTouchPointOfSecondWord);
+                wordInfo.mSourceDict, wordInfo.mIndexOfTouchPointOfSecondWord,
+                SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
     }
 
     public void close() {
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index b27fd81e9421d88ff27b56d10e63001dffdc186f..17637054a89dcd3ecf6be004b247e4de076dd5db 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -114,7 +114,8 @@ public final class SuggestedWords {
             final SuggestedWordInfo suggestedWordInfo = new SuggestedWordInfo(text.toString(),
                     SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_APP_DEFINED,
                     Dictionary.DICTIONARY_APPLICATION_DEFINED,
-                    SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */);
+                    SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                    SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
             result.add(suggestedWordInfo);
         }
         return result;
@@ -128,7 +129,8 @@ public final class SuggestedWords {
         final HashSet<String> alreadySeen = CollectionUtils.newHashSet();
         suggestionsList.add(new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE,
                 SuggestedWordInfo.KIND_TYPED, Dictionary.DICTIONARY_USER_TYPED,
-                SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+                SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
         alreadySeen.add(typedWord.toString());
         final int previousSize = previousSuggestions.size();
         for (int index = 1; index < previousSize; index++) {
@@ -151,6 +153,7 @@ public final class SuggestedWords {
 
     public static final class SuggestedWordInfo {
         public static final int NOT_AN_INDEX = -1;
+        public static final int NOT_A_CONFIDENCE = -1;
         public static final int MAX_SCORE = Integer.MAX_VALUE;
         public static final int KIND_MASK_KIND = 0xFF; // Mask to get only the kind
         public static final int KIND_TYPED = 0; // What user typed
@@ -180,16 +183,30 @@ public final class SuggestedWords {
         // passed to native code to get suggestions for a gesture that corresponds to the first
         // letter of the second word.
         public final int mIndexOfTouchPointOfSecondWord;
+        // For auto-commit. This is a measure of how confident we are that we can commit the
+        // first word of this suggestion.
+        public final int mAutoCommitFirstWordConfidence;
         private String mDebugString = "";
 
+        /**
+         * Create a new suggested word info.
+         * @param word The string to suggest.
+         * @param score A measure of how likely this suggestion is.
+         * @param kind The kind of suggestion, as one of the above KIND_* constants.
+         * @param sourceDict What instance of Dictionary produced this suggestion.
+         * @param indexOfTouchPointOfSecondWord See mIndexOfTouchPointOfSecondWord.
+         * @param autoCommitFirstWordConfidence See mAutoCommitFirstWordConfidence.
+         */
         public SuggestedWordInfo(final String word, final int score, final int kind,
-                final Dictionary sourceDict, final int indexOfTouchPointOfSecondWord) {
+                final Dictionary sourceDict, final int indexOfTouchPointOfSecondWord,
+                final int autoCommitFirstWordConfidence) {
             mWord = word;
             mScore = score;
             mKind = kind;
             mSourceDict = sourceDict;
             mCodePointCount = StringUtils.codePointCount(mWord);
             mIndexOfTouchPointOfSecondWord = indexOfTouchPointOfSecondWord;
+            mAutoCommitFirstWordConfidence = autoCommitFirstWordConfidence;
         }
 
         public boolean isEligibleForAutoCommit() {
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index 072bb8731010a22673a19daf8432d2d3cdbabce5..fc2d19298783d0f141df350be9e0d5ea933a3e61 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -295,7 +295,8 @@ public final class SettingsValues {
                 puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec),
                         SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED,
                         Dictionary.DICTIONARY_HARDCODED,
-                        SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+                        SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                        SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
             }
         }
         return new SuggestedWords(puncList,
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 8da1859c4e6bc1bb5b36fed9adef768ab5ad7965..6a366121d7989197f4b11c4d46b4fc6e9a462f7f 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -70,7 +70,8 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, j
         jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdsArray,
         jintArray inputCodePointsArray, jint inputSize, jint commitPoint, jintArray suggestOptions,
         jintArray prevWordCodePointsForBigrams, jintArray outputCodePointsArray,
-        jintArray scoresArray, jintArray spaceIndicesArray, jintArray outputTypesArray) {
+        jintArray scoresArray, jintArray spaceIndicesArray, jintArray outputTypesArray,
+        jintArray outputAutoCommitFirstWordConfidence) {
     Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
     if (!dictionary) return 0;
     ProximityInfo *pInfo = reinterpret_cast<ProximityInfo *>(proximityInfo);
@@ -253,7 +254,7 @@ static const JNINativeMethod sMethods[] = {
     },
     {
         const_cast<char *>("getSuggestionsNative"),
-        const_cast<char *>("(JJJ[I[I[I[I[III[I[I[I[I[I[I)I"),
+        const_cast<char *>("(JJJ[I[I[I[I[III[I[I[I[I[I[I[I)I"),
         reinterpret_cast<void *>(latinime_BinaryDictionary_getSuggestions)
     },
     {
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index 2603b35f5721b7677735e6693183a870c6e66e5d..234bb1b31cb059399709c41ff4956cabc0aeb6b8 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -259,7 +259,8 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
     protected void pickSuggestionManually(final int index, final String suggestion) {
         mLatinIME.pickSuggestionManually(index, new SuggestedWordInfo(suggestion, 1,
                 SuggestedWordInfo.KIND_CORRECTION, null /* sourceDict */,
-                SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+                SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
     }
 
     // Helper to avoid writing the try{}catch block each time
diff --git a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
index a5f3685daec58959696b3ce65b4d10ad8112e990..4cf83339a7e015fe9dd7a94c430472ffca5a21a2 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
@@ -35,11 +35,13 @@ public class SuggestedWordsTests extends AndroidTestCase {
         final ArrayList<SuggestedWordInfo> list = CollectionUtils.newArrayList();
         list.add(new SuggestedWordInfo(TYPED_WORD, TYPED_WORD_FREQ,
                 SuggestedWordInfo.KIND_TYPED, null /* sourceDict */,
-                SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+                SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
         for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) {
             list.add(new SuggestedWordInfo("" + i, 1, SuggestedWordInfo.KIND_CORRECTION,
                     null /* sourceDict */,
-                    SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+                    SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+                    SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
         }
 
         final SuggestedWords words = new SuggestedWords(