diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java
index 99f8a67365358bf9372622852d3485c8e3c4746d..74e6a01b580378ae01740dbecd946f88a4d184b2 100644
--- a/java/src/com/android/inputmethod/latin/CandidateView.java
+++ b/java/src/com/android/inputmethod/latin/CandidateView.java
@@ -24,7 +24,9 @@ import android.os.Message;
 import android.text.Spannable;
 import android.text.SpannableString;
 import android.text.TextUtils;
+import android.text.style.BackgroundColorSpan;
 import android.text.style.CharacterStyle;
+import android.text.style.ForegroundColorSpan;
 import android.text.style.StyleSpan;
 import android.text.style.UnderlineSpan;
 import android.util.AttributeSet;
@@ -57,22 +59,76 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
     private final int mColorOther;
     private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
     private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
+    private final CharacterStyle mInvertedForegroundColorSpan;
+    private final CharacterStyle mInvertedBackgroundColorSpan;
 
     private boolean mShowingCompletions;
+    private boolean mShowingAutoCorrectionInverted;
 
     private boolean mShowingAddToDictionary;
 
-    private static final long DELAY_HIDE_PREVIEW = 1000;
-    private static final int MSG_HIDE_PREVIEW = 0;
-    private final Handler mHandler = new Handler() {
+    private final UiHandler mHandler = new UiHandler();
+
+    private static class UpdateSuggestionsArgs {
+        public final List<CharSequence> mSuggestions;
+        public final boolean mCompletions;
+        public final boolean mTypedWordValid;
+        public final boolean mHaveMinimalSuggestion;
+        public UpdateSuggestionsArgs(List<CharSequence> suggestions, boolean completions,
+                boolean typedWordValid, boolean haveMinimalSuggestion) {
+            mSuggestions = suggestions;
+            mCompletions = completions;
+            mTypedWordValid = typedWordValid;
+            mHaveMinimalSuggestion = haveMinimalSuggestion;
+        }
+    }
+
+    private class UiHandler extends Handler {
+        private static final int MSG_HIDE_PREVIEW = 0;
+        private static final int MSG_UPDATE_SUGGESTION = 1;
+
+        private static final long DELAY_HIDE_PREVIEW = 1000;
+        private static final long DELAY_UPDATE_SUGGESTION = 300;
+
         @Override
         public void dispatchMessage(Message msg) {
             switch (msg.what) {
             case MSG_HIDE_PREVIEW:
                 hidePreview();
                 break;
+            case MSG_UPDATE_SUGGESTION:
+                UpdateSuggestionsArgs args = (UpdateSuggestionsArgs)msg.obj;
+                updateSuggestions(args.mSuggestions, args.mCompletions, args.mTypedWordValid,
+                        args.mHaveMinimalSuggestion);
+                break;
             }
         }
+
+        public void postHidePreview() {
+            cancelHidePreview();
+            sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW);
+        }
+
+        public void cancelHidePreview() {
+            removeMessages(MSG_HIDE_PREVIEW);
+        }
+
+        public void postUpdateSuggestions(List<CharSequence> suggestions, boolean completions,
+                boolean typedWordValid, boolean haveMinimalSuggestion) {
+            cancelUpdateSuggestions();
+            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION, new UpdateSuggestionsArgs(
+                    suggestions, completions, typedWordValid, haveMinimalSuggestion)),
+                    DELAY_UPDATE_SUGGESTION);
+        }
+
+        public void cancelUpdateSuggestions() {
+            removeMessages(MSG_UPDATE_SUGGESTION);
+        }
+
+        public void cancelAllMessages() {
+            cancelHidePreview();
+            cancelUpdateSuggestions();
+        }
     };
 
     /**
@@ -96,6 +152,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
         mColorNormal = res.getColor(R.color.candidate_normal);
         mColorRecommended = res.getColor(R.color.candidate_recommended);
         mColorOther = res.getColor(R.color.candidate_other);
+        mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorNormal ^ 0x00ffffff);
+        mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorNormal);
 
         for (int i = 0; i < MAX_SUGGESTIONS; i++) {
             View v = inflater.inflate(R.layout.candidate, null);
@@ -123,6 +181,16 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
 
     public void setSuggestions(List<CharSequence> suggestions, boolean completions,
             boolean typedWordValid, boolean haveMinimalSuggestion) {
+        if (mShowingAutoCorrectionInverted) {
+            mHandler.postUpdateSuggestions(suggestions, completions, typedWordValid,
+                    haveMinimalSuggestion);
+        } else {
+            updateSuggestions(suggestions, completions, typedWordValid, haveMinimalSuggestion);
+        }
+    }
+
+    private void updateSuggestions(List<CharSequence> suggestions, boolean completions,
+            boolean typedWordValid, boolean haveMinimalSuggestion) {
         clear();
         if (suggestions != null) {
             int insertCount = Math.min(suggestions.size(), MAX_SUGGESTIONS);
@@ -141,8 +209,8 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
             if (suggestion == null) continue;
             final int wordLength = suggestion.length();
 
-            View v = mWords.get(i);
-            TextView tv = (TextView)v.findViewById(R.id.candidate_word);
+            final View v = mWords.get(i);
+            final TextView tv = (TextView)v.findViewById(R.id.candidate_word);
             tv.setTextColor(mColorNormal);
             if (haveMinimalSuggestion
                     && ((i == 1 && !typedWordValid) || (i == 0 && typedWordValid))) {
@@ -179,6 +247,22 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
         requestLayout();
     }
 
+    public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) {
+        // Displaying auto corrected word as inverted is enabled only when highlighting candidate
+        // with color is disabled.
+        if (mConfigCandidateHighlightFontColorEnabled)
+            return;
+        final TextView tv = (TextView)mWords.get(1).findViewById(R.id.candidate_word);
+        final Spannable word = new SpannableString(autoCorrectedWord);
+        final int wordLength = word.length();
+        word.setSpan(mInvertedBackgroundColorSpan, 0, wordLength,
+                Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+        word.setSpan(mInvertedForegroundColorSpan, 0, wordLength,
+                Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
+        tv.setText(word);
+        mShowingAutoCorrectionInverted = true;
+    }
+
     public boolean isShowingAddToDictionaryHint() {
         return mShowingAddToDictionary;
     }
@@ -209,6 +293,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
         // in LatinIME.pickSuggestionManually().
         mSuggestions.clear();
         mShowingAddToDictionary = false;
+        mShowingAutoCorrectionInverted = false;
         removeAllViews();
     }
 
@@ -236,8 +321,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
             previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY);
         }
         previewText.setVisibility(VISIBLE);
-        mHandler.sendMessageDelayed(
-                mHandler.obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW);
+        mHandler.postHidePreview();
     }
 
     private void addToDictionary(CharSequence word) {
@@ -273,7 +357,7 @@ public class CandidateView extends LinearLayout implements OnClickListener, OnLo
     @Override
     public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mHandler.removeMessages(MSG_HIDE_PREVIEW);
+        mHandler.cancelAllMessages();
         hidePreview();
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 16a369a9ed5f45256f50abd1139676d232c3b599..ed5ce6bb80757cc2568150330b35efa0b6917446 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -81,10 +81,8 @@ import java.util.Locale;
 /**
  * Input method implementation for Qwerty'ish keyboard.
  */
-public class LatinIME extends InputMethodService
-        implements KeyboardActionListener,
-        SharedPreferences.OnSharedPreferenceChangeListener,
-        Tutorial.TutorialListener {
+public class LatinIME extends InputMethodService implements KeyboardActionListener,
+        SharedPreferences.OnSharedPreferenceChangeListener, Tutorial.TutorialListener {
     private static final String TAG = "LatinIME";
     private static final boolean PERF_DEBUG = false;
     private static final boolean DEBUG = false;
@@ -1167,9 +1165,7 @@ public class LatinIME extends InputMethodService
         if (ic == null) return;
         abortCorrection(false);
         ic.beginBatchEdit();
-        if (mPredicting) {
-            commitTyped(ic);
-        }
+        commitTyped(ic);
         maybeRemovePreviousPeriod(text);
         ic.commitText(text, 1);
         ic.endBatchEdit();
@@ -1382,7 +1378,14 @@ public class LatinIME extends InputMethodService
             doubleSpace();
         }
         if (pickedDefault) {
-            TextEntryState.backToAcceptedDefault(mWord.getTypedWord());
+            CharSequence typedWord = mWord.getTypedWord();
+            TextEntryState.backToAcceptedDefault(typedWord);
+            if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) {
+                // TODO: Will call InputConnection.commitCorrection() here.
+                if (mCandidateView != null)
+                    mCandidateView.onAutoCorrectionInverted(mBestWord);
+            }
+            setPunctuationSuggestions();
         }
         mKeyboardSwitcher.updateShiftState();
         if (ic != null) {
@@ -1564,7 +1567,7 @@ public class LatinIME extends InputMethodService
         if (mBestWord != null && mBestWord.length() > 0) {
             TextEntryState.acceptedDefault(mWord.getTypedWord(), mBestWord);
             mJustAccepted = true;
-            pickSuggestion(mBestWord, false);
+            pickSuggestion(mBestWord);
             // Add the word to the auto dictionary if it's not a known word
             addToDictionaries(mBestWord, AutoDictionary.FREQUENCY_FOR_TYPED);
             return true;
@@ -1615,7 +1618,7 @@ public class LatinIME extends InputMethodService
             return;
         }
         mJustAccepted = true;
-        pickSuggestion(suggestion, correcting);
+        pickSuggestion(suggestion);
         // Add the word to the auto dictionary if it's not a known word
         if (index == 0) {
             addToDictionaries(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
@@ -1660,10 +1663,8 @@ public class LatinIME extends InputMethodService
      * retrieval.
      * @param suggestion the suggestion picked by the user to be committed to
      *            the text field
-     * @param correcting whether this is due to a correction of an existing
-     *            word.
      */
-    private void pickSuggestion(CharSequence suggestion, boolean correcting) {
+    private void pickSuggestion(CharSequence suggestion) {
         KeyboardSwitcher switcher = mKeyboardSwitcher;
         if (!switcher.isKeyboardAvailable())
             return;
@@ -1676,11 +1677,6 @@ public class LatinIME extends InputMethodService
         mPredicting = false;
         mCommittedLength = suggestion.length();
         switcher.setPreferredLetters(null);
-        // If we just corrected a word, then don't show punctuations
-        if (!correcting) {
-            setPunctuationSuggestions();
-        }
-        switcher.updateShiftState();
     }
 
     /**