Merge "Pass the touch position correction flag from KeyboardSwitcher."
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index bcce581..a3e8d4a 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -24,7 +24,6 @@
     <bool name="config_default_show_settings_key">false</bool>
     <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_show_recorrection_option">false</bool>
     <bool name="config_enable_bigram_suggestions_option">true</bool>
     <bool name="config_enable_usability_study_mode_option">false</bool>
     <bool name="config_sliding_key_input_enabled">true</bool>
@@ -37,7 +36,6 @@
     <!-- Default value for bigram prediction: after entering a word and a space only, should we look
          at input history to suggest a hopefully helpful suggestions for the next word? -->
     <bool name="config_default_bigram_prediction">false</bool>
-    <bool name="config_default_compat_recorrection_enabled">true</bool>
     <bool name="config_default_sound_enabled">false</bool>
     <bool name="config_default_vibration_enabled">true</bool>
     <bool name="config_auto_correction_spacebar_led_enabled">true</bool>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 9b3829f..a1f3488 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -326,10 +326,6 @@
     <string name="prefs_enable_log">Enable user feedback</string>
     <!-- Description for enabling to send user statistics to Google -->
     <string name="prefs_description_log">Help improve this input method editor by automatically sending usage statistics and crash reports to Google.</string>
-    <!-- Preferences item for enabling to correct suggestions by touching words you have typed [CHAR LIMIT= 35] -->
-    <string name="prefs_enable_recorrection">Touch to correct words</string>
-    <!-- The summary for the preferences item for enabling to correct suggestions by touching words you have typed [CHAR LIMIT= 100] -->
-    <string name="prefs_enable_recorrection_summary">Touch entered words to correct them, only when suggestions are visible</string>
 
     <!-- Title of the item to change the keyboard theme [CHAR LIMIT=20]-->
     <string name="keyboard_layout">Keyboard theme</string>
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index 312af28..b54df26 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -45,12 +45,6 @@
             android:persistent="true"
             android:defaultValue="@bool/config_default_popup_preview" />
         <CheckBoxPreference
-            android:key="recorrection_enabled"
-            android:title="@string/prefs_enable_recorrection"
-            android:summary="@string/prefs_enable_recorrection_summary"
-            android:persistent="true"
-            android:defaultValue="@bool/config_default_compat_recorrection_enabled" />
-        <CheckBoxPreference
             android:key="show_settings_key"
             android:title="@string/prefs_settings_key"
             android:persistent="true"
diff --git a/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java b/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java
deleted file mode 100644
index 94615a7..0000000
--- a/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.inputmethod.deprecated.recorrection;
-
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.text.TextUtils;
-import android.view.inputmethod.ExtractedText;
-import android.view.inputmethod.ExtractedTextRequest;
-import android.view.inputmethod.InputConnection;
-
-import com.android.inputmethod.compat.InputConnectionCompatUtils;
-import com.android.inputmethod.compat.SuggestionSpanUtils;
-import com.android.inputmethod.deprecated.VoiceProxy;
-import com.android.inputmethod.keyboard.KeyboardSwitcher;
-import com.android.inputmethod.latin.AutoCorrection;
-import com.android.inputmethod.latin.EditingUtils;
-import com.android.inputmethod.latin.LatinIME;
-import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.Settings;
-import com.android.inputmethod.latin.Suggest;
-import com.android.inputmethod.latin.SuggestedWords;
-import com.android.inputmethod.latin.SuggestionsView;
-import com.android.inputmethod.latin.TextEntryState;
-import com.android.inputmethod.latin.WordComposer;
-
-import java.util.ArrayList;
-
-/**
- * Manager of re-correction functionalities
- */
-public class Recorrection implements SharedPreferences.OnSharedPreferenceChangeListener {
-    private static final Recorrection sInstance = new Recorrection();
-
-    private LatinIME mService;
-    private boolean mRecorrectionEnabled = false;
-    private final ArrayList<RecorrectionSuggestionEntries> mRecorrectionSuggestionsList =
-            new ArrayList<RecorrectionSuggestionEntries>();
-
-    public static Recorrection getInstance() {
-        return sInstance;
-    }
-
-    public static void init(LatinIME context, SharedPreferences prefs) {
-        if (context == null || prefs == null) {
-            return;
-        }
-        sInstance.initInternal(context, prefs);
-    }
-
-    private Recorrection() {
-    }
-
-    public boolean isRecorrectionEnabled() {
-        return mRecorrectionEnabled;
-    }
-
-    private void initInternal(LatinIME context, SharedPreferences prefs) {
-        if (SuggestionSpanUtils.SUGGESTION_SPAN_IS_SUPPORTED) {
-            mRecorrectionEnabled = false;
-            return;
-        }
-        updateRecorrectionEnabled(context.getResources(), prefs);
-        mService = context;
-        prefs.registerOnSharedPreferenceChangeListener(this);
-    }
-
-    public void checkRecorrectionOnStart() {
-        if (SuggestionSpanUtils.SUGGESTION_SPAN_IS_SUPPORTED || !mRecorrectionEnabled) return;
-
-        final InputConnection ic = mService.getCurrentInputConnection();
-        if (ic == null) return;
-        // There could be a pending composing span.  Clean it up first.
-        ic.finishComposingText();
-
-        if (mService.isShowingSuggestionsStrip() && mService.isSuggestionsRequested()) {
-            // First get the cursor position. This is required by setOldSuggestions(), so that
-            // it can pass the correct range to setComposingRegion(). At this point, we don't
-            // have valid values for mLastSelectionStart/End because onUpdateSelection() has
-            // not been called yet.
-            ExtractedTextRequest etr = new ExtractedTextRequest();
-            etr.token = 0; // anything is fine here
-            ExtractedText et = ic.getExtractedText(etr, 0);
-            if (et == null) return;
-            mService.setLastSelection(
-                    et.startOffset + et.selectionStart, et.startOffset + et.selectionEnd);
-
-            // Then look for possible corrections in a delayed fashion
-            if (!TextUtils.isEmpty(et.text) && mService.isCursorTouchingWord()) {
-                mService.mHandler.postUpdateOldSuggestions();
-            }
-        }
-    }
-
-    public void updateRecorrectionSelection(KeyboardSwitcher keyboardSwitcher,
-            SuggestionsView suggestionsView, int candidatesStart, int candidatesEnd,
-            int newSelStart, int newSelEnd, int oldSelStart, int lastSelectionStart,
-            int lastSelectionEnd, boolean hasUncommittedTypedChars) {
-        if (SuggestionSpanUtils.SUGGESTION_SPAN_IS_SUPPORTED || !mRecorrectionEnabled) return;
-        if (!mService.isShowingSuggestionsStrip()) return;
-        if (!keyboardSwitcher.isInputViewShown()) return;
-        if (!mService.isSuggestionsRequested()) return;
-        // Don't look for corrections if the keyboard is not visible
-        // Check if we should go in or out of correction mode.
-        if ((candidatesStart == candidatesEnd || newSelStart != oldSelStart || TextEntryState
-                .isRecorrecting())
-                && (newSelStart < newSelEnd - 1 || !hasUncommittedTypedChars)) {
-            if (mService.isCursorTouchingWord() || lastSelectionStart < lastSelectionEnd) {
-                mService.mHandler.cancelUpdateBigramPredictions();
-                mService.mHandler.postUpdateOldSuggestions();
-            } else {
-                abortRecorrection(false);
-                // If showing the "touch again to save" hint, do not replace it. Else,
-                // show the bigrams if we are at the end of the text, punctuation
-                // otherwise.
-                if (suggestionsView != null && !suggestionsView.isShowingAddToDictionaryHint()) {
-                    InputConnection ic = mService.getCurrentInputConnection();
-                    if (null == ic || !TextUtils.isEmpty(ic.getTextAfterCursor(1, 0))) {
-                        if (!mService.isShowingPunctuationList()) {
-                            mService.setPunctuationSuggestions();
-                        }
-                    } else {
-                        mService.mHandler.postUpdateBigramPredictions();
-                    }
-                }
-            }
-        }
-    }
-
-    public void saveRecorrectionSuggestion(WordComposer word, CharSequence result) {
-        if (SuggestionSpanUtils.SUGGESTION_SPAN_IS_SUPPORTED || !mRecorrectionEnabled) return;
-        if (word.size() <= 1) {
-            return;
-        }
-        // Skip if result is null. It happens in some edge case.
-        if (TextUtils.isEmpty(result)) {
-            return;
-        }
-
-        // Make a copy of the CharSequence, since it is/could be a mutable CharSequence
-        final String resultCopy = result.toString();
-        RecorrectionSuggestionEntries entry = new RecorrectionSuggestionEntries(
-                resultCopy, new WordComposer(word));
-        mRecorrectionSuggestionsList.add(entry);
-    }
-
-    public void clearWordsInHistory() {
-        mRecorrectionSuggestionsList.clear();
-    }
-
-    /**
-     * Tries to apply any typed alternatives for the word if we have any cached alternatives,
-     * otherwise tries to find new corrections and completions for the word.
-     * @param touching The word that the cursor is touching, with position information
-     * @return true if an alternative was found, false otherwise.
-     */
-    public boolean applyTypedAlternatives(WordComposer word, Suggest suggest,
-            KeyboardSwitcher keyboardSwitcher, EditingUtils.SelectedWord touching) {
-        if (SuggestionSpanUtils.SUGGESTION_SPAN_IS_SUPPORTED || !mRecorrectionEnabled) return false;
-        // If we didn't find a match, search for result in typed word history
-        WordComposer foundWord = null;
-        RecorrectionSuggestionEntries alternatives = null;
-        // Search old suggestions to suggest re-corrected suggestions.
-        for (RecorrectionSuggestionEntries entry : mRecorrectionSuggestionsList) {
-            if (TextUtils.equals(entry.getChosenWord(), touching.mWord)) {
-                foundWord = entry.mWordComposer;
-                alternatives = entry;
-                break;
-            }
-        }
-        // If we didn't find a match, at least suggest corrections as re-corrected suggestions.
-        if (foundWord == null
-                && (AutoCorrection.isValidWord(suggest.getUnigramDictionaries(),
-                        touching.mWord, true))) {
-            foundWord = new WordComposer();
-            for (int i = 0; i < touching.mWord.length(); i++) {
-                foundWord.add(touching.mWord.charAt(i),
-                        new int[] { touching.mWord.charAt(i) }, WordComposer.NOT_A_COORDINATE,
-                        WordComposer.NOT_A_COORDINATE);
-            }
-        }
-        // Found a match, show suggestions
-        if (foundWord != null || alternatives != null) {
-            if (alternatives == null) {
-                alternatives = new RecorrectionSuggestionEntries(touching.mWord, foundWord);
-            }
-            showRecorrections(suggest, keyboardSwitcher, alternatives);
-            if (foundWord != null) {
-                word.init(foundWord);
-            } else {
-                word.reset();
-            }
-            return true;
-        }
-        return false;
-    }
-
-
-    private void showRecorrections(Suggest suggest, KeyboardSwitcher keyboardSwitcher,
-            RecorrectionSuggestionEntries entries) {
-        SuggestedWords.Builder builder = entries.getAlternatives(suggest, keyboardSwitcher);
-        builder.setTypedWordValid(false).setHasMinimalSuggestion(false);
-        mService.showSuggestions(builder.build(), entries.getOriginalWord());
-    }
-
-    public void fetchAndDisplayRecorrectionSuggestions(VoiceProxy voiceProxy,
-            SuggestionsView suggestionsView, Suggest suggest, KeyboardSwitcher keyboardSwitcher,
-            WordComposer word, boolean hasUncommittedTypedChars, int lastSelectionStart,
-            int lastSelectionEnd, String wordSeparators) {
-        if (!InputConnectionCompatUtils.RECORRECTION_SUPPORTED) return;
-        if (SuggestionSpanUtils.SUGGESTION_SPAN_IS_SUPPORTED || !mRecorrectionEnabled) return;
-        voiceProxy.setShowingVoiceSuggestions(false);
-        if (suggestionsView != null && suggestionsView.isShowingAddToDictionaryHint()) {
-            return;
-        }
-        InputConnection ic = mService.getCurrentInputConnection();
-        if (ic == null) return;
-        if (!hasUncommittedTypedChars) {
-            // Extract the selected or touching text
-            EditingUtils.SelectedWord touching = EditingUtils.getWordAtCursorOrSelection(ic,
-                    lastSelectionStart, lastSelectionEnd, wordSeparators);
-
-            if (touching != null && touching.mWord.length() > 1) {
-                ic.beginBatchEdit();
-
-                if (applyTypedAlternatives(word, suggest, keyboardSwitcher, touching)
-                        || voiceProxy.applyVoiceAlternatives(touching)) {
-                    TextEntryState.selectedForRecorrection();
-                    InputConnectionCompatUtils.underlineWord(ic, touching);
-                } else {
-                    abortRecorrection(true);
-                }
-
-                ic.endBatchEdit();
-            } else {
-                abortRecorrection(true);
-                mService.updateBigramPredictions();
-            }
-        } else {
-            abortRecorrection(true);
-        }
-    }
-
-    public void abortRecorrection(boolean force) {
-        if (SuggestionSpanUtils.SUGGESTION_SPAN_IS_SUPPORTED) return;
-        if (force || TextEntryState.isRecorrecting()) {
-            TextEntryState.onAbortRecorrection();
-            mService.setCandidatesViewShown(mService.isSuggestionsStripVisible());
-            mService.getCurrentInputConnection().finishComposingText();
-            mService.clearSuggestions();
-        }
-    }
-
-    public void updateRecorrectionEnabled(Resources res, SharedPreferences prefs) {
-        // If the option should not be shown, do not read the re-correction preference
-        // but always use the default setting defined in the resources.
-        if (res.getBoolean(R.bool.config_enable_show_recorrection_option)) {
-            mRecorrectionEnabled = prefs.getBoolean(Settings.PREF_RECORRECTION_ENABLED,
-                    res.getBoolean(R.bool.config_default_compat_recorrection_enabled));
-        } else {
-            mRecorrectionEnabled =
-                    res.getBoolean(R.bool.config_default_compat_recorrection_enabled);
-        }
-    }
-
-    @Override
-    public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
-        if (SuggestionSpanUtils.SUGGESTION_SPAN_IS_SUPPORTED) return;
-        if (key.equals(Settings.PREF_RECORRECTION_ENABLED)) {
-            updateRecorrectionEnabled(mService.getResources(), prefs);
-        }
-    }
-}
diff --git a/java/src/com/android/inputmethod/deprecated/recorrection/RecorrectionSuggestionEntries.java b/java/src/com/android/inputmethod/deprecated/recorrection/RecorrectionSuggestionEntries.java
deleted file mode 100644
index 36ffe2d..0000000
--- a/java/src/com/android/inputmethod/deprecated/recorrection/RecorrectionSuggestionEntries.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.inputmethod.deprecated.recorrection;
-
-import com.android.inputmethod.keyboard.KeyboardSwitcher;
-import com.android.inputmethod.latin.Suggest;
-import com.android.inputmethod.latin.SuggestedWords;
-import com.android.inputmethod.latin.WordComposer;
-
-import android.text.TextUtils;
-
-public class RecorrectionSuggestionEntries {
-    public final CharSequence mChosenWord;
-    public final WordComposer mWordComposer;
-
-    public RecorrectionSuggestionEntries(CharSequence chosenWord, WordComposer wordComposer) {
-        mChosenWord = chosenWord;
-        mWordComposer = wordComposer;
-    }
-
-    public CharSequence getChosenWord() {
-        return mChosenWord;
-    }
-
-    public CharSequence getOriginalWord() {
-        return mWordComposer.getTypedWord();
-    }
-
-    public SuggestedWords.Builder getAlternatives(
-            Suggest suggest, KeyboardSwitcher keyboardSwitcher) {
-        return getTypedSuggestions(suggest, keyboardSwitcher, mWordComposer);
-    }
-
-    @Override
-    public int hashCode() {
-        return mChosenWord.hashCode();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        return o instanceof CharSequence && TextUtils.equals(mChosenWord, (CharSequence)o);
-    }
-
-    private static SuggestedWords.Builder getTypedSuggestions(
-            Suggest suggest, KeyboardSwitcher keyboardSwitcher, WordComposer word) {
-        return suggest.getSuggestedWordBuilder(word, null,
-                keyboardSwitcher.getLatinKeyboard().getProximityInfo());
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 882895f..36e97af 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -60,7 +60,6 @@
 import com.android.inputmethod.compat.VibratorCompatWrapper;
 import com.android.inputmethod.deprecated.LanguageSwitcherProxy;
 import com.android.inputmethod.deprecated.VoiceProxy;
-import com.android.inputmethod.deprecated.recorrection.Recorrection;
 import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardActionListener;
@@ -174,7 +173,6 @@
     private KeyboardSwitcher mKeyboardSwitcher;
     private SubtypeSwitcher mSubtypeSwitcher;
     private VoiceProxy mVoiceProxy;
-    private Recorrection mRecorrection;
 
     private UserDictionary mUserDictionary;
     private UserBigramDictionary mUserBigramDictionary;
@@ -235,14 +233,13 @@
 
     public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> {
         private static final int MSG_UPDATE_SUGGESTIONS = 0;
-        private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
-        private static final int MSG_UPDATE_SHIFT_STATE = 2;
-        private static final int MSG_VOICE_RESULTS = 3;
-        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 4;
-        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 5;
-        private static final int MSG_SPACE_TYPED = 6;
-        private static final int MSG_SET_BIGRAM_PREDICTIONS = 7;
-        private static final int MSG_PENDING_IMS_CALLBACK = 8;
+        private static final int MSG_UPDATE_SHIFT_STATE = 1;
+        private static final int MSG_VOICE_RESULTS = 2;
+        private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 3;
+        private static final int MSG_DISMISS_LANGUAGE_ON_SPACEBAR = 4;
+        private static final int MSG_SPACE_TYPED = 5;
+        private static final int MSG_SET_BIGRAM_PREDICTIONS = 6;
+        private static final int MSG_PENDING_IMS_CALLBACK = 7;
 
         public UIHandler(LatinIME outerInstance) {
             super(outerInstance);
@@ -257,13 +254,6 @@
             case MSG_UPDATE_SUGGESTIONS:
                 latinIme.updateSuggestions();
                 break;
-            case MSG_UPDATE_OLD_SUGGESTIONS:
-                latinIme.mRecorrection.fetchAndDisplayRecorrectionSuggestions(
-                        latinIme.mVoiceProxy, latinIme.mSuggestionsView,
-                        latinIme.mSuggest, latinIme.mKeyboardSwitcher, latinIme.mWordComposer,
-                        latinIme.mHasUncommittedTypedChars, latinIme.mLastSelectionStart,
-                        latinIme.mLastSelectionEnd, latinIme.mSettingsValues.mWordSeparators);
-                break;
             case MSG_UPDATE_SHIFT_STATE:
                 switcher.updateShiftState();
                 break;
@@ -308,16 +298,6 @@
             return hasMessages(MSG_UPDATE_SUGGESTIONS);
         }
 
-        public void postUpdateOldSuggestions() {
-            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
-            sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS),
-                    getOuterInstance().mSettingsValues.mDelayUpdateOldSuggestions);
-        }
-
-        public void cancelUpdateOldSuggestions() {
-            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
-        }
-
         public void postUpdateShiftKeyState() {
             removeMessages(MSG_UPDATE_SHIFT_STATE);
             sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE),
@@ -476,7 +456,6 @@
         InputMethodManagerCompatWrapper.init(this);
         SubtypeSwitcher.init(this);
         KeyboardSwitcher.init(this, prefs);
-        Recorrection.init(this, prefs);
         AccessibilityUtils.init(this, prefs);
 
         super.onCreate();
@@ -485,7 +464,6 @@
         mInputMethodId = Utils.getInputMethodId(mImm, getPackageName());
         mSubtypeSwitcher = SubtypeSwitcher.getInstance();
         mKeyboardSwitcher = KeyboardSwitcher.getInstance();
-        mRecorrection = Recorrection.getInstance();
         mVibrator = VibratorCompatWrapper.getInstance(this);
         DEBUG = LatinImeLogger.sDBG;
 
@@ -764,8 +742,6 @@
         inputView.setKeyPreviewPopupEnabled(mSettingsValues.mKeyPreviewPopupOn,
                 mSettingsValues.mKeyPreviewPopupDismissDelay);
         inputView.setProximityCorrectionEnabled(true);
-        // If we just entered a text field, maybe it has some old text that requires correction
-        mRecorrection.checkRecorrectionOnStart();
 
         voiceIme.onStartInputView(inputView.getWindowToken());
 
@@ -854,7 +830,6 @@
         if (inputView != null) inputView.cancelAllMessages();
         // Remove pending messages related to update suggestions
         mHandler.cancelUpdateSuggestions();
-        mHandler.cancelUpdateOldSuggestions();
     }
 
     @Override
@@ -892,29 +867,18 @@
             if (((mComposingStringBuilder.length() > 0 && mHasUncommittedTypedChars)
                     || mVoiceProxy.isVoiceInputHighlighted())
                     && (selectionChanged || candidatesCleared)) {
-                if (candidatesCleared) {
-                    // If the composing span has been cleared, save the typed word in the history
-                    // for recorrection before we reset the suggestions strip.  Then, we'll be able
-                    // to show suggestions for recorrection right away.
-                    mRecorrection.saveRecorrectionSuggestion(mWordComposer,
-                            mComposingStringBuilder);
-                }
                 mComposingStringBuilder.setLength(0);
                 mHasUncommittedTypedChars = false;
-                if (isCursorTouchingWord()) {
-                    mHandler.cancelUpdateBigramPredictions();
-                    mHandler.postUpdateSuggestions();
-                } else {
-                    setPunctuationSuggestions();
-                }
                 TextEntryState.reset();
+                updateSuggestions();
                 final InputConnection ic = getCurrentInputConnection();
                 if (ic != null) {
                     ic.finishComposingText();
                 }
                 mVoiceProxy.setVoiceInputHighlighted(false);
-            } else if (!mHasUncommittedTypedChars && TextEntryState.isAcceptedDefault()) {
+            } else if (!mHasUncommittedTypedChars) {
                 TextEntryState.reset();
+                updateSuggestions();
             }
             mJustAddedMagicSpace = false; // The user moved the cursor.
             mJustReplacedDoubleSpace = false;
@@ -925,11 +889,6 @@
         // Make a note of the cursor position
         mLastSelectionStart = newSelStart;
         mLastSelectionEnd = newSelEnd;
-
-        mRecorrection.updateRecorrectionSelection(mKeyboardSwitcher,
-                mSuggestionsView, candidatesStart, candidatesEnd, newSelStart,
-                newSelEnd, oldSelStart, mLastSelectionStart,
-                mLastSelectionEnd, mHasUncommittedTypedChars);
     }
 
     public void setLastSelection(int start, int end) {
@@ -947,7 +906,7 @@
      */
     @Override
     public void onExtractedTextClicked() {
-        if (mRecorrection.isRecorrectionEnabled() && isSuggestionsRequested()) return;
+        if (isSuggestionsRequested()) return;
 
         super.onExtractedTextClicked();
     }
@@ -963,7 +922,7 @@
      */
     @Override
     public void onExtractedCursorMovement(int dx, int dy) {
-        if (mRecorrection.isRecorrectionEnabled() && isSuggestionsRequested()) return;
+        if (isSuggestionsRequested()) return;
 
         super.onExtractedCursorMovement(dx, dy);
     }
@@ -979,7 +938,6 @@
             mOptionsDialog = null;
         }
         mVoiceProxy.hideVoiceWindow(mConfigurationChanging);
-        mRecorrection.clearWordsInHistory();
         super.hideWindow();
     }
 
@@ -1335,7 +1293,6 @@
         mVoiceProxy.commitVoiceInput();
         final InputConnection ic = getCurrentInputConnection();
         if (ic == null) return;
-        mRecorrection.abortRecorrection(false);
         ic.beginBatchEdit();
         commitTyped(ic);
         maybeRemovePreviousPeriod(ic, text);
@@ -1451,17 +1408,12 @@
             removeTrailingSpace();
         }
 
-        if (mLastSelectionStart == mLastSelectionEnd) {
-            mRecorrection.abortRecorrection(false);
-        }
-
         int code = primaryCode;
         if ((isAlphabet(code) || mSettingsValues.isSymbolExcludedFromWordSeparators(code))
                 && isSuggestionsRequested() && !isCursorTouchingWord()) {
             if (!mHasUncommittedTypedChars) {
                 mHasUncommittedTypedChars = true;
                 mComposingStringBuilder.setLength(0);
-                mRecorrection.saveRecorrectionSuggestion(mWordComposer, mBestWord);
                 mWordComposer.reset();
                 clearSuggestions();
             }
@@ -1527,7 +1479,6 @@
         final InputConnection ic = getCurrentInputConnection();
         if (ic != null) {
             ic.beginBatchEdit();
-            mRecorrection.abortRecorrection(false);
         }
         if (mHasUncommittedTypedChars) {
             // In certain languages where single quote is a separator, it's better
@@ -1573,7 +1524,6 @@
         if (Keyboard.CODE_SPACE == primaryCode) {
             if (!isCursorTouchingWord()) {
                 mHandler.cancelUpdateSuggestions();
-                mHandler.cancelUpdateOldSuggestions();
                 mHandler.postUpdateBigramPredictions();
             }
         } else {
@@ -1660,6 +1610,9 @@
             return;
         }
 
+        mHandler.cancelUpdateSuggestions();
+        mHandler.cancelUpdateBigramPredictions();
+
         if (!mHasUncommittedTypedChars) {
             setPunctuationSuggestions();
             return;
@@ -1892,7 +1845,6 @@
                 ic.commitText(bestWord, 1);
             }
         }
-        mRecorrection.saveRecorrectionSuggestion(mWordComposer, bestWord);
         mHasUncommittedTypedChars = false;
         mCommittedLength = bestWord.length();
     }
diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java
index bd94bab..d9508f4 100644
--- a/java/src/com/android/inputmethod/latin/Settings.java
+++ b/java/src/com/android/inputmethod/latin/Settings.java
@@ -64,7 +64,6 @@
     public static final String PREF_VIBRATE_ON = "vibrate_on";
     public static final String PREF_SOUND_ON = "sound_on";
     public static final String PREF_KEY_PREVIEW_POPUP_ON = "popup_on";
-    public static final String PREF_RECORRECTION_ENABLED = "recorrection_enabled";
     public static final String PREF_AUTO_CAP = "auto_cap";
     public static final String PREF_SHOW_SETTINGS_KEY = "show_settings_key";
     public static final String PREF_VOICE_SETTINGS_KEY = "voice_mode";
@@ -435,12 +434,6 @@
             generalSettings.removePreference(findPreference(PREF_KEY_PREVIEW_POPUP_ON));
         }
 
-        final boolean showRecorrectionOption = res.getBoolean(
-                R.bool.config_enable_show_recorrection_option);
-        if (!showRecorrectionOption) {
-            generalSettings.removePreference(findPreference(PREF_RECORRECTION_ENABLED));
-        }
-
         final boolean showBigramSuggestionsOption = res.getBoolean(
                 R.bool.config_enable_bigram_suggestions_option);
         if (!showBigramSuggestionsOption) {
diff --git a/native/src/correction.cpp b/native/src/correction.cpp
index 5128c2e..9e75ffc 100644
--- a/native/src/correction.cpp
+++ b/native/src/correction.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <assert.h>
+#include <ctype.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -89,8 +90,10 @@
     }
 }
 
-int Correction::getFreqForSplitTwoWords(const int firstFreq, const int secondFreq) {
-    return Correction::RankingAlgorithm::calcFreqForSplitTwoWords(firstFreq, secondFreq, this);
+int Correction::getFreqForSplitTwoWords(const int firstFreq, const int secondFreq,
+        const unsigned short *word) {
+    return Correction::RankingAlgorithm::calcFreqForSplitTwoWords(
+            firstFreq, secondFreq, this, word);
 }
 
 int Correction::getFinalFreq(const int freq, unsigned short **word, int *wordLength) {
@@ -498,6 +501,16 @@
     return quoteCount;
 }
 
+inline static bool isUpperCase(unsigned short c) {
+     if (c < sizeof(BASE_CHARS) / sizeof(BASE_CHARS[0])) {
+         c = BASE_CHARS[c];
+     }
+     if (isupper(c)) {
+         return true;
+     }
+     return false;
+}
+
 /* static */
 inline static int editDistance(
         int* editDistanceTable, const unsigned short* input,
@@ -749,7 +762,8 @@
 
 /* static */
 int Correction::RankingAlgorithm::calcFreqForSplitTwoWords(
-        const int firstFreq, const int secondFreq, const Correction* correction) {
+        const int firstFreq, const int secondFreq, const Correction* correction,
+        const unsigned short *word) {
     const int spaceProximityPos = correction->mSpaceProximityPos;
     const int missingSpacePos = correction->mMissingSpacePos;
     if (DEBUG_DICT) {
@@ -761,11 +775,27 @@
     const bool isSpaceProximity = spaceProximityPos >= 0;
     const int inputLength = correction->mInputLength;
     const int firstWordLength = isSpaceProximity ? spaceProximityPos : missingSpacePos;
-    const int secondWordLength = isSpaceProximity
-            ? (inputLength - spaceProximityPos - 1)
+    const int secondWordLength = isSpaceProximity ? (inputLength - spaceProximityPos - 1)
             : (inputLength - missingSpacePos);
     const int typedLetterMultiplier = correction->TYPED_LETTER_MULTIPLIER;
 
+    bool firstCapitalizedWordDemotion = false;
+    if (firstWordLength >= 2) {
+        firstCapitalizedWordDemotion = isUpperCase(word[0]);
+    }
+
+    bool secondCapitalizedWordDemotion = false;
+    if (secondWordLength >= 2) {
+        secondCapitalizedWordDemotion = isUpperCase(word[firstWordLength + 1]);
+    }
+
+    const bool capitalizedWordDemotion =
+            firstCapitalizedWordDemotion ^ secondCapitalizedWordDemotion;
+
+    if (DEBUG_DICT_FULL) {
+        LOGI("Two words: %c, %c, %d", word[0], word[firstWordLength + 1], capitalizedWordDemotion);
+    }
+
     if (firstWordLength == 0 || secondWordLength == 0) {
         return 0;
     }
@@ -815,6 +845,11 @@
     }
 
     multiplyRate(WORDS_WITH_MISSING_SPACE_CHARACTER_DEMOTION_RATE, &totalFreq);
+
+    if (capitalizedWordDemotion) {
+        multiplyRate(TWO_WORDS_CAPITALIZED_DEMOTION_RATE, &totalFreq);
+    }
+
     return totalFreq;
 }
 
diff --git a/native/src/correction.h b/native/src/correction.h
index 84e0752..a630646 100644
--- a/native/src/correction.h
+++ b/native/src/correction.h
@@ -73,7 +73,8 @@
 
     bool needsToPrune() const;
 
-    int getFreqForSplitTwoWords(const int firstFreq, const int secondFreq);
+    int getFreqForSplitTwoWords(
+            const int firstFreq, const int secondFreq, const unsigned short *word);
     int getFinalFreq(const int freq, unsigned short **word, int* wordLength);
 
     CorrectionType processCharAndCalcState(const int32_t c, const bool isTerminal);
@@ -151,7 +152,7 @@
         static int calculateFinalFreq(const int inputIndex, const int depth,
                 const int freq, int *editDistanceTable, const Correction* correction);
         static int calcFreqForSplitTwoWords(const int firstFreq, const int secondFreq,
-                const Correction* correction);
+                const Correction* correction, const unsigned short *word);
     };
 };
 } // namespace latinime
diff --git a/native/src/defines.h b/native/src/defines.h
index dab8629..57bd9f7 100644
--- a/native/src/defines.h
+++ b/native/src/defines.h
@@ -189,6 +189,7 @@
 #define CORRECTION_COUNT_RATE_DEMOTION_RATE_BASE 45
 #define INPUT_EXCEEDS_OUTPUT_DEMOTION_RATE 70
 #define FIRST_CHAR_DIFFERENT_DEMOTION_RATE 96
+#define TWO_WORDS_CAPITALIZED_DEMOTION_RATE 50
 
 // This should be greater than or equal to MAX_WORD_LENGTH defined in BinaryDictionary.java
 // This is only used for the size of array. Not to be used in c functions.
diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp
index f23bd32..8eb5a97 100644
--- a/native/src/unigram_dictionary.cpp
+++ b/native/src/unigram_dictionary.cpp
@@ -431,7 +431,7 @@
         word[i] = mWord[i - firstWordLength - 1];
     }
 
-    const int pairFreq = mCorrection->getFreqForSplitTwoWords(firstFreq, secondFreq);
+    const int pairFreq = mCorrection->getFreqForSplitTwoWords(firstFreq, secondFreq, word);
     if (DEBUG_DICT) {
         LOGI("Split two words:  %d, %d, %d, %d", firstFreq, secondFreq, pairFreq, inputLength);
     }