diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 5ba560d7275be7576328766e3e451387af7d5427..d5e5a4e53c173dff131350762a4eedfac1f1241f 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -266,6 +266,16 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
         }
     }
 
+    // Implements {@link KeyboardState.SwitchActions}.
+    @Override
+    public void cancelDoubleTapTimer() {
+        final LatinKeyboardView keyboardView = getKeyboardView();
+        if (keyboardView != null) {
+            final TimerProxy timer = keyboardView.getTimerProxy();
+            timer.cancelDoubleTapTimer();
+        }
+    }
+
     // Implements {@link KeyboardState.SwitchActions}.
     @Override
     public boolean isInDoubleTapTimeout() {
@@ -284,6 +294,16 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
         }
     }
 
+    // Implements {@link KeyboardState.SwitchActions}.
+    @Override
+    public void cancelLongPressTimer() {
+        final LatinKeyboardView keyboardView = getKeyboardView();
+        if (keyboardView != null) {
+            final TimerProxy timer = keyboardView.getTimerProxy();
+            timer.cancelLongPressTimer();
+        }
+    }
+
     // Implements {@link KeyboardState.SwitchActions}.
     @Override
     public void hapticAndAudioFeedback(int code) {
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 88a41579d99636a331fc48720e2061d9fb344363..9a0fe1efa071d2aa540d36238bbc966df641c727 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -232,6 +232,11 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke
                     ViewConfiguration.getDoubleTapTimeout());
         }
 
+        @Override
+        public void cancelDoubleTapTimer() {
+            removeMessages(MSG_DOUBLE_TAP);
+        }
+
         @Override
         public boolean isInDoubleTapTimeout() {
             return hasMessages(MSG_DOUBLE_TAP);
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 110f7f6aed1fb1c311ace728b70b1524e22aab0a..c45308419a0b9ae15c09c76b535dddb4e22e5fd9 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -77,6 +77,7 @@ public class PointerTracker {
         public void startLongPressTimer(int code);
         public void cancelLongPressTimer();
         public void startDoubleTapTimer();
+        public void cancelDoubleTapTimer();
         public boolean isInDoubleTapTimeout();
         public void cancelKeyTimers();
 
@@ -96,6 +97,8 @@ public class PointerTracker {
             @Override
             public void startDoubleTapTimer() {}
             @Override
+            public void cancelDoubleTapTimer() {}
+            @Override
             public boolean isInDoubleTapTimeout() { return false; }
             @Override
             public void cancelKeyTimers() {}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index cb8b4f05ce57b224cb5b9eeb7f34c437f4b36ca3..6a8a036775c86136f0fd7cbcb5eec1a3e01c40b4 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -54,7 +54,9 @@ public class KeyboardState {
 
         public void startDoubleTapTimer();
         public boolean isInDoubleTapTimeout();
+        public void cancelDoubleTapTimer();
         public void startLongPressTimer(int code);
+        public void cancelLongPressTimer();
         public void hapticAndAudioFeedback(int code);
     }
 
@@ -300,6 +302,8 @@ public class KeyboardState {
         } else if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
             onPressSymbol();
         } else {
+            mSwitchActions.cancelDoubleTapTimer();
+            mSwitchActions.cancelLongPressTimer();
             mShiftKeyState.onOtherKeyPressed();
             mSymbolKeyState.onOtherKeyPressed();
         }
@@ -348,7 +352,7 @@ public class KeyboardState {
                 // state. And mark as if shift key is released.
                 mShiftKeyState.onRelease();
             } else {
-                // Shift key is long pressed while shift unloked state.
+                // Shift key is long pressed while shift unlocked state.
                 setShiftLocked(true);
             }
             mSwitchActions.hapticAndAudioFeedback(code);
@@ -364,6 +368,11 @@ public class KeyboardState {
 
     private void updateAlphabetShiftState(boolean autoCaps) {
         if (!mIsAlphabetMode) return;
+        if (!mShiftKeyState.isReleasing()) {
+            // Ignore update shift state event while the shift key is being pressed (including
+            // chording).
+            return;
+        }
         if (!mAlphabetShiftState.isShiftLocked() && !mShiftKeyState.isIgnoring()) {
             if (mShiftKeyState.isReleasing() && autoCaps) {
                 // Only when shift key is releasing, automatic temporary upper case will be set.
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
index d9181f78693cb315636924a48c5ad2e10cea98d0..5db65c660b06ab30d35885d3d5661a1a371e8a14 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java
@@ -16,12 +16,18 @@
 
 package com.android.inputmethod.keyboard.internal;
 
+import android.util.Log;
+
+import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.PointerTracker;
 
 import java.util.Iterator;
 import java.util.LinkedList;
 
 public class PointerTrackerQueue {
+    private static final String TAG = PointerTrackerQueue.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
     private final LinkedList<PointerTracker> mQueue = new LinkedList<PointerTracker>();
 
     public synchronized void add(PointerTracker tracker) {
@@ -32,7 +38,11 @@ public class PointerTrackerQueue {
         mQueue.remove(tracker);
     }
 
-    public synchronized void releaseAllPointersOlderThan(PointerTracker tracker, long eventTime) {
+    public synchronized void releaseAllPointersOlderThan(PointerTracker tracker,
+            long eventTime) {
+        if (DEBUG) {
+            Log.d(TAG, "releaseAllPoniterOlderThan: [" + tracker.mPointerId + "] " + this);
+        }
         if (!mQueue.contains(tracker)) {
             return;
         }
@@ -54,6 +64,13 @@ public class PointerTrackerQueue {
     }
 
     public synchronized void releaseAllPointersExcept(PointerTracker tracker, long eventTime) {
+        if (DEBUG) {
+            if (tracker == null) {
+                Log.d(TAG, "releaseAllPoniters: " + this);
+            } else {
+                Log.d(TAG, "releaseAllPoniterExcept: [" + tracker.mPointerId + "] " + this);
+            }
+        }
         final Iterator<PointerTracker> it = mQueue.iterator();
         while (it.hasNext()) {
             final PointerTracker t = it.next();
@@ -79,8 +96,9 @@ public class PointerTrackerQueue {
         for (final PointerTracker tracker : mQueue) {
             if (sb.length() > 0)
                 sb.append(" ");
-            sb.append(tracker.mPointerId);
+            sb.append("[" + tracker.mPointerId + " "
+                + Keyboard.printableCode(tracker.getKey().mCode) + "]");
         }
-        return "[" + sb + "]";
+        return sb.toString();
     }
 }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 1cb79e7070c694f18aa9e743581094b5a23dfd69..730992b1363049ac4a8ac87e219ae55f2761ade0 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -325,7 +325,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
             return hasMessages(MSG_UPDATE_SUGGESTIONS);
         }
 
-        public void postUpdateShiftKeyState() {
+        public void postUpdateShiftState() {
             removeMessages(MSG_UPDATE_SHIFT_STATE);
             sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), mDelayUpdateShiftState);
         }
@@ -898,9 +898,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
                 resetComposingState(true /* alsoResetLastComposedWord */);
                 updateSuggestions();
             }
+
+            mHandler.postUpdateShiftState();
         }
         mExpectingUpdateSelection = false;
-        mHandler.postUpdateShiftKeyState();
         // TODO: Decide to call restartSuggestionsOnWordBeforeCursorIfAtEndOfWord() or not
         // here. It would probably be too expensive to call directly here but we may want to post a
         // message to delay it. The point would be to unify behavior between backspace to the
@@ -1391,7 +1392,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
         mVoiceProxy.handleBackspace();
 
         // In many cases, we may have to put the keyboard in auto-shift state again.
-        mHandler.postUpdateShiftKeyState();
+        mHandler.postUpdateShiftState();
 
         if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) {
             // Cancel multi-character input: remove the text we just entered.
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java
index e9f37afee7f74230521feb2e50a5917b26d5c344..0e6caaf8772ebf569060989a18f60535a829a4f5 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java
@@ -227,4 +227,17 @@ public class KeyboardStateMultiTouchTests extends KeyboardStateTestsBase {
         // Release "123?" key, switch back to alphabet.
         releaseKey(CODE_SYMBOL, ALPHABET_UNSHIFTED);
     }
+
+    // Chording letter key with shift key.
+    public void testChordingLetterAndShiftKey() {
+        // Press letter key and hold.
+        pressKey('z', ALPHABET_UNSHIFTED);
+        // Press shift key, {@link PointerTracker} will fire a phantom release letter key.
+        chordingReleaseKey('z', ALPHABET_UNSHIFTED);
+        chordingPressKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED);
+        // Press another letter key and hold.
+        chordingPressAndReleaseKey('J', ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Release shift key
+        releaseKey(CODE_SHIFT, ALPHABET_UNSHIFTED);
+    }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
index 8c53fb5c896b8a894712af964b44c664e8f7cec0..ef0facf57ec83b7204619db9d1bbb631602f0657 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
@@ -687,4 +687,67 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
         // Press/release "?123" key, enter symbols (not symbols shifted).
         pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
     }
+
+    // Rapidly type shift key.
+    public void testRapidShiftTyping() {
+        // Press/release shift key
+        pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Rapidly press/release letter key.
+        secondPressAndReleaseKey('J', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+        // Rapidly press/release shift key.
+        secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Rapidly press/release letter key.
+        secondPressAndReleaseKey('J', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+        // Rapidly press/release shift key.
+        secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Rapidly press/release letter key.
+        secondPressAndReleaseKey('J', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+
+        // Press/release shift key to enter alphabet manual shifted.
+        pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Press/release shift key
+        pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+        // Rapidly press/release letter key.
+        secondPressAndReleaseKey('j', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Rapidly press/release shift key.
+        secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Rapidly press/release letter key.
+        secondPressAndReleaseKey('J', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+        // Rapidly press/release shift key.
+        secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Rapidly press/release letter key.
+        secondPressAndReleaseKey('J', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+
+        // Long press shift key to enter alphabet shift locked.
+        longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_SHIFT_LOCKED);
+        // Press/release shift key
+        pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED);
+        // Rapidly press/release letter key.
+        secondPressAndReleaseKey('j', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Rapidly press/release shift key.
+        secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Rapidly press/release letter key.
+        secondPressAndReleaseKey('J', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+        // Rapidly press/release shift key.
+        secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Rapidly press/release letter key.
+        secondPressAndReleaseKey('J', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+
+        // Set auto caps mode on.
+        setAutoCapsMode(AUTO_CAPS);
+        // Press/release auto caps trigger letter to enter alphabet automatic shifted.
+        pressAndReleaseKey(CODE_AUTO_CAPS_TRIGGER, ALPHABET_UNSHIFTED, ALPHABET_AUTOMATIC_SHIFTED);
+        // Press/release shift key
+        pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+        // Rapidly press/release letter key.
+        secondPressAndReleaseKey('j', ALPHABET_UNSHIFTED, ALPHABET_UNSHIFTED);
+        // Rapidly press/release shift key.
+        secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Rapidly press/release letter key.
+        secondPressAndReleaseKey('J', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+        // Rapidly press/release shift key.
+        secondPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+        // Rapidly press/release letter key.
+        secondPressAndReleaseKey('J', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
+    }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
index a01b69cc176f4458c95160b192536b1e64ddacd1..999e08a8dc1b2bb444d81ba53b3b1d8894029076 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
@@ -124,6 +124,11 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions {
         mIsInDoubleTapTimeout = true;
     }
 
+    @Override
+    public void cancelDoubleTapTimer() {
+        mIsInDoubleTapTimeout = false;
+    }
+
     @Override
     public boolean isInDoubleTapTimeout() {
         return mIsInDoubleTapTimeout;
@@ -134,6 +139,11 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions {
         mLongPressTimeoutCode = code;
     }
 
+    @Override
+    public void cancelLongPressTimer() {
+        mLongPressTimeoutCode = 0;
+    }
+
     @Override
     public void hapticAndAudioFeedback(int code) {
         // Nothing to do.