diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 492883caf9d9ce954ea53ab3aa469eb40f3e6871..1e76571be156622092e24fd21160bc39777208fd 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -151,16 +151,11 @@ public class Keyboard {
      * @param context the application or service context
      * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
      * @param id keyboard identifier
+     * @param width keyboard width
      */
-    public Keyboard(Context context, int xmlLayoutResId, KeyboardId id) {
-        this(context, xmlLayoutResId, id,
-                context.getResources().getDisplayMetrics().widthPixels,
-                context.getResources().getDisplayMetrics().heightPixels);
-    }
 
-    private Keyboard(Context context, int xmlLayoutResId, KeyboardId id, int width,
-            int height) {
-        Resources res = context.getResources();
+    public Keyboard(Context context, int xmlLayoutResId, KeyboardId id, int width) {
+        final Resources res = context.getResources();
         GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
         GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
         GRID_SIZE = GRID_WIDTH * GRID_HEIGHT;
@@ -168,7 +163,8 @@ public class Keyboard {
         final int horizontalEdgesPadding = (int)res.getDimension(
                 R.dimen.keyboard_horizontal_edges_padding);
         mDisplayWidth = width - horizontalEdgesPadding * 2;
-        mDisplayHeight = height;
+        // TODO: Adjust the height by referring to the height of area available for drawing as well.
+        mDisplayHeight = res.getDisplayMetrics().heightPixels;
 
         mDefaultHorizontalGap = 0;
         setKeyWidth(mDisplayWidth / 10);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index f68b68f1d298dad1c592439007f3e47d6ca38ee3..eabbf709ccff50ddf7a412d3162834e987a3b9f7 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -40,6 +40,7 @@ public class KeyboardId {
 
     public final Locale mLocale;
     public final int mOrientation;
+    public final int mWidth;
     public final int mMode;
     public final int mXmlId;
     public final int mColorScheme;
@@ -49,17 +50,20 @@ public class KeyboardId {
     public final boolean mHasVoiceKey;
     public final int mImeAction;
     public final boolean mEnableShiftLock;
+
     public final String mXmlName;
+    public final EditorInfo mAttribute;
 
     private final int mHashCode;
 
     public KeyboardId(String xmlName, int xmlId, int colorScheme, Locale locale, int orientation,
-            int mode, EditorInfo attribute, boolean hasSettingsKey, boolean voiceKeyEnabled,
-            boolean hasVoiceKey, boolean enableShiftLock) {
+            int width, 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.mWidth = width;
         this.mMode = mode;
         this.mXmlId = xmlId;
         this.mColorScheme = colorScheme;
@@ -73,11 +77,14 @@ public class KeyboardId {
         this.mImeAction = imeOptions & (
                 EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
         this.mEnableShiftLock = enableShiftLock;
+
         this.mXmlName = xmlName;
+        this.mAttribute = attribute;
 
         this.mHashCode = Arrays.hashCode(new Object[] {
                 locale,
                 orientation,
+                width,
                 mode,
                 xmlId,
                 colorScheme,
@@ -90,6 +97,18 @@ public class KeyboardId {
         });
     }
 
+    public KeyboardId cloneWithNewLayout(String xmlName, int xmlId) {
+        return new KeyboardId(xmlName, xmlId, mColorScheme, mLocale, mOrientation, mWidth, mMode,
+                mAttribute, mHasSettingsKey, mVoiceKeyEnabled, mHasVoiceKey, mEnableShiftLock);
+    }
+
+    public KeyboardId cloneWithNewGeometry(int width) {
+        if (mWidth == width)
+            return this;
+        return new KeyboardId(mXmlName, mXmlId, mColorScheme, mLocale, mOrientation, width, mMode,
+                mAttribute, mHasSettingsKey, mVoiceKeyEnabled, mHasVoiceKey, mEnableShiftLock);
+    }
+
     public int getXmlId() {
         return mXmlId;
     }
@@ -118,6 +137,7 @@ public class KeyboardId {
     boolean equals(KeyboardId other) {
         return other.mLocale.equals(this.mLocale)
             && other.mOrientation == this.mOrientation
+            && other.mWidth == this.mWidth
             && other.mMode == this.mMode
             && other.mXmlId == this.mXmlId
             && other.mColorScheme == this.mColorScheme
@@ -136,10 +156,10 @@ public class KeyboardId {
 
     @Override
     public String toString() {
-        return String.format("[%s.xml %s %s %s imeAction=%s %s%s%s%s%s%s]",
+        return String.format("[%s.xml %s %s%d %s %s %s%s%s%s%s%s]",
                 mXmlName,
                 mLocale,
-                (mOrientation == 1 ? "port" : "land"),
+                (mOrientation == 1 ? "port" : "land"), mWidth,
                 modeName(mMode),
                 EditorInfoCompatUtils.imeOptionsName(mImeAction),
                 (mPasswordInput ? " passwordInput" : ""),
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 384139112a242d9c4a13848f765f924a933d0329..88823108fbddaeb2f10ab6d743f1f37440fb83a9 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -37,7 +37,7 @@ import java.util.Locale;
 
 public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener {
     private static final String TAG = "KeyboardSwitcher";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG_CACHE = false;
     public static final boolean DEBUG_STATE = false;
 
     private static String sConfigDefaultKeyboardThemeId;
@@ -99,6 +99,7 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
     private static final int DEFAULT_SETTINGS_KEY_MODE = SETTINGS_KEY_MODE_AUTO;
 
     private int mLayoutId;
+    private int mKeyboardWidth;
 
     private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
 
@@ -151,17 +152,39 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         // Update the settings key state because number of enabled IMEs could have been changed
         mSettingsKeyEnabledInSettings = getSettingsKeyMode(mPrefs, mInputMethodService);
         final KeyboardId id = getKeyboardId(attribute, isSymbols);
-        makeSymbolsKeyboardIds(id.mMode, attribute);
-        mCurrentId = id;
-        final Resources res = mInputMethodService.getResources();
-        mInputView.setKeyPreviewPopupEnabled(Settings.Values.isKeyPreviewPopupEnabled(mPrefs, res),
-                Settings.Values.getKeyPreviewPopupDismissDelay(mPrefs, res));
+
+        // 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,
+        // "@integer/key_shift" key code is used for that purpose in order to properly display
+        // "more" and "locked more" key labels.  To achieve these behavior, we should initialize
+        // mSymbolsId and mSymbolsShiftedId to "phone keyboard" and "phone symbols keyboard"
+        // respectively here for xlarge device's layout switching.
+        mSymbolsId = makeSiblingKeyboardId(id, R.xml.kbd_symbols, R.xml.kbd_phone);
+        mSymbolsShiftedId = makeSiblingKeyboardId(
+                id, R.xml.kbd_symbols_shift, R.xml.kbd_phone_symbols);
+
         setKeyboard(getKeyboard(id));
     }
 
+    public void onSizeChanged() {
+        final int width = mInputMethodService.getWindow().getWindow().getDecorView().getWidth();
+        if (width == 0)
+            return;
+        mKeyboardWidth = width;
+        // Set keyboard with new width.
+        final KeyboardId newId = mCurrentId.cloneWithNewGeometry(width);
+        setKeyboard(getKeyboard(newId));
+    }
+
     private void setKeyboard(final Keyboard newKeyboard) {
         final Keyboard oldKeyboard = mInputView.getKeyboard();
         mInputView.setKeyboard(newKeyboard);
+        mCurrentId = newKeyboard.mId;
+        final Resources res = mInputMethodService.getResources();
+        mInputView.setKeyPreviewPopupEnabled(
+                Settings.Values.isKeyPreviewPopupEnabled(mPrefs, res),
+                Settings.Values.getKeyPreviewPopupDismissDelay(mPrefs, res));
         final boolean localeChanged = (oldKeyboard == null)
                 || !newKeyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
         mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
@@ -175,19 +198,19 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
             final Locale savedLocale = Utils.setSystemLocale(res,
                     mSubtypeSwitcher.getInputLocale());
 
-            keyboard = new LatinKeyboard(mInputMethodService, id);
+            keyboard = new LatinKeyboard(mInputMethodService, id, id.mWidth);
 
             if (id.mEnableShiftLock) {
                 keyboard.enableShiftLock();
             }
 
             mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard));
-            if (DEBUG)
+            if (DEBUG_CACHE)
                 Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": "
                         + ((ref == null) ? "LOAD" : "GCed") + " id=" + id);
 
             Utils.setSystemLocale(res, savedLocale);
-        } else if (DEBUG) {
+        } else if (DEBUG_CACHE) {
             Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT  id=" + id);
         }
 
@@ -244,33 +267,19 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
         final boolean hasSettingsKey = hasSettingsKey(attribute);
         final Resources res = mInputMethodService.getResources();
         final int orientation = res.getConfiguration().orientation;
+        if (mKeyboardWidth == 0)
+            mKeyboardWidth = res.getDisplayMetrics().widthPixels;
         final Locale locale = mSubtypeSwitcher.getInputLocale();
         return new KeyboardId(
-                res.getResourceEntryName(xmlId), xmlId, charColorId, locale, orientation, mode,
-                attribute, hasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, enableShiftLock);
+                res.getResourceEntryName(xmlId), xmlId, charColorId, locale, orientation,
+                mKeyboardWidth, mode, attribute, hasSettingsKey, mVoiceKeyEnabled, hasVoiceKey,
+                enableShiftLock);
     }
 
-    private void makeSymbolsKeyboardIds(final int mode, EditorInfo attribute) {
-        final Locale locale = mSubtypeSwitcher.getInputLocale();
-        final Resources res = mInputMethodService.getResources();
-        final int orientation = res.getConfiguration().orientation;
-        final int colorScheme = getColorScheme();
-        final boolean hasVoiceKey = mVoiceKeyEnabled && !mVoiceButtonOnPrimary;
-        final boolean hasSettingsKey = hasSettingsKey(attribute);
-        // 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,
-        // "@integer/key_shift" key code is used for that purpose in order to properly display
-        // "more" and "locked more" key labels.  To achieve these behavior, we should initialize
-        // 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;
-        final String xmlName = res.getResourceEntryName(xmlId);
-        mSymbolsId = new KeyboardId(xmlName, xmlId, colorScheme, locale, orientation, mode,
-                attribute, hasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, false);
-        xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift;
-        mSymbolsShiftedId = new KeyboardId(xmlName, xmlId, colorScheme, locale, orientation, mode,
-                attribute, hasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, false);
+    private KeyboardId makeSiblingKeyboardId(KeyboardId base, int alphabet, int phone) {
+        final int xmlId = base.mMode == KeyboardId.MODE_PHONE ? phone : alphabet;
+        final String xmlName = mInputMethodService.getResources().getResourceEntryName(xmlId);
+        return base.cloneWithNewLayout(xmlName, xmlId);
     }
 
     public int getKeyboardMode() {
@@ -561,14 +570,12 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha
             return;
         final LatinKeyboard keyboard;
         if (mCurrentId.equals(mSymbolsId) || !mCurrentId.equals(mSymbolsShiftedId)) {
-            mCurrentId = mSymbolsShiftedId;
-            keyboard = getKeyboard(mCurrentId);
+            keyboard = getKeyboard(mSymbolsShiftedId);
             // Symbol shifted keyboard has an ALT key that has a caps lock style indicator. To
             // enable the indicator, we need to call setShiftLocked(true).
             keyboard.setShiftLocked(true);
         } else {
-            mCurrentId = mSymbolsId;
-            keyboard = getKeyboard(mCurrentId);
+            keyboard = getKeyboard(mSymbolsId);
             // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the
             // indicator, we need to call setShiftLocked(false).
             keyboard.setShiftLocked(false);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 4f85c0348a9e5f0a3517681a9cee252273db75a0..1df6444a01d61eaadcc9000550a23d4fdc85006e 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -462,6 +462,12 @@ public class KeyboardView extends View implements PointerTracker.UIProxy {
         return mKeyboardActionListener;
     }
 
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        // TODO: Should notify InputMethodService instead?
+        KeyboardSwitcher.getInstance().onSizeChanged();
+    }
+
     /**
      * Attaches a keyboard to this view. The keyboard can be switched at any time and the
      * view will re-layout itself to accommodate the keyboard.
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
index c279769f6e742b6061f7d2493098308e11026f15..16aa5968926e4748f408a7d3c21edf8ec4fb3c81 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
@@ -88,8 +88,8 @@ public class LatinKeyboard extends Keyboard {
     private static final String SMALL_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR = "small";
     private static final String MEDIUM_TEXT_SIZE_OF_LANGUAGE_ON_SPACEBAR = "medium";
 
-    public LatinKeyboard(Context context, KeyboardId id) {
-        super(context, id.getXmlId(), id);
+    public LatinKeyboard(Context context, KeyboardId id, int width) {
+        super(context, id.getXmlId(), id, width);
         final Resources res = context.getResources();
         mContext = context;
 
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
index 5dde15e94065083ee4811cc90d5a52fd84923777..69e9dd8da542a95fc75755ce42fef6188ea537ef 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
@@ -23,8 +23,8 @@ import java.util.List;
 public class MiniKeyboard extends Keyboard {
     private int mDefaultKeyCoordX;
 
-    public MiniKeyboard(Context context, int xmlLayoutResId, KeyboardId id) {
-        super(context, xmlLayoutResId, id);
+    public MiniKeyboard(Context context, int xmlLayoutResId, Keyboard parentKeyboard) {
+        super(context, xmlLayoutResId, null, parentKeyboard.getMinWidth());
     }
 
     public void setDefaultCoordX(int pos) {
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java
index 2b83c3ff5c6628d7b8708cee8f6725643f0b5510..29f41cd22b43cbc7b3ea0b97bd85ea9a3f714173 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardBuilder.java
@@ -185,7 +185,8 @@ public class MiniKeyboardBuilder {
             Keyboard parentKeyboard) {
         final Context context = view.getContext();
         mRes = context.getResources();
-        final MiniKeyboard keyboard = new MiniKeyboard(context, layoutTemplateResId, null);
+        final MiniKeyboard keyboard = new MiniKeyboard(
+                context, layoutTemplateResId, parentKeyboard);
         mKeyboard = keyboard;
         mPopupCharacters = parentKey.mPopupCharacters;
 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 2c39eba55fbe341ce5f9ff963ae73f69df8c593b..4043b3581b325051f03be01651b6ffb08989aa43 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -623,6 +623,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
         }
     }
 
+    @Override
+    public void onWindowHidden() {
+        super.onWindowHidden();
+        KeyboardView inputView = mKeyboardSwitcher.getInputView();
+        if (inputView != null) inputView.closing();
+    }
+
     @Override
     public void onFinishInput() {
         super.onFinishInput();
@@ -809,7 +816,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
             if (isExtractViewShown()) {
                 // No need to have extra space to show the key preview.
                 mCandidateViewContainer.setMinimumHeight(0);
-                super.setCandidatesViewShown(shown);
+                super.setCandidatesViewShown(shouldShowCandidates);
             } else {
                 // We must control the visibility of the suggestion strip in order to avoid clipped
                 // key previews, even when we don't show the suggestion strip.
diff --git a/tests/src/com/android/inputmethod/latin/SuggestHelper.java b/tests/src/com/android/inputmethod/latin/SuggestHelper.java
index 8a11ff955463f20dfb94c6dcd793e2e0b0e62300..87ea011fa1d57e7b225d4c6af2a4b1704bc984e2 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestHelper.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestHelper.java
@@ -36,7 +36,7 @@ public class SuggestHelper {
         // Use null as the locale for Suggest so as to force it to use the internal dictionary
         // (and not try to find a dictionary provider for a specified locale)
         mSuggest = new Suggest(context, dictionaryId, null);
-        mKeyboard = new LatinKeyboard(context, keyboardId);
+        mKeyboard = new LatinKeyboard(context, keyboardId, keyboardId.mWidth);
         mKeyDetector = new KeyDetector();
         init();
     }
@@ -44,7 +44,7 @@ public class SuggestHelper {
     protected SuggestHelper(Context context, File dictionaryPath, long startOffset, long length,
             KeyboardId keyboardId) {
         mSuggest = new Suggest(context, dictionaryPath, startOffset, length, null);
-        mKeyboard = new LatinKeyboard(context, keyboardId);
+        mKeyboard = new LatinKeyboard(context, keyboardId, keyboardId.mWidth);
         mKeyDetector = new KeyDetector();
         init();
     }
diff --git a/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java b/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
index 64f26743e121f3318d97b0d0dca0d4c586bce44f..cf4ccfeaad6f883724402cb32f05afe89fd64a82 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
@@ -38,10 +38,11 @@ public class SuggestTestsBase extends AndroidTestCase {
         mTestPackageFile = new File(getTestContext().getApplicationInfo().sourceDir);
     }
 
-    protected static KeyboardId createKeyboardId(Locale locale) {
+    protected KeyboardId createKeyboardId(Locale locale) {
+        final int displayWidth = getContext().getResources().getDisplayMetrics().widthPixels;
         return new KeyboardId(locale.toString() + " keyboard",
                 com.android.inputmethod.latin.R.xml.kbd_qwerty, KeyboardView.COLOR_SCHEME_WHITE,
-                locale, Configuration.ORIENTATION_LANDSCAPE, KeyboardId.MODE_TEXT,
+                locale, displayWidth, Configuration.ORIENTATION_LANDSCAPE, KeyboardId.MODE_TEXT,
                 new EditorInfo(), false, false, false, false);
     }