diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index f5babd3cd3015b91ef1d3df1a16addb5152e7762..65892784d01ccfb38aa79ade02d914c8b0aed903 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -168,6 +168,7 @@
             <enum name="web" value="4" />
             <enum name="phone" value="5" />
         </attr>
+        <attr name="passwordInput" format="boolean" />
         <attr name="hasSettingsKey" format="string" />
         <attr name="voiceKeyEnabled" format="string" />
         <attr name="hasVoiceKey" format="string" />
diff --git a/java/res/xml-xlarge/kbd_number.xml b/java/res/xml-xlarge/kbd_number.xml
index 875548ba78031872ccaf2e8fa28b5e175c356485..152ec8285f794befce7ca6ad9fe8ae540603cb78 100644
--- a/java/res/xml-xlarge/kbd_number.xml
+++ b/java/res/xml-xlarge/kbd_number.xml
@@ -31,120 +31,189 @@
 >
     <include
         latin:keyboardLayout="@xml/kbd_key_styles" />
-    <!-- This row is intentionally not marked as a top row -->
-    <Row>
-        <Key
-            latin:keyStyle="tabKeyStyle"
-            latin:keyLabelOption="alignLeft"
-            latin:keyEdgeFlags="left" />
-        <Spacer
-            latin:horizontalGap="4.458%p" />
-        <Key
-            latin:keyLabel="-"
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyLabel="+"
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyLabel="."
-            latin:keyWidth="8.042%p" />
-        <Spacer
-            latin:horizontalGap="4.458%p" />
-        <Key
-            latin:keyLabel="1" />
-        <Key
-            latin:keyLabel="2" />
-        <Key
-            latin:keyLabel="3" />
-        <Spacer
-            latin:horizontalGap="9.360%p" />
-        <Key
-            latin:keyStyle="deleteKeyStyle"
-            latin:keyWidth="9.804%p"
-            latin:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Spacer
-            latin:horizontalGap="16.406%p" />
-        <Key
-            latin:keyLabel="*"
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyLabel="/"
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyLabel=","
-            latin:keyWidth="8.042%p" />
-        <Spacer
-            latin:horizontalGap="4.458%p" />
-        <Key
-            latin:keyLabel="4" />
-        <Key
-            latin:keyLabel="5" />
-        <Key
-            latin:keyLabel="6" />
-        <Spacer
-            latin:horizontalGap="4.458%p" />
-        <Key
-            latin:keyStyle="returnKeyStyle"
-            latin:keyWidth="14.706%p"
-            latin:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <!-- There is an empty area bellow the "More" key and left of the "(" key.  To ignore
-             the touch event on the area, "(" is intentionally not marked as a left edge key. -->
-        <Spacer
-            latin:horizontalGap="16.406%p" />
-        <Key
-            latin:keyLabel="("
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyLabel=")"
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyLabel="="
-            latin:keyWidth="8.042%p" />
-        <Spacer
-            latin:horizontalGap="4.458%p" />
-        <Key
-            latin:keyLabel="7" />
-        <Key
-            latin:keyLabel="8" />
-        <Key
-            latin:keyLabel="9" />
-        <!-- There is an empty area bellow the "Enter" key and right of the "9" key.  To ignore
-             the touch event on the area, "9" is intentionally not marked as a right edge key. -->
-    </Row>
-    <!-- This row is intentionally not marked as a bottom row -->
-    <Row>
-        <!-- There is an empty area bellow the "More" key and left of the "space" key.  To ignore
-             the touch event on the area, "space" is intentionally not marked as a left edge key. -->
-        <Spacer
-            latin:horizontalGap="8.362%p" />
-        <Key
-            latin:keyStyle="settingsKeyStyle"
-            latin:keyWidth="8.042%p" />
-        <Key
-            latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
-            latin:keyWidth="24.127%p" />
-        <Spacer
-            latin:horizontalGap="4.458%p" />
-        <Key
-            latin:keyLabel="*" />
-        <Key
-            latin:keyLabel="0" />
-        <Key
-            latin:keyLabel="#" />
-        <switch>
-            <case
-                latin:voiceKeyEnabled="true"
-            >
-                <Key
-                    latin:keyStyle="micKeyStyle"
+    <switch>
+        <case
+            latin:passwordInput="true"
+        >
+            <!-- This row is intentionally not marked as a top row -->
+            <Row>
+                <Spacer
+                    latin:horizontalGap="32.076%p" />
+                <Key
+                    latin:keyLabel="1" />
+                <Key
+                    latin:keyLabel="2" />
+                <Key
+                    latin:keyLabel="3" />
+                <Spacer
+                    latin:horizontalGap="22.272%p" />
+                <Key
+                    latin:keyStyle="deleteKeyStyle"
+                    latin:keyWidth="9.804%p"
+                    latin:keyEdgeFlags="right" />
+            </Row>
+            <Row>
+                <Spacer
+                    latin:horizontalGap="32.076%p" />
+                <Key
+                    latin:keyLabel="4" />
+                <Key
+                    latin:keyLabel="5" />
+                <Key
+                    latin:keyLabel="6" />
+                <Spacer
+                    latin:horizontalGap="17.371%p" />
+                <Key
+                    latin:keyStyle="returnKeyStyle"
+                    latin:keyWidth="14.706%p"
+                    latin:keyEdgeFlags="right" />
+            </Row>
+            <Row>
+                <Spacer
+                    latin:horizontalGap="32.076%p" />
+                <Key
+                    latin:keyLabel="7" />
+                <Key
+                    latin:keyLabel="8" />
+                <Key
+                    latin:keyLabel="9" />
+                <!-- There is an empty area below the "Enter" key and right of the "9" key. To
+                     ignore the touch event on the area, "9" is intentionally not marked as a right
+                     edge key. -->
+            </Row>
+            <!-- This row is intentionally not marked as a bottom row -->
+            <Row>
+                <Spacer
+                    latin:horizontalGap="44.026%p" />
+                <Key
+                    latin:keyLabel="0" />
+                <!-- There is an empty area below the "Enter" key and right of the "#" key. To
+                     ignore the touch event on the area, "#" is intentionally not marked as a right
+                     edge key. -->
+            </Row>
+        </case>
+        <!-- latin:passwordInput="false" -->
+        <default>
+            <!-- This row is intentionally not marked as a top row -->
+            <Row>
+                <Key
+                    latin:keyStyle="tabKeyStyle"
+                    latin:keyLabelOption="alignLeft"
+                    latin:keyEdgeFlags="left" />
+                <Spacer
+                    latin:horizontalGap="4.458%p" />
+                <Key
+                    latin:keyLabel="-"
+                    latin:keyWidth="8.042%p" />
+                <Key
+                    latin:keyLabel="+"
+                    latin:keyWidth="8.042%p" />
+                <Key
+                    latin:keyLabel="."
+                    latin:keyWidth="8.042%p" />
+                <Spacer
+                    latin:horizontalGap="4.458%p" />
+                <Key
+                    latin:keyLabel="1" />
+                <Key
+                    latin:keyLabel="2" />
+                <Key
+                    latin:keyLabel="3" />
+                <Spacer
+                    latin:horizontalGap="9.360%p" />
+                <Key
+                    latin:keyStyle="deleteKeyStyle"
+                    latin:keyWidth="9.804%p"
+                    latin:keyEdgeFlags="right" />
+            </Row>
+            <Row>
+                <Spacer
+                    latin:horizontalGap="16.406%p" />
+                <Key
+                    latin:keyLabel="*"
                     latin:keyWidth="8.042%p" />
-            </case>
-        </switch>
-        <!-- There is an empty area bellow the "Enter" key and right of the "#" key.  To ignore
-             the touch event on the area, "#" is intentionally not marked as a right edge key. -->
-    </Row>
+                <Key
+                    latin:keyLabel="/"
+                    latin:keyWidth="8.042%p" />
+                <Key
+                    latin:keyLabel=","
+                    latin:keyWidth="8.042%p" />
+                <Spacer
+                    latin:horizontalGap="4.458%p" />
+                <Key
+                    latin:keyLabel="4" />
+                <Key
+                    latin:keyLabel="5" />
+                <Key
+                    latin:keyLabel="6" />
+                <Spacer
+                    latin:horizontalGap="4.458%p" />
+                <Key
+                    latin:keyStyle="returnKeyStyle"
+                    latin:keyWidth="14.706%p"
+                    latin:keyEdgeFlags="right" />
+            </Row>
+            <Row>
+                <!-- There is an empty area below the "More" key and left of the "(" key. To
+                     ignore the touch event on the area, "(" is intentionally not marked as a left
+                     edge key. -->
+                <Spacer
+                    latin:horizontalGap="16.406%p" />
+                <Key
+                    latin:keyLabel="("
+                    latin:keyWidth="8.042%p" />
+                <Key
+                    latin:keyLabel=")"
+                    latin:keyWidth="8.042%p" />
+                <Key
+                    latin:keyLabel="="
+                    latin:keyWidth="8.042%p" />
+                <Spacer
+                    latin:horizontalGap="4.458%p" />
+                <Key
+                    latin:keyLabel="7" />
+                <Key
+                    latin:keyLabel="8" />
+                <Key
+                    latin:keyLabel="9" />
+                <!-- There is an empty area below the "Enter" key and right of the "9" key. To
+                     ignore the touch event on the area, "9" is intentionally not marked as a right
+                     edge key. -->
+            </Row>
+            <!-- This row is intentionally not marked as a bottom row -->
+            <Row>
+                <!-- There is an empty area below the "More" key and left of the "space" key. To
+                     ignore the touch event on the area, "space" is intentionally not marked as a
+                     left edge key. -->
+                <Spacer
+                    latin:horizontalGap="8.362%p" />
+                <Key
+                    latin:keyStyle="settingsKeyStyle"
+                    latin:keyWidth="8.042%p" />
+                <Key
+                    latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
+                    latin:keyWidth="24.127%p" />
+                <Spacer
+                    latin:horizontalGap="4.458%p" />
+                <Key
+                    latin:keyLabel="*" />
+                <Key
+                    latin:keyLabel="0" />
+                <Key
+                    latin:keyLabel="#" />
+                <switch>
+                    <case
+                        latin:voiceKeyEnabled="true"
+                    >
+                        <Key
+                            latin:keyStyle="micKeyStyle"
+                            latin:keyWidth="8.042%p" />
+                    </case>
+                </switch>
+                <!-- There is an empty area below the "Enter" key and right of the "#" key. To
+                     ignore the touch event on the area, "#" is intentionally not marked as a right
+                     edge key. -->
+            </Row>
+        </default>
+    </switch>
 </Keyboard>
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 42dc0b0cd20313c2088adc362e13d5e8f982698d..d09f6786e09471620359c26450bd7e6cd0d1e007 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -17,6 +17,7 @@
 package com.android.inputmethod.keyboard;
 
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.Utils;
 
 import android.view.inputmethod.EditorInfo;
 
@@ -41,6 +42,7 @@ public class KeyboardId {
     public final int mMode;
     public final int mXmlId;
     public final int mColorScheme;
+    public final boolean mPasswordInput;
     public final boolean mHasSettingsKey;
     public final boolean mVoiceKeyEnabled;
     public final boolean mHasVoiceKey;
@@ -50,21 +52,25 @@ public class KeyboardId {
 
     private final int mHashCode;
 
-    public KeyboardId(String xmlName, int xmlId, Locale locale, int orientation, int mode,
-            int colorScheme, boolean hasSettingsKey, boolean voiceKeyEnabled, boolean hasVoiceKey,
-            int imeOptions, boolean enableShiftLock) {
+    public KeyboardId(String xmlName, int xmlId, int colorScheme, Locale locale, int orientation,
+            int mode, EditorInfo attribute, boolean hasSettingsKey, boolean voiceKeyEnabled,
+            boolean hasVoiceKey, boolean enableShiftLock) {
+        final int inputType = (attribute != null) ? attribute.inputType : 0;
+        final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
         this.mLocale = locale;
         this.mOrientation = orientation;
         this.mMode = mode;
         this.mXmlId = xmlId;
         this.mColorScheme = colorScheme;
+        this.mPasswordInput = Utils.isPasswordInputType(inputType)
+                || Utils.isVisiblePasswordInputType(inputType);
         this.mHasSettingsKey = hasSettingsKey;
         this.mVoiceKeyEnabled = voiceKeyEnabled;
         this.mHasVoiceKey = hasVoiceKey;
         // We are interested only in {@link EditorInfo#IME_MASK_ACTION} enum value and
         // {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION}.
-        this.mImeAction = imeOptions
-                & (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
+        this.mImeAction = imeOptions & (
+                EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
         this.mEnableShiftLock = enableShiftLock;
         this.mXmlName = xmlName;
 
@@ -74,6 +80,7 @@ public class KeyboardId {
                 mode,
                 xmlId,
                 colorScheme,
+                mPasswordInput,
                 hasSettingsKey,
                 voiceKeyEnabled,
                 hasVoiceKey,
@@ -113,6 +120,7 @@ public class KeyboardId {
             && other.mMode == this.mMode
             && other.mXmlId == this.mXmlId
             && other.mColorScheme == this.mColorScheme
+            && other.mPasswordInput == this.mPasswordInput
             && other.mHasSettingsKey == this.mHasSettingsKey
             && other.mVoiceKeyEnabled == this.mVoiceKeyEnabled
             && other.mHasVoiceKey == this.mHasVoiceKey
@@ -127,17 +135,19 @@ public class KeyboardId {
 
     @Override
     public String toString() {
-        return String.format("[%s.xml %s %s %s imeOptions=%s %s%s%s%s%s]",
+        return String.format("[%s.xml %s %s %s imeAction=%s %s%s%s%s%s%s]",
                 mXmlName,
                 mLocale,
                 (mOrientation == 1 ? "port" : "land"),
                 modeName(mMode),
                 imeOptionsName(mImeAction),
-                colorSchemeName(mColorScheme),
+                (mPasswordInput ? " passwordInput" : ""),
                 (mHasSettingsKey ? " hasSettingsKey" : ""),
                 (mVoiceKeyEnabled ? " voiceKeyEnabled" : ""),
                 (mHasVoiceKey ? " hasVoiceKey" : ""),
-                (mEnableShiftLock ? " enableShiftLock" : ""));
+                (mEnableShiftLock ? " enableShiftLock" : ""),
+                colorSchemeName(mColorScheme)
+        );
     }
 
     public static String modeName(int mode) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
index 70f16c21b1c7970de1dddfc4526a910adc94ad7b..89208dd5d2935a03112b56d7a0d5ffb71feab12f 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
@@ -419,6 +419,8 @@ public class KeyboardParser {
         try {
             final boolean modeMatched = matchInteger(a,
                     R.styleable.Keyboard_Case_mode, id.mMode);
+            final boolean passwordInputMatched = matchBoolean(a,
+                    R.styleable.Keyboard_Case_passwordInput, id.mPasswordInput);
             final boolean settingsKeyMatched = matchBoolean(a,
                     R.styleable.Keyboard_Case_hasSettingsKey, id.mHasSettingsKey);
             final boolean voiceEnabledMatched = matchBoolean(a,
@@ -435,15 +437,16 @@ public class KeyboardParser {
                     R.styleable.Keyboard_Case_imeAction, id.mImeAction);
             final boolean languageCodeMatched = matchString(a,
                     R.styleable.Keyboard_Case_languageCode, id.mLocale.getLanguage());
-            final boolean selected = modeMatched && settingsKeyMatched && voiceEnabledMatched
-                    && voiceKeyMatched && colorSchemeMatched && imeActionMatched
-                    && languageCodeMatched;
+            final boolean selected = modeMatched && passwordInputMatched && settingsKeyMatched
+                    && voiceEnabledMatched && voiceKeyMatched && colorSchemeMatched
+                    && imeActionMatched && languageCodeMatched;
 
-            if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s> %s", TAG_CASE,
+            if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s> %s", TAG_CASE,
                     textAttr(KeyboardId.modeName(
                             a.getInt(R.styleable.Keyboard_Case_mode, -1)), "mode"),
                     textAttr(KeyboardId.colorSchemeName(
                             a.getInt(R.styleable.KeyboardView_colorScheme, -1)), "colorSchemeName"),
+                    booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, "passwordInput"),
                     booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, "hasSettingsKey"),
                     booleanAttr(a, R.styleable.Keyboard_Case_voiceKeyEnabled, "voiceKeyEnabled"),
                     booleanAttr(a, R.styleable.Keyboard_Case_hasVoiceKey, "hasVoiceKey"),
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 9b98f287875a02b0f299f73bae2a7d26a55fc68f..93d3811c4f9a61ded8a9f553137cafa52a477f3e 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -28,6 +28,7 @@ import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.util.Log;
 import android.view.InflateException;
+import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
 
 import java.lang.ref.SoftReference;
@@ -66,8 +67,9 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
     private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
             new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
 
+    // TODO: clean mMode up and use mAttribute instead.
     private int mMode = KeyboardId.MODE_TEXT; /* default value */
-    private int mImeOptions;
+    private EditorInfo mAttribute;
     private boolean mIsSymbols;
     /** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of
      * what user actually typed. */
@@ -128,10 +130,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         final int orientation = res.getConfiguration().orientation;
         final int mode = mMode;
         final int colorScheme = getColorScheme();
-        final boolean hasSettingsKey = mHasSettingsKey;
-        final boolean voiceKeyEnabled = mVoiceKeyEnabled;
-        final boolean hasVoiceKey = voiceKeyEnabled && !mVoiceButtonOnPrimary;
-        final int imeOptions = mImeOptions;
+        final boolean hasVoiceKey = mVoiceKeyEnabled && !mVoiceButtonOnPrimary;
         // Note: This comment is only applied for phone number keyboard layout.
         // On non-xlarge device, "@integer/key_switch_alpha_symbol" key code is used to switch
         // between "phone keyboard" and "phone symbols keyboard".  But on xlarge device,
@@ -140,26 +139,25 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         // mSymbolsId and mSymbolsShiftedId to "phone keyboard" and "phone symbols keyboard"
         // respectively here for xlarge device's layout switching.
         int xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone : R.xml.kbd_symbols;
-        mSymbolsId = new KeyboardId(
-                res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, colorScheme,
-                hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
+        final String xmlName = res.getResourceEntryName(xmlId);
+        mSymbolsId = new KeyboardId(xmlName, xmlId, colorScheme, locale, orientation, mode,
+                mAttribute, mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, true);
         xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift;
-        mSymbolsShiftedId = new KeyboardId(
-                res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, colorScheme,
-                hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
+        mSymbolsShiftedId = new KeyboardId(xmlName, xmlId, colorScheme, locale, orientation, mode,
+                mAttribute, mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, true);
     }
 
     private boolean hasVoiceKey(boolean isSymbols) {
         return mVoiceKeyEnabled && (isSymbols != mVoiceButtonOnPrimary);
     }
 
-    public void loadKeyboard(int mode, int imeOptions, boolean voiceKeyEnabled,
+    public void loadKeyboard(int mode, EditorInfo attribute, boolean voiceKeyEnabled,
             boolean voiceButtonOnPrimary) {
         mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA;
         try {
             if (mInputView == null) return;
             final Keyboard oldKeyboard = mInputView.getKeyboard();
-            loadKeyboardInternal(mode, imeOptions, voiceKeyEnabled, voiceButtonOnPrimary, false);
+            loadKeyboardInternal(mode, attribute, voiceKeyEnabled, voiceButtonOnPrimary, false);
             final Keyboard newKeyboard = mInputView.getKeyboard();
             if (newKeyboard.isAlphaKeyboard()) {
                 final boolean localeChanged = (oldKeyboard == null)
@@ -167,23 +165,25 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
                 mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
             }
         } catch (RuntimeException e) {
-            Log.w(TAG, e);
-            LatinImeLogger.logOnException(mode + "," + imeOptions, e);
+            // Get KeyboardId to record which keyboard has been failed to load.
+            final KeyboardId id = getKeyboardId(mode, attribute, false);
+            Log.w(TAG, "loading keyboard failed: " + id, e);
+            LatinImeLogger.logOnException(id.toString(), e);
         }
     }
 
-    private void loadKeyboardInternal(int mode, int imeOptions, boolean voiceButtonEnabled,
+    private void loadKeyboardInternal(int mode, EditorInfo attribute, boolean voiceButtonEnabled,
             boolean voiceButtonOnPrimary, boolean isSymbols) {
         if (mInputView == null) return;
 
         mMode = mode;
-        mImeOptions = imeOptions;
+        mAttribute = attribute;
         mVoiceKeyEnabled = voiceButtonEnabled;
         mVoiceButtonOnPrimary = voiceButtonOnPrimary;
         mIsSymbols = isSymbols;
         // Update the settings key state because number of enabled IMEs could have been changed
         mHasSettingsKey = getSettingsKeyMode(mPrefs, mInputMethodService);
-        final KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
+        final KeyboardId id = getKeyboardId(mode, attribute, isSymbols);
 
         final Keyboard oldKeyboard = mInputView.getKeyboard();
         if (oldKeyboard != null && oldKeyboard.mId.equals(id))
@@ -228,7 +228,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         return keyboard;
     }
 
-    private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) {
+    private KeyboardId getKeyboardId(int mode, EditorInfo attribute, boolean isSymbols) {
         final boolean hasVoiceKey = hasVoiceKey(isSymbols);
         final int charColorId = getColorScheme();
         final int xmlId;
@@ -260,8 +260,8 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         final int orientation = res.getConfiguration().orientation;
         final Locale locale = mSubtypeSwitcher.getInputLocale();
         return new KeyboardId(
-                res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, charColorId,
-                mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, imeOptions, enableShiftLock);
+                res.getResourceEntryName(xmlId), xmlId, charColorId, locale, orientation, mode,
+                attribute, mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, enableShiftLock);
     }
 
     public int getKeyboardMode() {
@@ -566,7 +566,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
     }
 
     private void toggleKeyboardMode() {
-        loadKeyboardInternal(mMode, mImeOptions, mVoiceKeyEnabled, mVoiceButtonOnPrimary,
+        loadKeyboardInternal(mMode, mAttribute, mVoiceKeyEnabled, mVoiceButtonOnPrimary,
                 !mIsSymbols);
         if (mIsSymbols) {
             mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN;
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
index b6eab1f3b1a5093f6181c486612b1fd70ce72fdb..5820049bb8d0c895fb6d8768e646759a615230ac 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
@@ -155,6 +155,8 @@ public class LatinKeyboard extends Keyboard {
     }
 
     private void updateSpacebarForLocale(boolean isAutoCorrection) {
+        if (mSpaceKey == null)
+            return;
         final Resources res = mContext.getResources();
         // If application locales are explicitly selected.
         if (SubtypeSwitcher.getInstance().needsToDisplayLanguage()) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 0bb39fdd9c170269548b22435187d718b43aff39..2a340ad0fa58a310c333721aef2d627d0b7ce78c 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -494,26 +494,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         return container;
     }
 
-    // Please refer to TextView.isPasswordInputType
-    private static boolean isPasswordInputType(int inputType) {
-        final int variation =
-                inputType & (InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION);
-        return (variation
-                == (InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD))
-                || (variation
-                == (InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD))
-                || (variation
-                == (InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD));
-    }
-
-    // Please refer to TextView.isVisiblePasswordInputType
-    private static boolean isVisiblePasswordInputType(int inputType) {
-        final int variation =
-                inputType & (InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION);
-        return variation
-                == (InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
-    }
-
     private static boolean isEmailVariation(int variation) {
         return variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
                 || variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
@@ -539,10 +519,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         // Most such things we decide below in initializeInputAttributesAndGetMode, but we need to
         // know now whether this is a password text field, because we need to know now whether we
         // want to enable the voice button.
-        mVoiceConnector.resetVoiceStates(isPasswordInputType(attribute.inputType)
-                || isVisiblePasswordInputType(attribute.inputType));
+        mVoiceConnector.resetVoiceStates(Utils.isPasswordInputType(attribute.inputType)
+                || Utils.isVisiblePasswordInputType(attribute.inputType));
 
-        final int mode = initializeInputAttributesAndGetMode(attribute.inputType);
+        final int mode = initializeInputAttributesAndGetMode(attribute);
 
         inputView.closing();
         mEnteredText = null;
@@ -553,7 +533,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
 
         loadSettings(attribute);
         if (mSubtypeSwitcher.isKeyboardMode()) {
-            switcher.loadKeyboard(mode, attribute.imeOptions,
+            switcher.loadKeyboard(mode, attribute,
                     mVoiceConnector.isVoiceButtonEnabled(),
                     mVoiceConnector.isVoiceButtonOnPrimary());
             switcher.updateShiftState();
@@ -577,7 +557,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
     }
 
-    private int initializeInputAttributesAndGetMode(int inputType) {
+    // TODO: Separate calculating keyboard mode from initializing attributes, and make it an
+    // utility method in {@link Utils}.
+    private int initializeInputAttributesAndGetMode(EditorInfo attribute) {
+        if (attribute == null) return KeyboardId.MODE_TEXT;
+        final int inputType = attribute.inputType;
         final int variation = inputType & InputType.TYPE_MASK_VARIATION;
         mAutoSpace = false;
         mInputTypeNoAutoCorrect = false;
@@ -597,16 +581,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             case InputType.TYPE_CLASS_TEXT:
                 mIsSettingsSuggestionStripOn = true;
                 // Make sure that passwords are not displayed in candidate view
-                if (isPasswordInputType(inputType) || isVisiblePasswordInputType(inputType)) {
+                if (Utils.isPasswordInputType(inputType)
+                        || Utils.isVisiblePasswordInputType(inputType)) {
                     mIsSettingsSuggestionStripOn = false;
                 }
-                if (isEmailVariation(variation)
+                if (LatinIME.isEmailVariation(variation)
                         || variation == InputType.TYPE_TEXT_VARIATION_PERSON_NAME) {
                     mAutoSpace = false;
                 } else {
                     mAutoSpace = true;
                 }
-                if (isEmailVariation(variation)) {
+                if (LatinIME.isEmailVariation(variation)) {
                     mIsSettingsSuggestionStripOn = false;
                     mode = KeyboardId.MODE_EMAIL;
                 } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
@@ -1924,15 +1909,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             mSubtypeSwitcher.toggleLanguage(reset, next);
         }
         // Reload keyboard because the current language has been changed.
-        KeyboardSwitcher switcher = mKeyboardSwitcher;
         final EditorInfo attribute = getCurrentInputEditorInfo();
-        final int mode = initializeInputAttributesAndGetMode((attribute != null)
-                ? attribute.inputType : 0);
-        final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
-        switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(),
-                mVoiceConnector.isVoiceButtonOnPrimary());
+        final int mode = initializeInputAttributesAndGetMode(attribute);
+        mKeyboardSwitcher.loadKeyboard(mode, attribute,
+                mVoiceConnector.isVoiceButtonEnabled(), mVoiceConnector.isVoiceButtonOnPrimary());
         initSuggest();
-        switcher.updateShiftState();
+        mKeyboardSwitcher.updateShiftState();
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index aafafbf2f1d0bc02de39d47998aac41a6f4d3592..7091d9b568fabaca212b0591c9a46904fc7333d5 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -16,13 +16,17 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.keyboard.KeyboardId;
+
 import android.inputmethodservice.InputMethodService;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
+import android.text.InputType;
 import android.text.format.DateUtils;
 import android.util.Log;
+import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
 
@@ -55,7 +59,7 @@ public class Utils {
     }
 
     public static class GCUtils {
-        private static final String TAG = "GCUtils";
+        private static final String GC_TAG = GCUtils.class.getSimpleName();
         public static final int GC_TRY_COUNT = 2;
         // GC_TRY_LOOP_MAX is used for the hard limit of GC wait,
         // GC_TRY_LOOP_MAX should be greater than GC_TRY_COUNT.
@@ -84,7 +88,7 @@ public class Utils {
                     Thread.sleep(GC_INTERVAL);
                     return true;
                 } catch (InterruptedException e) {
-                    Log.e(TAG, "Sleep was interrupted.");
+                    Log.e(GC_TAG, "Sleep was interrupted.");
                     LatinImeLogger.logOnException(metaData, t);
                     return false;
                 }
@@ -452,4 +456,24 @@ public class Utils {
             return new PrintWriter(new FileOutputStream(mFile), true /* autoFlush */);
         }
     }
+
+    // Please refer to TextView.isPasswordInputType
+    public static boolean isPasswordInputType(int inputType) {
+        final int variation =
+                inputType & (InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION);
+        return (variation
+                == (InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD))
+                || (variation
+                == (InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD))
+                || (variation
+                == (InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_VARIATION_PASSWORD));
+    }
+
+    // Please refer to TextView.isVisiblePasswordInputType
+    public static boolean isVisiblePasswordInputType(int inputType) {
+        final int variation =
+                inputType & (InputType.TYPE_MASK_CLASS | InputType.TYPE_MASK_VARIATION);
+        return variation
+                == (InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
+    }
 }
diff --git a/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java b/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
index 365cea865fa0a887caa479a7de57c0dff5296b59..4500c2aee9c09c11ecc438e6c6a0ca4867d81c96 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
@@ -23,6 +23,7 @@ import android.content.res.AssetFileDescriptor;
 import android.content.res.Configuration;
 import android.test.AndroidTestCase;
 import android.text.TextUtils;
+import android.view.inputmethod.EditorInfo;
 
 import java.io.File;
 import java.io.InputStream;
@@ -30,9 +31,9 @@ import java.util.Locale;
 
 public class SuggestTestsBase extends AndroidTestCase {
     protected static final KeyboardId US_KEYBOARD_ID = new KeyboardId("en_US qwerty keyboard",
-            com.android.inputmethod.latin.R.xml.kbd_qwerty, Locale.US,
-            Configuration.ORIENTATION_LANDSCAPE, KeyboardId.MODE_TEXT,
-            KeyboardView.COLOR_SCHEME_WHITE, false, false, false, 0, false);
+            com.android.inputmethod.latin.R.xml.kbd_qwerty, KeyboardView.COLOR_SCHEME_WHITE,
+            Locale.US, Configuration.ORIENTATION_LANDSCAPE, KeyboardId.MODE_TEXT,
+            new EditorInfo(), false, false, false, false);
 
     protected File mTestPackageFile;