diff --git a/java/src/com/android/inputmethod/latin/EditingUtil.java b/java/src/com/android/inputmethod/latin/EditingUtil.java
index 0c87f8d58fab4aa3e123b2fd28335c2943fe2ab0..be31cb787f2fefd0220a92a0f5744bae5867d9f8 100644
--- a/java/src/com/android/inputmethod/latin/EditingUtil.java
+++ b/java/src/com/android/inputmethod/latin/EditingUtil.java
@@ -16,12 +16,12 @@
 
 package com.android.inputmethod.latin;
 
-import java.util.regex.Pattern;
-
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
 
+import java.util.regex.Pattern;
+
 /**
  * Utility methods to deal with editing text through an InputConnection.
  */
@@ -203,4 +203,27 @@ public class EditingUtil {
             return null;
         }
     }
+
+    /**
+     * Checks if the cursor is touching/inside a word or the selection is for a whole
+     * word and no more and no less.
+     * @param range the Range object that contains the bounds of the word around the cursor
+     * @param start the start of the selection
+     * @param end the end of the selection, which could be the same as the start, if text is not
+     * in selection mode
+     * @return false if the selection is a partial word or straddling multiple words, true if
+     * the selection is a full word or there is no selection.
+     */
+    public static boolean isFullWordOrInside(Range range, int start, int end) {
+        // Is the cursor inside or touching a word?
+        if (start == end) return true;
+
+        // Is it a selection? Then is the start of the selection the start of the word and
+        // the size of the selection the size of the word? Then return true
+        if (start < end
+                && (range.charsBefore == 0 && range.charsAfter == end - start)) {
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index b059b6cfe47caa07a81d35e80556a7ca72296af1..b1bb84d27b50ef311ec4911110797375d256da2f 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -752,10 +752,10 @@ public class LatinIME extends InputMethodService
             mVoiceInputHighlighted = false;
         } else if (!mPredicting && !mJustAccepted) {
             switch (TextEntryState.getState()) {
-                case TextEntryState.STATE_ACCEPTED_DEFAULT:
+                case ACCEPTED_DEFAULT:
                     TextEntryState.reset();
                     // fall through
-                case TextEntryState.STATE_SPACE_AFTER_PICKED:
+                case SPACE_AFTER_PICKED:
                     mJustAddedAutoSpace = false;  // The user moved the cursor.
                     break;
             }
@@ -768,10 +768,10 @@ public class LatinIME extends InputMethodService
         mLastSelectionEnd = newSelEnd;
 
 
-        // TODO: Uncomment this block when we enable re-editing feature
-        // If a word is selected
+        // Check if we should go in or out of correction mode.
         if (isPredictionOn() && mJustRevertedSeparator == null
-                && (candidatesStart == candidatesEnd || newSelStart != oldSelStart)
+                && (candidatesStart == candidatesEnd || newSelStart != oldSelStart
+                        || TextEntryState.isCorrecting())
                 && (newSelStart < newSelEnd - 1 || (!mPredicting))
                 && !mVoiceInputHighlighted) {
             if (isCursorTouchingWord() || mLastSelectionStart < mLastSelectionEnd) {
@@ -1207,7 +1207,7 @@ public class LatinIME extends InputMethodService
         }
         postUpdateShiftKeyState();
         TextEntryState.backspace();
-        if (TextEntryState.getState() == TextEntryState.STATE_UNDO_COMMIT) {
+        if (TextEntryState.getState() == TextEntryState.State.UNDO_COMMIT) {
             revertLastWord(deleteChar);
             ic.endBatchEdit();
             return;
@@ -1358,13 +1358,13 @@ public class LatinIME extends InputMethodService
 
         // Handle the case of ". ." -> " .." with auto-space if necessary
         // before changing the TextEntryState.
-        if (TextEntryState.getState() == TextEntryState.STATE_PUNCTUATION_AFTER_ACCEPTED
+        if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
                 && primaryCode == KEYCODE_PERIOD) {
             reswapPeriodAndSpace();
         }
 
         TextEntryState.typedCharacter((char) primaryCode, true);
-        if (TextEntryState.getState() == TextEntryState.STATE_PUNCTUATION_AFTER_ACCEPTED
+        if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
                 && primaryCode != KEYCODE_ENTER) {
             swapPunctuationAndSpace();
         } else if (isPredictionOn() && primaryCode == KEYCODE_SPACE) {
@@ -1790,8 +1790,16 @@ public class LatinIME extends InputMethodService
             mJustAddedAutoSpace = true;
         }
 
-        // Fool the state watcher so that a subsequent backspace will not do a revert
-        TextEntryState.typedCharacter((char) KEYCODE_SPACE, true);
+        // Fool the state watcher so that a subsequent backspace will not do a revert, unless
+        // we just did a correction, in which case we need to stay in
+        // TextEntryState.State.PICKED_SUGGESTION state.
+        if (!correcting) {
+            TextEntryState.typedCharacter((char) KEYCODE_SPACE, true);
+            setNextSuggestions();
+        } else {
+            // In case the cursor position doesn't change, make sure we show the suggestions again.
+            postUpdateOldSuggestions();
+        }
         if (index == 0 && mCorrectionMode > 0 && !mSuggest.isValidWord(suggestion)
                 && !mSuggest.isValidWord(suggestion.toString().toLowerCase())) {
             mCandidateView.showAddToDictionaryHint(suggestion);
@@ -1820,7 +1828,6 @@ public class LatinIME extends InputMethodService
                 mWordToSuggestions.put(suggestion.toString(), suggestions);
             }
         }
-        // TODO: implement rememberReplacedWord for typed words
     }
 
     /**
@@ -1860,7 +1867,10 @@ public class LatinIME extends InputMethodService
         mPredicting = false;
         mCommittedLength = suggestion.length();
         ((LatinKeyboard) inputView.getKeyboard()).setPreferredLetters(null);
-        setNextSuggestions();
+        // If we just corrected a word, then don't show punctuations
+        if (!correcting) {
+            setNextSuggestions();
+        }
         updateShiftKeyState(getCurrentInputEditorInfo());
     }
 
@@ -1880,13 +1890,16 @@ public class LatinIME extends InputMethodService
             EditingUtil.Range range = new EditingUtil.Range();
             CharSequence touching = EditingUtil.getWordAtCursor(getCurrentInputConnection(),
                     mWordSeparators, range);
-            if (touching != null && touching.length() > 1) {
+            // If it's a selection, check if it's an entire word and no more, no less.
+            boolean fullword = EditingUtil.isFullWordOrInside(range, mLastSelectionStart,
+                    mLastSelectionEnd);
+            if (fullword && touching != null && touching.length() > 1) {
+                // Strip out any trailing word separator
                 if (mWordSeparators.indexOf(touching.charAt(touching.length() - 1)) > 0) {
                     touching = touching.toString().substring(0, touching.length() - 1);
                 }
 
                 // Search for result in spoken word alternatives
-                // TODO: possibly combine the spoken suggestions with the typed suggestions.
                 String selectedWord = touching.toString().trim();
                 if (!mWordToSuggestions.containsKey(selectedWord)){
                     selectedWord = selectedWord.toLowerCase();
@@ -1911,7 +1924,8 @@ public class LatinIME extends InputMethodService
                     ic.endBatchEdit();
                     return;
                 }
-                // If we didn't find a match, search for result in word history
+
+                // If we didn't find a match, search for result in typed word history
                 WordComposer foundWord = null;
                 WordAlternatives alternatives = null;
                 for (WordAlternatives entry : mWordHistory) {
diff --git a/java/src/com/android/inputmethod/latin/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java
index bc7bf3f711a01c033df8686505a399f5ce47beeb..9011191f10cca56a316c0f04ab433c09de3b5faf 100644
--- a/java/src/com/android/inputmethod/latin/TextEntryState.java
+++ b/java/src/com/android/inputmethod/latin/TextEntryState.java
@@ -17,19 +17,22 @@
 package com.android.inputmethod.latin;
 
 import android.content.Context;
+import android.inputmethodservice.Keyboard.Key;
 import android.text.format.DateFormat;
 import android.util.Log;
 
-import android.inputmethodservice.Keyboard.Key;
-
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.util.Calendar;
 
 public class TextEntryState {
     
+    private static final boolean DBG = false;
+
+    private static final String TAG = "TextEntryState";
+
     private static boolean LOGGING = false;
-    
+
     private static int sBackspaceCount = 0;
     
     private static int sAutoSuggestCount = 0;
@@ -46,20 +49,22 @@ public class TextEntryState {
 
     private static int sActualChars;
 
-    public static final int STATE_UNKNOWN = 0;
-    public static final int STATE_START = 1;
-    public static final int STATE_IN_WORD = 2;
-    public static final int STATE_ACCEPTED_DEFAULT = 3;
-    public static final int STATE_PICKED_SUGGESTION = 4;
-    public static final int STATE_PUNCTUATION_AFTER_WORD = 5;
-    public static final int STATE_PUNCTUATION_AFTER_ACCEPTED = 6;
-    public static final int STATE_SPACE_AFTER_ACCEPTED = 7;
-    public static final int STATE_SPACE_AFTER_PICKED = 8;
-    public static final int STATE_UNDO_COMMIT = 9;
-    public static final int STATE_CORRECTING = 10;
-    public static final int STATE_PICKED_CORRECTION = 11;
-
-    private static int sState = STATE_UNKNOWN;
+    public enum State {
+        UNKNOWN,
+        START,
+        IN_WORD,
+        ACCEPTED_DEFAULT,
+        PICKED_SUGGESTION,
+        PUNCTUATION_AFTER_WORD,
+        PUNCTUATION_AFTER_ACCEPTED,
+        SPACE_AFTER_ACCEPTED,
+        SPACE_AFTER_PICKED,
+        UNDO_COMMIT,
+        CORRECTING,
+        PICKED_CORRECTION;
+    }
+
+    private static State sState = State.UNKNOWN;
 
     private static FileOutputStream sKeyLocationFile;
     private static FileOutputStream sUserActionFile;
@@ -73,7 +78,7 @@ public class TextEntryState {
         sWordNotInDictionaryCount = 0;
         sTypedChars = 0;
         sActualChars = 0;
-        sState = STATE_START;
+        sState = State.START;
         
         if (LOGGING) {
             try {
@@ -118,118 +123,133 @@ public class TextEntryState {
         }
         sTypedChars += typedWord.length();
         sActualChars += actualWord.length();
-        sState = STATE_ACCEPTED_DEFAULT;
+        sState = State.ACCEPTED_DEFAULT;
         LatinImeLogger.logOnAutoSuggestion(typedWord.toString(), actualWord.toString());
+        displayState();
     }
 
-    // STATE_ACCEPTED_DEFAULT will be changed to other sub-states
-    // (see "case STATE_ACCEPTED_DEFAULT" in typedCharacter() below),
-    // and should be restored back to STATE_ACCEPTED_DEFAULT after processing for each sub-state.
+    // State.ACCEPTED_DEFAULT will be changed to other sub-states
+    // (see "case ACCEPTED_DEFAULT" in typedCharacter() below),
+    // and should be restored back to State.ACCEPTED_DEFAULT after processing for each sub-state.
     public static void backToAcceptedDefault(CharSequence typedWord) {
         if (typedWord == null) return;
         switch (sState) {
-            case STATE_SPACE_AFTER_ACCEPTED:
-            case STATE_PUNCTUATION_AFTER_ACCEPTED:
-            case STATE_IN_WORD:
-                sState = STATE_ACCEPTED_DEFAULT;
+            case SPACE_AFTER_ACCEPTED:
+            case PUNCTUATION_AFTER_ACCEPTED:
+            case IN_WORD:
+                sState = State.ACCEPTED_DEFAULT;
                 break;
         }
+        displayState();
     }
 
     public static void acceptedTyped(CharSequence typedWord) {
         sWordNotInDictionaryCount++;
-        sState = STATE_PICKED_SUGGESTION;
+        sState = State.PICKED_SUGGESTION;
+        displayState();
     }
 
     public static void acceptedSuggestion(CharSequence typedWord, CharSequence actualWord) {
         sManualSuggestCount++;
-        int oldState = sState;
+        State oldState = sState;
         if (typedWord.equals(actualWord)) {
             acceptedTyped(typedWord);
         }
-        sState = oldState == STATE_CORRECTING ? STATE_PICKED_CORRECTION : STATE_PICKED_SUGGESTION;
+        if (oldState == State.CORRECTING || oldState == State.PICKED_CORRECTION) {
+            sState = State.PICKED_CORRECTION;
+        } else {
+            sState = State.PICKED_SUGGESTION;
+        }
+        displayState();
     }
 
     public static void selectedForCorrection() {
-        sState = STATE_CORRECTING;
+        sState = State.CORRECTING;
+        displayState();
     }
 
     public static void typedCharacter(char c, boolean isSeparator) {
         boolean isSpace = c == ' ';
         switch (sState) {
-            case STATE_IN_WORD:
+            case IN_WORD:
                 if (isSpace || isSeparator) {
-                    sState = STATE_START;
+                    sState = State.START;
                 } else {
                     // State hasn't changed.
                 }
                 break;
-            case STATE_ACCEPTED_DEFAULT:
-            case STATE_SPACE_AFTER_PICKED:
+            case ACCEPTED_DEFAULT:
+            case SPACE_AFTER_PICKED:
                 if (isSpace) {
-                    sState = STATE_SPACE_AFTER_ACCEPTED;
+                    sState = State.SPACE_AFTER_ACCEPTED;
                 } else if (isSeparator) {
-                    sState = STATE_PUNCTUATION_AFTER_ACCEPTED;
+                    sState = State.PUNCTUATION_AFTER_ACCEPTED;
                 } else {
-                    sState = STATE_IN_WORD;
+                    sState = State.IN_WORD;
                 }
                 break;
-            case STATE_PICKED_SUGGESTION:
-            case STATE_PICKED_CORRECTION:
+            case PICKED_SUGGESTION:
+            case PICKED_CORRECTION:
                 if (isSpace) {
-                    sState = STATE_SPACE_AFTER_PICKED;
+                    sState = State.SPACE_AFTER_PICKED;
                 } else if (isSeparator) {
                     // Swap 
-                    sState = STATE_PUNCTUATION_AFTER_ACCEPTED;
+                    sState = State.PUNCTUATION_AFTER_ACCEPTED;
                 } else {
-                    sState = STATE_IN_WORD;
+                    sState = State.IN_WORD;
                 }
                 break;
-            case STATE_START:
-            case STATE_UNKNOWN:
-            case STATE_SPACE_AFTER_ACCEPTED:
-            case STATE_PUNCTUATION_AFTER_ACCEPTED:
-            case STATE_PUNCTUATION_AFTER_WORD:
+            case START:
+            case UNKNOWN:
+            case SPACE_AFTER_ACCEPTED:
+            case PUNCTUATION_AFTER_ACCEPTED:
+            case PUNCTUATION_AFTER_WORD:
                 if (!isSpace && !isSeparator) {
-                    sState = STATE_IN_WORD;
+                    sState = State.IN_WORD;
                 } else {
-                    sState = STATE_START;
+                    sState = State.START;
                 }
                 break;
-            case STATE_UNDO_COMMIT:
+            case UNDO_COMMIT:
                 if (isSpace || isSeparator) {
-                    sState = STATE_ACCEPTED_DEFAULT;
+                    sState = State.ACCEPTED_DEFAULT;
                 } else {
-                    sState = STATE_IN_WORD;
+                    sState = State.IN_WORD;
                 }
                 break;
-            case STATE_CORRECTING:
-                sState = STATE_START;
+            case CORRECTING:
+                sState = State.START;
                 break;
         }
+        displayState();
     }
     
     public static void backspace() {
-        if (sState == STATE_ACCEPTED_DEFAULT) {
-            sState = STATE_UNDO_COMMIT;
+        if (sState == State.ACCEPTED_DEFAULT) {
+            sState = State.UNDO_COMMIT;
             sAutoSuggestUndoneCount++;
             LatinImeLogger.logOnAutoSuggestionCanceled();
-        } else if (sState == STATE_UNDO_COMMIT) {
-            sState = STATE_IN_WORD;
+        } else if (sState == State.UNDO_COMMIT) {
+            sState = State.IN_WORD;
         }
         sBackspaceCount++;
+        displayState();
     }
-    
+
     public static void reset() {
-        sState = STATE_START;
+        sState = State.START;
+        displayState();
     }
-    
-    public static int getState() {
+
+    public static State getState() {
+        if (DBG) {
+            Log.d(TAG, "Returning state = " + sState);
+        }
         return sState;
     }
 
     public static boolean isCorrecting() {
-        return sState == STATE_CORRECTING || sState == STATE_PICKED_CORRECTION;
+        return sState == State.CORRECTING || sState == State.PICKED_CORRECTION;
     }
 
     public static void keyPressedAt(Key key, int x, int y) {
@@ -248,5 +268,11 @@ public class TextEntryState {
             }
         }
     }
+
+    private static void displayState() {
+        if (DBG) {
+            Log.d(TAG, "State = " + sState);
+        }
+    }
 }