diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index cb80d052eb874787839d4dad8dfbb8dcbc03af1b..1398bae2adcd75a97ceb497dcd98d5c06de2c2fb 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -216,37 +216,53 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
         return null;
     }
 
-    // Implements {@link KeyboardState.SwitchActions}.
-    @Override
-    public void setShifted(int shiftMode) {
+    /**
+     * Update keyboard shift state triggered by connected EditText status change.
+     */
+    public void updateShiftState() {
+        mState.onUpdateShiftState(mInputMethodService.getCurrentAutoCapsState());
+    }
+
+    public void onPressKey(int code) {
+        mState.onPressKey(code);
+    }
+
+    public void onReleaseKey(int code, boolean withSliding) {
+        mState.onReleaseKey(code, withSliding);
+    }
+
+    public void onCancelInput() {
+        mState.onCancelInput(isSinglePointer());
+    }
+
+    // TODO: Remove these constants.
+    private static final int ALPHABET_UNSHIFTED = 0;
+    private static final int ALPHABET_MANUAL_SHIFTED = 1;
+    private static final int ALPHABET_AUTOMATIC_SHIFTED = 2;
+    private static final int ALPHABET_SHIFT_LOCKED = 3;
+
+    // TODO: Remove this method.
+    private void updateAlphabetKeyboardShiftState(int shiftMode) {
         mInputMethodService.mHandler.cancelUpdateShiftState();
         Keyboard keyboard = getKeyboard();
         if (keyboard == null)
             return;
         switch (shiftMode) {
-        case AUTOMATIC_SHIFT:
-            keyboard.setAutomaticTemporaryUpperCase();
+        case ALPHABET_UNSHIFTED:
+            keyboard.setShifted(false);
             break;
-        case MANUAL_SHIFT:
+        case ALPHABET_MANUAL_SHIFTED:
             keyboard.setShifted(true);
             break;
-        case UNSHIFT:
-            keyboard.setShifted(false);
+        case ALPHABET_AUTOMATIC_SHIFTED:
+            keyboard.setAutomaticTemporaryUpperCase();
+            break;
+        case ALPHABET_SHIFT_LOCKED:
+            keyboard.setShiftLocked(true);
             break;
         }
         mKeyboardView.invalidateAllKeys();
-    }
-
-    // Implements {@link KeyboardState.SwitchActions}.
-    @Override
-    public void setShiftLocked(boolean shiftLocked) {
-        mInputMethodService.mHandler.cancelUpdateShiftState();
-        Keyboard keyboard = getKeyboard();
-        if (keyboard == null)
-            return;
-        keyboard.setShiftLocked(shiftLocked);
-        mKeyboardView.invalidateAllKeys();
-        if (!shiftLocked) {
+        if (shiftMode != ALPHABET_SHIFT_LOCKED) {
             // To be able to turn off caps lock by "double tap" on shift key, we should ignore
             // the second tap of the "double tap" from now for a while because we just have
             // already turned off caps lock above.
@@ -254,35 +270,38 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
         }
     }
 
-    /**
-     * Update keyboard shift state triggered by connected EditText status change.
-     */
-    public void updateShiftState() {
-        mState.onUpdateShiftState(mInputMethodService.getCurrentAutoCapsState());
-    }
-
-    public void onPressKey(int code) {
-        mState.onPressKey(code);
+    // Implements {@link KeyboardState.SwitchActions}.
+    @Override
+    public void setAlphabetKeyboard() {
+        setKeyboard(mKeyboardSet.getMainKeyboard());
+        updateAlphabetKeyboardShiftState(ALPHABET_UNSHIFTED);
     }
 
-    public void onReleaseKey(int code, boolean withSliding) {
-        mState.onReleaseKey(code, withSliding);
+    // Implements {@link KeyboardState.SwitchActions}.
+    @Override
+    public void setAlphabetManualShiftedKeyboard() {
+        setKeyboard(mKeyboardSet.getMainKeyboard());
+        updateAlphabetKeyboardShiftState(ALPHABET_MANUAL_SHIFTED);
     }
 
-    public void onCancelInput() {
-        mState.onCancelInput(isSinglePointer());
+    // Implements {@link KeyboardState.SwitchActions}.
+    @Override
+    public void setAlphabetAutomaticShiftedKeyboard() {
+        setKeyboard(mKeyboardSet.getMainKeyboard());
+        updateAlphabetKeyboardShiftState(ALPHABET_AUTOMATIC_SHIFTED);
     }
 
     // Implements {@link KeyboardState.SwitchActions}.
     @Override
-    public void setSymbolsKeyboard() {
-        setKeyboard(mKeyboardSet.getSymbolsKeyboard());
+    public void setAlphabetShiftLockedKeyboard() {
+        setKeyboard(mKeyboardSet.getMainKeyboard());
+        updateAlphabetKeyboardShiftState(ALPHABET_SHIFT_LOCKED);
     }
 
     // Implements {@link KeyboardState.SwitchActions}.
     @Override
-    public void setAlphabetKeyboard() {
-        setKeyboard(mKeyboardSet.getMainKeyboard());
+    public void setSymbolsKeyboard() {
+        setKeyboard(mKeyboardSet.getSymbolsKeyboard());
     }
 
     // Implements {@link KeyboardState.SwitchActions}.
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index babf600a6fc6614e93c405bebdfb50050f9964cb..007b10112dcc87ab9cb37641e444a0407bfb79e8 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -40,16 +40,10 @@ public class KeyboardState {
 
     public interface SwitchActions {
         public void setAlphabetKeyboard();
-
-        public static final int UNSHIFT = 0;
-        public static final int MANUAL_SHIFT = 1;
-        public static final int AUTOMATIC_SHIFT = 2;
-        public void setShifted(int shiftMode);
-
-        public void setShiftLocked(boolean shiftLocked);
-
+        public void setAlphabetManualShiftedKeyboard();
+        public void setAlphabetAutomaticShiftedKeyboard();
+        public void setAlphabetShiftLockedKeyboard();
         public void setSymbolsKeyboard();
-
         public void setSymbolsShiftedKeyboard();
 
         /**
@@ -63,6 +57,9 @@ public class KeyboardState {
     private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
     private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
 
+    // TODO: Merge {@link #mSwitchState}, {@link #mIsAlphabetMode}, {@link #mAlphabetShiftState},
+    // {@link #mIsSymbolShifted}, {@link #mPrevMainKeyboardWasShiftLocked}, and
+    // {@link #mPrevSymbolsKeyboardWasShifted} into single state variable.
     private static final int SWITCH_STATE_ALPHA = 0;
     private static final int SWITCH_STATE_SYMBOL_BEGIN = 1;
     private static final int SWITCH_STATE_SYMBOL = 2;
@@ -88,6 +85,7 @@ public class KeyboardState {
         public boolean mIsShiftLocked;
         public boolean mIsShifted;
 
+        @Override
         public String toString() {
             if (!mIsValid) return "INVALID";
             if (mIsAlphabetMode) {
@@ -155,7 +153,7 @@ public class KeyboardState {
         if (state.mIsAlphabetMode) {
             setShiftLocked(state.mIsShiftLocked);
             if (!state.mIsShiftLocked) {
-                setShifted(state.mIsShifted ? SwitchActions.MANUAL_SHIFT : SwitchActions.UNSHIFT);
+                setShifted(state.mIsShifted ? MANUAL_SHIFT : UNSHIFT);
             }
         }
     }
@@ -165,30 +163,58 @@ public class KeyboardState {
         return mAlphabetShiftState.isShiftLocked();
     }
 
+    private static final int UNSHIFT = 0;
+    private static final int MANUAL_SHIFT = 1;
+    private static final int AUTOMATIC_SHIFT = 2;
+
     private void setShifted(int shiftMode) {
         if (DEBUG_ACTION) {
-            Log.d(TAG, "setShifted: shiftMode=" + shiftModeToString(shiftMode));
+            Log.d(TAG, "setShifted: shiftMode=" + shiftModeToString(shiftMode) + " " + this);
+        }
+        if (!mIsAlphabetMode) return;
+        final int prevShiftMode;
+        if (mAlphabetShiftState.isAutomaticTemporaryUpperCase()) {
+            prevShiftMode = AUTOMATIC_SHIFT;
+        } else if (mAlphabetShiftState.isManualTemporaryUpperCase()) {
+            prevShiftMode = MANUAL_SHIFT;
+        } else {
+            prevShiftMode = UNSHIFT;
         }
         switch (shiftMode) {
-        case SwitchActions.AUTOMATIC_SHIFT:
+        case AUTOMATIC_SHIFT:
             mAlphabetShiftState.setAutomaticTemporaryUpperCase();
+            if (shiftMode != prevShiftMode) {
+                mSwitchActions.setAlphabetAutomaticShiftedKeyboard();
+            }
             break;
-        case SwitchActions.MANUAL_SHIFT:
+        case MANUAL_SHIFT:
             mAlphabetShiftState.setShifted(true);
+            if (shiftMode != prevShiftMode) {
+                mSwitchActions.setAlphabetManualShiftedKeyboard();
+            }
             break;
-        case SwitchActions.UNSHIFT:
+        case UNSHIFT:
             mAlphabetShiftState.setShifted(false);
+            if (shiftMode != prevShiftMode) {
+                mSwitchActions.setAlphabetKeyboard();
+            }
             break;
         }
-        mSwitchActions.setShifted(shiftMode);
     }
 
     private void setShiftLocked(boolean shiftLocked) {
         if (DEBUG_ACTION) {
-            Log.d(TAG, "setShiftLocked: shiftLocked=" + shiftLocked);
+            Log.d(TAG, "setShiftLocked: shiftLocked=" + shiftLocked + " " + this);
+        }
+        if (!mIsAlphabetMode) return;
+        if (shiftLocked && (!mAlphabetShiftState.isShiftLocked()
+                || mAlphabetShiftState.isShiftLockShifted())) {
+            mSwitchActions.setAlphabetShiftLockedKeyboard();
+        }
+        if (!shiftLocked && mAlphabetShiftState.isShiftLocked()) {
+            mSwitchActions.setAlphabetKeyboard();
         }
         mAlphabetShiftState.setShiftLocked(shiftLocked);
-        mSwitchActions.setShiftLocked(shiftLocked);
     }
 
     private void toggleAlphabetAndSymbols() {
@@ -308,10 +334,9 @@ public class KeyboardState {
             if (!mAlphabetShiftState.isShiftLocked() && !mShiftKeyState.isIgnoring()) {
                 if (mShiftKeyState.isReleasing() && autoCaps) {
                     // Only when shift key is releasing, automatic temporary upper case will be set.
-                    setShifted(SwitchActions.AUTOMATIC_SHIFT);
+                    setShifted(AUTOMATIC_SHIFT);
                 } else {
-                    setShifted(mShiftKeyState.isMomentary()
-                            ? SwitchActions.MANUAL_SHIFT : SwitchActions.UNSHIFT);
+                    setShifted(mShiftKeyState.isMomentary() ? MANUAL_SHIFT : UNSHIFT);
                 }
             }
         } else {
@@ -326,12 +351,12 @@ public class KeyboardState {
             if (mAlphabetShiftState.isShiftLocked()) {
                 // Shift key is pressed while caps lock state, we will treat this state as shifted
                 // caps lock state and mark as if shift key pressed while normal state.
-                setShifted(SwitchActions.MANUAL_SHIFT);
+                setShifted(MANUAL_SHIFT);
                 mShiftKeyState.onPress();
             } else if (mAlphabetShiftState.isAutomaticTemporaryUpperCase()) {
                 // Shift key is pressed while automatic temporary upper case, we have to move to
                 // manual temporary upper case.
-                setShifted(SwitchActions.MANUAL_SHIFT);
+                setShifted(MANUAL_SHIFT);
                 mShiftKeyState.onPress();
             } else if (mAlphabetShiftState.isShiftedOrShiftLocked()) {
                 // In manual upper case state, we just record shift key has been pressing while
@@ -339,7 +364,7 @@ public class KeyboardState {
                 mShiftKeyState.onPressOnShifted();
             } else {
                 // In base layout, chording or manual temporary upper case mode is started.
-                setShifted(SwitchActions.MANUAL_SHIFT);
+                setShifted(MANUAL_SHIFT);
                 mShiftKeyState.onPress();
             }
         } else {
@@ -358,7 +383,7 @@ public class KeyboardState {
                 if (mAlphabetShiftState.isShiftLockShifted()) {
                     setShiftLocked(true);
                 } else {
-                    setShifted(SwitchActions.UNSHIFT);
+                    setShifted(UNSHIFT);
                 }
             } else if (isShiftLocked && !mAlphabetShiftState.isShiftLockShifted()
                     && (mShiftKeyState.isPressing() || mShiftKeyState.isPressingOnShifted())
@@ -370,12 +395,12 @@ public class KeyboardState {
             } else if (mAlphabetShiftState.isShiftedOrShiftLocked()
                     && mShiftKeyState.isPressingOnShifted() && !withSliding) {
                 // Shift has been pressed without chording while shifted state.
-                setShifted(SwitchActions.UNSHIFT);
+                setShifted(UNSHIFT);
             } else if (mAlphabetShiftState.isManualTemporaryUpperCaseFromAuto()
                     && mShiftKeyState.isPressing() && !withSliding) {
                 // Shift has been pressed without chording while manual temporary upper case
                 // transited from automatic temporary upper case.
-                setShifted(SwitchActions.UNSHIFT);
+                setShifted(UNSHIFT);
             }
         } else {
             // In symbol mode, switch back to the previous keyboard mode if the user chords the
@@ -504,9 +529,9 @@ public class KeyboardState {
 
     private static String shiftModeToString(int shiftMode) {
         switch (shiftMode) {
-        case SwitchActions.UNSHIFT: return "UNSHIFT";
-        case SwitchActions.MANUAL_SHIFT: return "MANUAL";
-        case SwitchActions.AUTOMATIC_SHIFT: return "AUTOMATIC";
+        case UNSHIFT: return "UNSHIFT";
+        case MANUAL_SHIFT: return "MANUAL";
+        case AUTOMATIC_SHIFT: return "AUTOMATIC";
         default: return null;
         }
     }
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
index a675a843ed24bf0c774f93ece0eda8ef898e2224..fce698a1e2f98b14320e9e3d01145dce5b2b514c 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
@@ -78,23 +78,18 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions {
     }
 
     @Override
-    public void setShifted(int shiftMode) {
-        if (shiftMode == SwitchActions.UNSHIFT) {
-            mLayout = Constants.ALPHABET_UNSHIFTED;
-        } else if (shiftMode == SwitchActions.MANUAL_SHIFT) {
-            mLayout = Constants.ALPHABET_MANUAL_SHIFTED;
-        } else if (shiftMode == SwitchActions.AUTOMATIC_SHIFT) {
-            mLayout = Constants.ALPHABET_AUTOMATIC_SHIFTED;
-        }
+    public void setAlphabetManualShiftedKeyboard() {
+        mLayout = Constants.ALPHABET_MANUAL_SHIFTED;
     }
 
     @Override
-    public void setShiftLocked(boolean shiftLocked) {
-        if (shiftLocked) {
-            mLayout = Constants.ALPHABET_SHIFT_LOCKED;
-        } else {
-            mLayout = Constants.ALPHABET_UNSHIFTED;
-        }
+    public void setAlphabetAutomaticShiftedKeyboard() {
+        mLayout = Constants.ALPHABET_AUTOMATIC_SHIFTED;
+    }
+
+    @Override
+    public void setAlphabetShiftLockedKeyboard() {
+        mLayout = Constants.ALPHABET_SHIFT_LOCKED;
     }
 
     @Override