Merge "Add explicit NULL check to latinime_Keyboard_setProximityInfo() and ProximityInfo::ProximityInfo()."
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index 703258b..2baae54 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -1,4 +1,5 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        coreApp="true"
         package="com.android.inputmethod.latin">
 
     <uses-permission android:name="android.permission.VIBRATE"/>
diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
index 0f9bde8..4a5c5a4 100644
--- a/java/res/values-land/dimens.xml
+++ b/java/res/values-land/dimens.xml
@@ -25,7 +25,6 @@
     <!-- key_height + key_bottom_gap = popup_key_height -->
 <!--    <dimen name="key_height">0.260in</dimen>-->
     <dimen name="popup_key_height">0.280in</dimen>
-    <dimen name="keyboard_horizontal_edges_padding">0.0in</dimen>
 
     <fraction name="keyboard_top_padding">1.818%p</fraction>
     <fraction name="keyboard_bottom_padding">0.0%p</fraction>
diff --git a/java/res/values-sw600dp-land/dimens.xml b/java/res/values-sw600dp-land/dimens.xml
index c1cef1d..1b8c8a6 100644
--- a/java/res/values-sw600dp-land/dimens.xml
+++ b/java/res/values-sw600dp-land/dimens.xml
@@ -23,7 +23,6 @@
     <dimen name="keyboardHeight">45.0mm</dimen>
     <fraction name="minKeyboardHeight">45%p</fraction>
 
-    <dimen name="keyboard_horizontal_edges_padding">0dp</dimen>
     <fraction name="keyboard_top_padding">2.444%p</fraction>
     <fraction name="keyboard_bottom_padding">0.0%p</fraction>
     <fraction name="key_bottom_gap">4.911%p</fraction>
diff --git a/java/res/values-sw600dp/dimens.xml b/java/res/values-sw600dp/dimens.xml
index e1bdecf..3183023 100644
--- a/java/res/values-sw600dp/dimens.xml
+++ b/java/res/values-sw600dp/dimens.xml
@@ -26,7 +26,6 @@
 
     <dimen name="popup_key_height">10.0mm</dimen>
 
-    <dimen name="keyboard_horizontal_edges_padding">0.0mm</dimen>
     <fraction name="keyboard_top_padding">2.291%p</fraction>
     <fraction name="keyboard_bottom_padding">0.0%p</fraction>
     <fraction name="key_bottom_gap">3.750%p</fraction>
diff --git a/java/res/values-sw768dp-land/dimens.xml b/java/res/values-sw768dp-land/dimens.xml
index 8f9b006..664e8c1 100644
--- a/java/res/values-sw768dp-land/dimens.xml
+++ b/java/res/values-sw768dp-land/dimens.xml
@@ -23,7 +23,6 @@
     <dimen name="keyboardHeight">58.0mm</dimen>
     <fraction name="minKeyboardHeight">45%p</fraction>
 
-    <dimen name="keyboard_horizontal_edges_padding">0.0mm</dimen>
     <fraction name="keyboard_top_padding">1.896%p</fraction>
     <fraction name="keyboard_bottom_padding">0.0%p</fraction>
 
diff --git a/java/res/values-sw768dp/dimens.xml b/java/res/values-sw768dp/dimens.xml
index b825b14..bb4937d 100644
--- a/java/res/values-sw768dp/dimens.xml
+++ b/java/res/values-sw768dp/dimens.xml
@@ -24,7 +24,6 @@
     <fraction name="maxKeyboardHeight">50%p</fraction>
     <fraction name="minKeyboardHeight">-35.0%p</fraction>
 
-    <dimen name="keyboard_horizontal_edges_padding">0.0mm</dimen>
     <fraction name="keyboard_top_padding">2.291%p</fraction>
     <fraction name="keyboard_bottom_padding">0.0%p</fraction>
 
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index cd1b460..1776630 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -144,19 +144,10 @@
         <!-- Minimum keyboard height represented in pixels, percentage of display height if fraction
              is positive, or percentage of display width if fraction is negative. -->
         <attr name="minKeyboardHeight" format="dimension|fraction" />
-        <!-- Keyboard top and bottom paddings. -->
+        <!-- Keyboard top, bottom, both horizontal edges paddings. -->
         <attr name="keyboardTopPadding" format="dimension|fraction" />
         <attr name="keyboardBottomPadding" format="dimension|fraction" />
-        <!-- Default width of a key, in pixels or percentage of display width.
-             If the value is zero, the actual key width will be determined to fill out the area up
-             to the right edge of the keyboard.
-             If the value is negative, the actual key width will be determined to fill out the
-             area between the nearest key on the left hand side and the right edge of the keyboard.
-             -->
-        <attr name="keyWidth" format="dimension|fraction|enum">
-            <enum name="fillRight" value="-1" />
-            <enum name="fillBoth" value="-2" />
-        </attr>
+        <attr name="keyboardHorizontalEdgesPadding" format="dimension|fraction" />
         <!-- Default height of a row (key height + vertical gap), in pixels or percentage of
              keyboard height. -->
         <attr name="rowHeight" format="dimension|fraction" />
@@ -258,6 +249,17 @@
         <!-- Visual insets -->
         <attr name="visualInsetsLeft" format="dimension|fraction" />
         <attr name="visualInsetsRight" format="dimension|fraction" />
+        <!-- Width of the key, in pixels or percentage of display width.
+             If the value is fillRight, the actual key width will be determined to fill out the area
+             up to the right edge of the keyboard.
+             If the value is fillBoth, the actual key width will be determined to fill out the
+             area between the nearest key on the left hand side and the right edge of the keyboard.
+             -->
+        <!-- This should be aligned with KeyboardBuilder.Row.KEYWIDTH_* -->
+        <attr name="keyWidth" format="dimension|fraction|enum">
+            <enum name="fillRight" value="-1" />
+            <enum name="fillBoth" value="-2" />
+        </attr>
         <!-- The X-coordinate of upper right corner of this key including horizontal gap.
              If the value is negative, the origin is the right edge of the keyboard. -->
         <attr name="keyXPos" format="dimension|fraction" />
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index cbd557e..8b4cd6d 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -29,9 +29,9 @@
     <dimen name="mini_keyboard_horizontal_edges_padding">16dip</dimen>
     <dimen name="mini_keyboard_key_horizontal_padding">8dip</dimen>
 
-    <dimen name="keyboard_horizontal_edges_padding">0dp</dimen>
     <fraction name="keyboard_top_padding">1.556%p</fraction>
     <fraction name="keyboard_bottom_padding">4.669%p</fraction>
+    <fraction name="keyboard_horizontal_edges_padding">0%p</fraction>
     <fraction name="key_bottom_gap">6.250%p</fraction>
     <fraction name="key_horizontal_gap">1.352%p</fraction>
 
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index 7b8bfa8..c6ea2a5 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -24,6 +24,7 @@
         <item name="moreKeysTemplate">@xml/kbd_mini_keyboard_template</item>
         <item name="keyboardTopPadding">@fraction/keyboard_top_padding</item>
         <item name="keyboardBottomPadding">@fraction/keyboard_bottom_padding</item>
+        <item name="keyboardHorizontalEdgesPadding">@fraction/keyboard_horizontal_edges_padding</item>
         <item name="horizontalGap">@fraction/key_horizontal_gap</item>
         <item name="verticalGap">@fraction/key_bottom_gap</item>
         <item name="maxMoreKeysColumn">@integer/config_max_more_keys_column</item>
diff --git a/java/res/xml-land/kbd_number.xml b/java/res/xml-land/kbd_number.xml
new file mode 100644
index 0000000..f5930ef
--- /dev/null
+++ b/java/res/xml-land/kbd_number.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyboardHorizontalEdgesPadding="10%p"
+    latin:keyWidth="26.67%p"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_rows_number" />
+</Keyboard>
diff --git a/java/res/xml-land/kbd_phone.xml b/java/res/xml-land/kbd_phone.xml
new file mode 100644
index 0000000..3b1fb36
--- /dev/null
+++ b/java/res/xml-land/kbd_phone.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyboardHorizontalEdgesPadding="10%p"
+    latin:keyWidth="26.67%p"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_rows_phone" />
+</Keyboard>
diff --git a/java/res/xml-land/kbd_phone_shift.xml b/java/res/xml-land/kbd_phone_shift.xml
new file mode 100644
index 0000000..e596647
--- /dev/null
+++ b/java/res/xml-land/kbd_phone_shift.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyboardHorizontalEdgesPadding="10%p"
+    latin:keyWidth="26.67%p"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_rows_phone_shift" />
+</Keyboard>
diff --git a/java/res/xml-sw600dp-land/kbd_mini_keyboard_template.xml b/java/res/xml-sw600dp-land/kbd_mini_keyboard_template.xml
index 3c19c29..8272e02 100644
--- a/java/res/xml-sw600dp-land/kbd_mini_keyboard_template.xml
+++ b/java/res/xml-sw600dp-land/kbd_mini_keyboard_template.xml
@@ -21,5 +21,6 @@
 <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
     latin:keyWidth="5%p"
     latin:rowHeight="@dimen/popup_key_height"
+    style="?attr/miniKeyboardStyle"
     >
 </Keyboard>
diff --git a/java/res/xml-sw600dp/kbd_mini_keyboard_template.xml b/java/res/xml-sw600dp/kbd_mini_keyboard_template.xml
index 9955fe8..0d5795f 100644
--- a/java/res/xml-sw600dp/kbd_mini_keyboard_template.xml
+++ b/java/res/xml-sw600dp/kbd_mini_keyboard_template.xml
@@ -21,5 +21,6 @@
 <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
     latin:keyWidth="8%p"
     latin:rowHeight="@dimen/popup_key_height"
+    style="?attr/miniKeyboardStyle"
     >
 </Keyboard>
diff --git a/java/res/xml-sw768dp-land/kbd_mini_keyboard_template.xml b/java/res/xml-sw768dp-land/kbd_mini_keyboard_template.xml
index d5f80e7..85e864a 100644
--- a/java/res/xml-sw768dp-land/kbd_mini_keyboard_template.xml
+++ b/java/res/xml-sw768dp-land/kbd_mini_keyboard_template.xml
@@ -21,5 +21,6 @@
 <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
     latin:keyWidth="3.5%p"
     latin:rowHeight="@dimen/popup_key_height"
+    style="?attr/miniKeyboardStyle"
     >
 </Keyboard>
diff --git a/java/res/xml-sw768dp/kbd_mini_keyboard_template.xml b/java/res/xml-sw768dp/kbd_mini_keyboard_template.xml
index 1c15a5e..409c605 100644
--- a/java/res/xml-sw768dp/kbd_mini_keyboard_template.xml
+++ b/java/res/xml-sw768dp/kbd_mini_keyboard_template.xml
@@ -21,5 +21,6 @@
 <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
     latin:keyWidth="5.0%p"
     latin:rowHeight="@dimen/popup_key_height"
+    style="?attr/miniKeyboardStyle"
     >
 </Keyboard>
diff --git a/java/res/xml/kbd_number.xml b/java/res/xml/kbd_number.xml
index aabf0eb..38dd6bf 100644
--- a/java/res/xml/kbd_number.xml
+++ b/java/res/xml/kbd_number.xml
@@ -23,109 +23,5 @@
     latin:keyWidth="26.67%p"
 >
     <include
-        latin:keyboardLayout="@xml/kbd_key_styles" />
-    <include
-        latin:keyboardLayout="@xml/kbd_numkey_styles" />
-    <switch>
-        <case
-            latin:passwordInput="true"
-        >
-            <Row>
-                <Key
-                    latin:keyStyle="num1KeyStyle" />
-                <Key
-                    latin:keyStyle="num2KeyStyle" />
-                <Key
-                    latin:keyStyle="num3KeyStyle" />
-            </Row>
-            <Row>
-                <Key
-                    latin:keyStyle="num4KeyStyle" />
-                <Key
-                    latin:keyStyle="num5KeyStyle" />
-                <Key
-                    latin:keyStyle="num6KeyStyle" />
-            </Row>
-            <Row>
-                <Key
-                    latin:keyStyle="num7KeyStyle" />
-                <Key
-                    latin:keyStyle="num8KeyStyle" />
-                <Key
-                    latin:keyStyle="num9KeyStyle" />
-                <Key
-                    latin:keyStyle="deleteKeyStyle"
-                    latin:keyWidth="fillRight" />
-            </Row>
-            <Row>
-                <Spacer />
-                <Key
-                    latin:keyStyle="num0KeyStyle" />
-                <Spacer />
-                <Key
-                    latin:keyStyle="returnKeyStyle"
-                    latin:keyWidth="fillRight" />
-            </Row>
-        </case>
-        <!-- latin:passwordInput="false" -->
-        <default>
-            <Row>
-                <Key
-                    latin:keyLabel="1"
-                    latin:keyStyle="numKeyStyle" />
-                <Key
-                    latin:keyLabel="2"
-                    latin:keyStyle="numKeyStyle" />
-                <Key
-                    latin:keyLabel="3"
-                    latin:keyStyle="numKeyStyle" />
-                <Key
-                    latin:keyLabel="-"
-                    latin:keyStyle="numFunctionalKeyStyle"
-                    latin:keyWidth="fillRight" />
-            </Row>
-            <Row>
-                <Key
-                    latin:keyLabel="4"
-                    latin:keyStyle="numKeyStyle" />
-                <Key
-                    latin:keyLabel="5"
-                    latin:keyStyle="numKeyStyle" />
-                <Key
-                    latin:keyLabel="6"
-                    latin:keyStyle="numKeyStyle" />
-                <Key
-                    latin:keyLabel=","
-                    latin:keyStyle="numFunctionalKeyStyle"
-                    latin:keyWidth="fillRight" />
-            </Row>
-            <Row>
-                <Key
-                    latin:keyLabel="7"
-                    latin:keyStyle="numKeyStyle" />
-                <Key
-                    latin:keyLabel="8"
-                    latin:keyStyle="numKeyStyle"/>
-                <Key
-                    latin:keyLabel="9"
-                    latin:keyStyle="numKeyStyle" />
-                <Key
-                    latin:keyStyle="deleteKeyStyle"
-                    latin:keyWidth="fillRight" />
-            </Row>
-            <Row>
-                <Key
-                    latin:keyStyle="numSpaceKeyStyle" />
-                <Key
-                    latin:keyLabel="0"
-                    latin:keyStyle="numKeyStyle" />
-                <Key
-                    latin:keyLabel="."
-                    latin:keyStyle="numKeyStyle" />
-                <Key
-                    latin:keyStyle="returnKeyStyle"
-                    latin:keyWidth="fillRight" />
-            </Row>
-        </default>
-    </switch>
+        latin:keyboardLayout="@xml/kbd_rows_number" />
 </Keyboard>
diff --git a/java/res/xml/kbd_phone.xml b/java/res/xml/kbd_phone.xml
index 4588ab2..b550f17 100644
--- a/java/res/xml/kbd_phone.xml
+++ b/java/res/xml/kbd_phone.xml
@@ -1,19 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* 
+/*
 **
 ** Copyright 2008, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 -->
@@ -23,53 +23,5 @@
     latin:keyWidth="26.67%p"
 >
     <include
-        latin:keyboardLayout="@xml/kbd_key_styles" />
-    <include
-        latin:keyboardLayout="@xml/kbd_numkey_styles" />
-    <Row>
-        <Key
-            latin:keyStyle="num1KeyStyle" />
-        <Key
-            latin:keyStyle="num2KeyStyle" />
-        <Key
-            latin:keyStyle="num3KeyStyle" />
-        <Key
-            latin:keyLabel="-"
-            latin:keyStyle="numFunctionalKeyStyle"
-            latin:keyWidth="fillRight" />
-    </Row>
-    <Row>
-        <Key
-            latin:keyStyle="num4KeyStyle" />
-        <Key
-            latin:keyStyle="num5KeyStyle" />
-        <Key
-            latin:keyStyle="num6KeyStyle" />
-        <Key
-            latin:keyLabel="."
-            latin:keyStyle="numFunctionalKeyStyle"
-            latin:keyWidth="fillRight" />
-    </Row>
-    <Row>
-        <Key
-            latin:keyStyle="num7KeyStyle" />
-        <Key
-            latin:keyStyle="num8KeyStyle" />
-        <Key
-            latin:keyStyle="num9KeyStyle" />
-        <Key
-            latin:keyStyle="deleteKeyStyle"
-            latin:keyWidth="fillRight" />
-    </Row>
-    <Row>
-        <Key
-            latin:keyStyle="numSwitchToAltKeyStyle" />
-        <Key
-            latin:keyStyle="num0KeyStyle" />
-        <Key
-            latin:keyStyle="numSpaceKeyStyle" />
-        <Key
-            latin:keyStyle="returnKeyStyle"
-            latin:keyWidth="fillRight" />
-    </Row>
+        latin:keyboardLayout="@xml/kbd_rows_phone" />
 </Keyboard>
diff --git a/java/res/xml/kbd_phone_shift.xml b/java/res/xml/kbd_phone_shift.xml
index 5be9bf9..eea823f 100644
--- a/java/res/xml/kbd_phone_shift.xml
+++ b/java/res/xml/kbd_phone_shift.xml
@@ -1,19 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* 
+/*
 **
 ** Copyright 2008, The Android Open Source Project
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 -->
@@ -23,66 +23,5 @@
     latin:keyWidth="26.67%p"
 >
     <include
-        latin:keyboardLayout="@xml/kbd_key_styles" />
-    <include
-        latin:keyboardLayout="@xml/kbd_numkey_styles" />
-    <Row>
-        <Key
-            latin:keyLabel="("
-            latin:keyStyle="numKeyStyle" />
-        <Key
-            latin:keyLabel="/"
-            latin:keyStyle="numKeyStyle" />
-        <Key
-            latin:keyLabel=")"
-            latin:keyStyle="numKeyStyle" />
-        <Key
-            latin:keyLabel="-"
-            latin:keyStyle="numFunctionalKeyStyle"
-            latin:keyWidth="fillRight" />
-    </Row>
-    <Row>
-        <Key
-            latin:keyLabel="N" />
-        <!-- Pause is a comma. Check PhoneNumberUtils.java to see if this 
-            has changed. -->
-        <Key
-            latin:code="44"
-            latin:keyLabel="@string/label_pause_key"
-            latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" />
-        <Key
-            latin:keyLabel=","
-            latin:keyStyle="numKeyStyle" />
-        <Key
-            latin:keyLabel="."
-            latin:keyStyle="numFunctionalKeyStyle"
-            latin:keyWidth="fillRight" />
-    </Row>
-    <Row>
-        <Key
-            latin:keyStyle="numStarKeyStyle" />
-        <!-- Wait is a semicolon. -->
-        <Key
-            latin:code="59"
-            latin:keyLabel="@string/label_wait_key"
-            latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" />
-        <Key
-            latin:keyLabel="#"
-            latin:keyStyle="numKeyStyle" />
-        <Key
-            latin:keyStyle="deleteKeyStyle"
-            latin:keyWidth="fillRight" />
-    </Row>
-    <Row>
-        <Key
-            latin:keyStyle="numSwitchToNumericKeyStyle" />
-        <Key
-            latin:keyLabel="+"
-            latin:keyStyle="numKeyStyle" />
-        <Key
-            latin:keyStyle="numSpaceKeyStyle" />
-        <Key
-            latin:keyStyle="returnKeyStyle"
-            latin:keyWidth="fillRight" />
-    </Row>
+        latin:keyboardLayout="@xml/kbd_rows_phone_shift" />
 </Keyboard>
diff --git a/java/res/xml/kbd_rows_number.xml b/java/res/xml/kbd_rows_number.xml
new file mode 100644
index 0000000..21d0656
--- /dev/null
+++ b/java/res/xml/kbd_rows_number.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <include
+        latin:keyboardLayout="@xml/kbd_numkey_styles" />
+    <switch>
+        <case
+            latin:passwordInput="true"
+        >
+            <Row>
+                <Key
+                    latin:keyStyle="num1KeyStyle" />
+                <Key
+                    latin:keyStyle="num2KeyStyle" />
+                <Key
+                    latin:keyStyle="num3KeyStyle" />
+            </Row>
+            <Row>
+                <Key
+                    latin:keyStyle="num4KeyStyle" />
+                <Key
+                    latin:keyStyle="num5KeyStyle" />
+                <Key
+                    latin:keyStyle="num6KeyStyle" />
+            </Row>
+            <Row>
+                <Key
+                    latin:keyStyle="num7KeyStyle" />
+                <Key
+                    latin:keyStyle="num8KeyStyle" />
+                <Key
+                    latin:keyStyle="num9KeyStyle" />
+                <Key
+                    latin:keyStyle="deleteKeyStyle"
+                    latin:keyWidth="fillRight" />
+            </Row>
+            <Row>
+                <Spacer />
+                <Key
+                    latin:keyStyle="num0KeyStyle" />
+                <Spacer />
+                <Key
+                    latin:keyStyle="returnKeyStyle"
+                    latin:keyWidth="fillRight" />
+            </Row>
+        </case>
+        <!-- latin:passwordInput="false" -->
+        <default>
+            <Row>
+                <Key
+                    latin:keyLabel="1"
+                    latin:keyStyle="numKeyStyle" />
+                <Key
+                    latin:keyLabel="2"
+                    latin:keyStyle="numKeyStyle" />
+                <Key
+                    latin:keyLabel="3"
+                    latin:keyStyle="numKeyStyle" />
+                <Key
+                    latin:keyLabel="-"
+                    latin:keyStyle="numFunctionalKeyStyle"
+                    latin:keyWidth="fillRight" />
+            </Row>
+            <Row>
+                <Key
+                    latin:keyLabel="4"
+                    latin:keyStyle="numKeyStyle" />
+                <Key
+                    latin:keyLabel="5"
+                    latin:keyStyle="numKeyStyle" />
+                <Key
+                    latin:keyLabel="6"
+                    latin:keyStyle="numKeyStyle" />
+                <Key
+                    latin:keyLabel=","
+                    latin:keyStyle="numFunctionalKeyStyle"
+                    latin:keyWidth="fillRight" />
+            </Row>
+            <Row>
+                <Key
+                    latin:keyLabel="7"
+                    latin:keyStyle="numKeyStyle" />
+                <Key
+                    latin:keyLabel="8"
+                    latin:keyStyle="numKeyStyle"/>
+                <Key
+                    latin:keyLabel="9"
+                    latin:keyStyle="numKeyStyle" />
+                <Key
+                    latin:keyStyle="deleteKeyStyle"
+                    latin:keyWidth="fillRight" />
+            </Row>
+            <Row>
+                <Key
+                    latin:keyStyle="numSpaceKeyStyle" />
+                <Key
+                    latin:keyLabel="0"
+                    latin:keyStyle="numKeyStyle" />
+                <Key
+                    latin:keyLabel="."
+                    latin:keyStyle="numKeyStyle" />
+                <Key
+                    latin:keyStyle="returnKeyStyle"
+                    latin:keyWidth="fillRight" />
+            </Row>
+        </default>
+    </switch>
+</merge>
diff --git a/java/res/xml/kbd_rows_phone.xml b/java/res/xml/kbd_rows_phone.xml
new file mode 100644
index 0000000..5500a60
--- /dev/null
+++ b/java/res/xml/kbd_rows_phone.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <include
+        latin:keyboardLayout="@xml/kbd_numkey_styles" />
+    <Row>
+        <Key
+            latin:keyStyle="num1KeyStyle" />
+        <Key
+            latin:keyStyle="num2KeyStyle" />
+        <Key
+            latin:keyStyle="num3KeyStyle" />
+        <Key
+            latin:keyLabel="-"
+            latin:keyStyle="numFunctionalKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyStyle="num4KeyStyle" />
+        <Key
+            latin:keyStyle="num5KeyStyle" />
+        <Key
+            latin:keyStyle="num6KeyStyle" />
+        <Key
+            latin:keyLabel="."
+            latin:keyStyle="numFunctionalKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyStyle="num7KeyStyle" />
+        <Key
+            latin:keyStyle="num8KeyStyle" />
+        <Key
+            latin:keyStyle="num9KeyStyle" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyStyle="numSwitchToAltKeyStyle" />
+        <Key
+            latin:keyStyle="num0KeyStyle" />
+        <Key
+            latin:keyStyle="numSpaceKeyStyle" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+</merge>
diff --git a/java/res/xml/kbd_rows_phone_shift.xml b/java/res/xml/kbd_rows_phone_shift.xml
new file mode 100644
index 0000000..3c283d3
--- /dev/null
+++ b/java/res/xml/kbd_rows_phone_shift.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <include
+        latin:keyboardLayout="@xml/kbd_numkey_styles" />
+    <Row>
+        <Key
+            latin:keyLabel="("
+            latin:keyStyle="numKeyStyle" />
+        <Key
+            latin:keyLabel="/"
+            latin:keyStyle="numKeyStyle" />
+        <Key
+            latin:keyLabel=")"
+            latin:keyStyle="numKeyStyle" />
+        <Key
+            latin:keyLabel="-"
+            latin:keyStyle="numFunctionalKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyLabel="N" />
+        <!-- Pause is a comma. Check PhoneNumberUtils.java to see if this
+            has changed. -->
+        <Key
+            latin:code="44"
+            latin:keyLabel="@string/label_pause_key"
+            latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" />
+        <Key
+            latin:keyLabel=","
+            latin:keyStyle="numKeyStyle" />
+        <Key
+            latin:keyLabel="."
+            latin:keyStyle="numFunctionalKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyStyle="numStarKeyStyle" />
+        <!-- Wait is a semicolon. -->
+        <Key
+            latin:code="59"
+            latin:keyLabel="@string/label_wait_key"
+            latin:keyLabelOption="followKeyHintLabelRatio|autoXScale" />
+        <Key
+            latin:keyLabel="#"
+            latin:keyStyle="numKeyStyle" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyStyle="numSwitchToNumericKeyStyle" />
+        <Key
+            latin:keyLabel="+"
+            latin:keyStyle="numKeyStyle" />
+        <Key
+            latin:keyStyle="numSpaceKeyStyle" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+</merge>
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 7ae3467..b1cc7ca 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -120,11 +120,6 @@
     /** Whether this key needs to show the "..." popup hint for special purposes */
     private boolean mNeedsSpecialPopupHint;
 
-    // keyWidth enum constants
-    private static final int KEYWIDTH_NOT_ENUM = 0;
-    private static final int KEYWIDTH_FILL_RIGHT = -1;
-    private static final int KEYWIDTH_FILL_BOTH = -2;
-
     // RTL parenthesis character swapping map.
     private static final Map<Integer, Integer> sRtlParenthesisMap = new HashMap<Integer, Integer>();
 
@@ -216,20 +211,9 @@
      */
     public Key(Resources res, KeyboardParams params, KeyboardBuilder.Row row,
             XmlResourceParser parser, KeyStyles keyStyles) {
-        final TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
-                R.styleable.Keyboard);
-        mHeight = (int)KeyboardBuilder.getDimensionOrFraction(keyboardAttr,
-                R.styleable.Keyboard_rowHeight, params.mHeight, row.mRowHeight)
-                - params.mVerticalGap;
-        final float horizontalGap = isSpacer() ? 0
-                : KeyboardBuilder.getDimensionOrFraction(keyboardAttr,
-                        R.styleable.Keyboard_horizontalGap, params.mWidth, params.mHorizontalGap);
+        final float horizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
         mVerticalGap = params.mVerticalGap;
-        final int widthType = KeyboardBuilder.getEnumValue(keyboardAttr,
-                R.styleable.Keyboard_keyWidth, KEYWIDTH_NOT_ENUM);
-        float keyWidth = KeyboardBuilder.getDimensionOrFraction(keyboardAttr,
-                R.styleable.Keyboard_keyWidth, params.mWidth, row.mDefaultKeyWidth);
-        keyboardAttr.recycle();
+        mHeight = row.mRowHeight - mVerticalGap;
 
         final TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
                 R.styleable.Keyboard_Key);
@@ -244,38 +228,16 @@
             style = keyStyles.getEmptyKeyStyle();
         }
 
-        final int keyboardWidth = params.mOccupiedWidth;
-        final float x = row.mCurrentX;
-        float keyXPos = KeyboardBuilder.getDimensionOrFraction(keyAttr,
-                R.styleable.Keyboard_Key_keyXPos, keyboardWidth, x);
-        if (keyXPos < 0) {
-            // If keyXPos is negative, the actual x-coordinate will be keyboardWidth + keyXPos.
-            keyXPos += keyboardWidth;
-            if (keyXPos < x) {
-                // keyXPos shouldn't be less than x because drawable area for this key starts
-                // at x. Or, this key will overlaps the adjacent key on its left hand side.
-                keyXPos = x;
-            }
-        }
-        if (widthType == KEYWIDTH_FILL_RIGHT) {
-            // If keyWidth is zero, the actual key width will be determined to fill out the
-            // area up to the right edge of the keyboard.
-            keyWidth = keyboardWidth - keyXPos;
-        } else if (widthType == KEYWIDTH_FILL_BOTH) {
-            // If keyWidth is negative, the actual key width will be determined to fill out the
-            // area between the nearest key on the left hand side and the right edge of the
-            // keyboard.
-            keyXPos = x;
-            keyWidth = keyboardWidth - keyXPos;
-        }
+        final float keyXPos = row.getKeyX(keyAttr);
+        final float keyWidth = row.getKeyWidth(keyAttr, keyXPos);
 
         // Horizontal gap is divided equally to both sides of the key.
         mX = (int) (keyXPos + horizontalGap / 2);
-        mY = row.mCurrentY;
+        mY = row.getKeyY();
         mWidth = (int) (keyWidth - horizontalGap);
         mHorizontalGap = (int) horizontalGap;
         // Update row to have current x coordinate.
-        row.mCurrentX = keyXPos + keyWidth;
+        row.setXPos(keyXPos + keyWidth);
 
         final CharSequence[] moreKeys = style.getTextArray(keyAttr,
                 R.styleable.Keyboard_Key_moreKeys);
@@ -287,20 +249,20 @@
         } else {
             mMoreKeys = moreKeys;
         }
-        mMaxMoreKeysColumn = style.getInt(keyboardAttr, R.styleable.Keyboard_Key_maxMoreKeysColumn,
-                params.mMaxMiniKeyboardColumn);
+        mMaxMoreKeysColumn = style.getInt(keyAttr,
+                R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMiniKeyboardColumn);
 
-        mBackgroundType = style.getInt(
-                keyAttr, R.styleable.Keyboard_Key_backgroundType, BACKGROUND_TYPE_NORMAL);
+        mBackgroundType = style.getInt(keyAttr,
+                R.styleable.Keyboard_Key_backgroundType, BACKGROUND_TYPE_NORMAL);
         mRepeatable = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_isRepeatable, false);
         mEnabled = style.getBoolean(keyAttr, R.styleable.Keyboard_Key_enabled, true);
         mEdgeFlags = 0;
 
         final KeyboardIconsSet iconsSet = params.mIconsSet;
         mVisualInsetsLeft = (int) KeyboardBuilder.getDimensionOrFraction(keyAttr,
-                R.styleable.Keyboard_Key_visualInsetsLeft, keyboardWidth, 0);
+                R.styleable.Keyboard_Key_visualInsetsLeft, params.mBaseWidth, 0);
         mVisualInsetsRight = (int) KeyboardBuilder.getDimensionOrFraction(keyAttr,
-                R.styleable.Keyboard_Key_visualInsetsRight, keyboardWidth, 0);
+                R.styleable.Keyboard_Key_visualInsetsRight, params.mBaseWidth, 0);
         mPreviewIcon = iconsSet.getIcon(style.getInt(keyAttr,
                 R.styleable.Keyboard_Key_keyIconPreview, KeyboardIconsSet.ICON_UNDEFINED));
         mIcon = iconsSet.getIcon(style.getInt(keyAttr, R.styleable.Keyboard_Key_keyIcon,
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 3a8a1d4..2f11164 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -90,15 +90,12 @@
     /** Total width of the keyboard, including the padding and keys */
     public final int mOccupiedWidth;
 
-    public final int mHeight;
-    public final int mWidth;
-
-    /** Default row height */
-    public final int mDefaultRowHeight;
-
+    /** The padding above the keyboard */
+    public final int mTopPadding;
     /** Default gap between rows */
     public final int mVerticalGap;
 
+    public final int mMostCommonKeyHeight;
     public final int mMostCommonKeyWidth;
 
     /** More keys keyboard template */
@@ -126,14 +123,13 @@
         mId = params.mId;
         mOccupiedHeight = params.mOccupiedHeight;
         mOccupiedWidth = params.mOccupiedWidth;
-        mHeight = params.mHeight;
-        mWidth = params.mWidth;
+        mMostCommonKeyHeight = params.mMostCommonKeyHeight;
         mMostCommonKeyWidth = params.mMostCommonKeyWidth;
         mIsRtlKeyboard = params.mIsRtlKeyboard;
         mMoreKeysTemplate = params.mMoreKeysTemplate;
         mMaxMiniKeyboardColumn = params.mMaxMiniKeyboardColumn;
 
-        mDefaultRowHeight = params.mDefaultRowHeight;
+        mTopPadding = params.mTopPadding;
         mVerticalGap = params.mVerticalGap;
 
         mKeys = Collections.unmodifiableList(params.mKeys);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 5a44460..c94ffd9 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -391,7 +391,7 @@
         mDirtyRect.set(0, 0, getWidth(), getHeight());
         mBufferNeedsUpdate = true;
         invalidateAllKeys();
-        final int keyHeight = keyboard.mDefaultRowHeight - keyboard.mVerticalGap;
+        final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
         mKeyDrawParams.updateKeyHeight(keyHeight);
         mKeyPreviewDrawParams.updateKeyHeight(keyHeight);
     }
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
index ad8056c..c904394 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
@@ -122,9 +122,9 @@
                     mTopRowAdjustment = -1;
                 }
 
-                mWidth = mOccupiedWidth = mNumColumns * mDefaultKeyWidth;
+                mBaseWidth = mOccupiedWidth = mNumColumns * mDefaultKeyWidth;
                 // Need to subtract the bottom row's gutter only.
-                mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight - mVerticalGap
+                mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight - mVerticalGap
                         + mTopPadding + mBottomPadding;
             }
 
@@ -219,7 +219,7 @@
 
             final int keyWidth = getMaxKeyWidth(view, mMoreKeys, mParams.mDefaultKeyWidth);
             mParams.setParameters(mMoreKeys.length, parentKey.mMaxMoreKeysColumn,
-                    keyWidth, parentKeyboard.mDefaultRowHeight, parentKey.mX
+                    keyWidth, parentKeyboard.mMostCommonKeyHeight, parentKey.mX
                             + (mParams.mDefaultKeyWidth - keyWidth) / 2, view.getMeasuredWidth());
         }
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index e39548e..99b917c 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -123,6 +123,9 @@
     private static final String TAG_DEFAULT = "default";
     public static final String TAG_KEY_STYLE = "key-style";
 
+    private static final int DEFAULT_KEYBOARD_COLUMNS = 10;
+    private static final int DEFAULT_KEYBOARD_ROWS = 4;
+
     protected final KP mParams;
     protected final Context mContext;
     protected final Resources mResources;
@@ -141,29 +144,96 @@
      * defines.
      */
     public static class Row {
+        // keyWidth enum constants
+        private static final int KEYWIDTH_NOT_ENUM = 0;
+        private static final int KEYWIDTH_FILL_RIGHT = -1;
+        private static final int KEYWIDTH_FILL_BOTH = -2;
+
+        private final KeyboardParams mParams;
         /** Default width of a key in this row. */
         public final float mDefaultKeyWidth;
         /** Default height of a key in this row. */
         public final int mRowHeight;
 
-        public final int mCurrentY;
+        private final int mCurrentY;
         // Will be updated by {@link Key}'s constructor.
-        public float mCurrentX;
+        private float mCurrentX;
 
         public Row(Resources res, KeyboardParams params, XmlResourceParser parser, int y) {
-            final int keyboardWidth = params.mWidth;
-            final int keyboardHeight = params.mHeight;
-            TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser),
+            mParams = params;
+            TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
                     R.styleable.Keyboard);
-            mDefaultKeyWidth = KeyboardBuilder.getDimensionOrFraction(a,
-                    R.styleable.Keyboard_keyWidth, keyboardWidth, params.mDefaultKeyWidth);
-            mRowHeight = (int)KeyboardBuilder.getDimensionOrFraction(a,
-                    R.styleable.Keyboard_rowHeight, keyboardHeight, params.mDefaultRowHeight);
-            a.recycle();
+            mRowHeight = (int)KeyboardBuilder.getDimensionOrFraction(keyboardAttr,
+                    R.styleable.Keyboard_rowHeight, params.mBaseHeight, params.mDefaultRowHeight);
+            keyboardAttr.recycle();
+            TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
+                    R.styleable.Keyboard_Key);
+            mDefaultKeyWidth = KeyboardBuilder.getDimensionOrFraction(keyboardAttr,
+                    R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth, params.mDefaultKeyWidth);
+            keyAttr.recycle();
 
             mCurrentY = y;
             mCurrentX = 0.0f;
         }
+
+        public void setXPos(float keyXPos) {
+            mCurrentX = keyXPos;
+        }
+
+        public void advanceXPos(float width) {
+            mCurrentX += width;
+        }
+
+        public int getKeyY() {
+            return mCurrentY;
+        }
+
+        public float getKeyX(TypedArray keyAttr) {
+            final int widthType = KeyboardBuilder.getEnumValue(keyAttr,
+                    R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM);
+            if (widthType == KEYWIDTH_FILL_BOTH) {
+                // If keyWidth is fillBoth, the key width should start right after the nearest key
+                // on the left hand side.
+                return mCurrentX;
+            }
+
+            final int keyboardRightEdge = mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding;
+            if (keyAttr.hasValue(R.styleable.Keyboard_Key_keyXPos)) {
+                final float keyXPos = KeyboardBuilder.getDimensionOrFraction(keyAttr,
+                        R.styleable.Keyboard_Key_keyXPos, mParams.mBaseWidth, 0);
+                if (keyXPos < 0) {
+                    // If keyXPos is negative, the actual x-coordinate will be
+                    // keyboardWidth + keyXPos.
+                    // keyXPos shouldn't be less than mCurrentX because drawable area for this key
+                    // starts at mCurrentX. Or, this key will overlaps the adjacent key on its left
+                    // hand side.
+                    return Math.max(keyXPos + keyboardRightEdge, mCurrentX);
+                } else {
+                    return keyXPos + mParams.mHorizontalEdgesPadding;
+                }
+            }
+            return mCurrentX;
+        }
+
+        public float getKeyWidth(TypedArray keyAttr, float keyXPos) {
+            final int widthType = KeyboardBuilder.getEnumValue(keyAttr,
+                    R.styleable.Keyboard_Key_keyWidth, KEYWIDTH_NOT_ENUM);
+            switch (widthType) {
+            case KEYWIDTH_FILL_RIGHT:
+            case KEYWIDTH_FILL_BOTH:
+                final int keyboardRightEdge =
+                        mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding;
+                // If keyWidth is fillRight, the actual key width will be determined to fill out the
+                // area up to the right edge of the keyboard.
+                // If keyWidth is fillBoth, the actual key width will be determined to fill out the
+                // area between the nearest key on the left hand side and the right edge of the
+                // keyboard.
+                return keyboardRightEdge - keyXPos;
+            default: // KEYWIDTH_NOT_ENUM
+                return KeyboardBuilder.getDimensionOrFraction(keyAttr,
+                        R.styleable.Keyboard_Key_keyWidth, mParams.mBaseWidth, mDefaultKeyWidth);
+            }
+        }
     }
 
     public KeyboardBuilder(Context context, KP params) {
@@ -173,8 +243,6 @@
         mDisplayMetrics = res.getDisplayMetrics();
 
         mParams = params;
-        mParams.mHorizontalEdgesPadding = (int)res.getDimension(
-                R.dimen.keyboard_horizontal_edges_padding);
 
         mParams.GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
         mParams.GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
@@ -259,38 +327,42 @@
                 minKeyboardHeight = -(int)getDimensionOrFraction(keyboardAttr,
                         R.styleable.Keyboard_minKeyboardHeight, displayWidth, displayWidth / 2);
             }
+            final KeyboardParams params = mParams;
             // Keyboard height will not exceed maxKeyboardHeight and will not be less than
             // minKeyboardHeight.
-            mParams.mOccupiedHeight = Math.max(
+            params.mOccupiedHeight = Math.max(
                     Math.min(keyboardHeight, maxKeyboardHeight), minKeyboardHeight);
-            mParams.mOccupiedWidth = mParams.mId.mWidth;
-            mParams.mTopPadding = (int)getDimensionOrFraction(keyboardAttr,
-                    R.styleable.Keyboard_keyboardTopPadding, mParams.mOccupiedHeight, 0);
-            mParams.mBottomPadding = (int)getDimensionOrFraction(keyboardAttr,
-                    R.styleable.Keyboard_keyboardBottomPadding, mParams.mOccupiedHeight, 0);
+            params.mOccupiedWidth = params.mId.mWidth;
+            params.mTopPadding = (int)getDimensionOrFraction(keyboardAttr,
+                    R.styleable.Keyboard_keyboardTopPadding, params.mOccupiedHeight, 0);
+            params.mBottomPadding = (int)getDimensionOrFraction(keyboardAttr,
+                    R.styleable.Keyboard_keyboardBottomPadding, params.mOccupiedHeight, 0);
+            params.mHorizontalEdgesPadding = (int)getDimensionOrFraction(keyboardAttr,
+                    R.styleable.Keyboard_keyboardHorizontalEdgesPadding, mParams.mOccupiedWidth, 0);
 
-            final int height = mParams.mOccupiedHeight;
-            final int width = mParams.mOccupiedWidth - mParams.mHorizontalEdgesPadding * 2
-                    - mParams.mHorizontalCenterPadding;
-            mParams.mHeight = height;
-            mParams.mWidth = width;
-            mParams.mDefaultKeyWidth = (int)getDimensionOrFraction(keyboardAttr,
-                    R.styleable.Keyboard_keyWidth, width, width / 10);
-            mParams.mDefaultRowHeight = (int)getDimensionOrFraction(keyboardAttr,
-                    R.styleable.Keyboard_rowHeight, height, height / 4);
-            mParams.mHorizontalGap = (int)getDimensionOrFraction(keyboardAttr,
-                    R.styleable.Keyboard_horizontalGap, width, 0);
-            mParams.mVerticalGap = (int)getDimensionOrFraction(keyboardAttr,
-                    R.styleable.Keyboard_verticalGap, height, 0);
+            params.mBaseWidth = params.mOccupiedWidth - params.mHorizontalEdgesPadding * 2
+                    - params.mHorizontalCenterPadding;
+            params.mDefaultKeyWidth = (int)getDimensionOrFraction(keyAttr,
+                    R.styleable.Keyboard_Key_keyWidth, params.mBaseWidth,
+                    params.mBaseWidth / DEFAULT_KEYBOARD_COLUMNS);
+            params.mHorizontalGap = (int)getDimensionOrFraction(keyboardAttr,
+                    R.styleable.Keyboard_horizontalGap, params.mBaseWidth, 0);
+            params.mVerticalGap = (int)getDimensionOrFraction(keyboardAttr,
+                    R.styleable.Keyboard_verticalGap, params.mOccupiedHeight, 0);
+            params.mBaseHeight = params.mOccupiedHeight - params.mTopPadding
+                    - params.mBottomPadding + params.mVerticalGap;
+            params.mDefaultRowHeight = (int)getDimensionOrFraction(keyboardAttr,
+                    R.styleable.Keyboard_rowHeight, params.mBaseHeight,
+                    params.mBaseHeight / DEFAULT_KEYBOARD_ROWS);
 
-            mParams.mIsRtlKeyboard = keyboardAttr.getBoolean(
+            params.mIsRtlKeyboard = keyboardAttr.getBoolean(
                     R.styleable.Keyboard_isRtlKeyboard, false);
-            mParams.mMoreKeysTemplate = keyboardAttr.getResourceId(
+            params.mMoreKeysTemplate = keyboardAttr.getResourceId(
                     R.styleable.Keyboard_moreKeysTemplate, 0);
-            mParams.mMaxMiniKeyboardColumn = keyAttr.getInt(
+            params.mMaxMiniKeyboardColumn = keyAttr.getInt(
                     R.styleable.Keyboard_Key_maxMoreKeysColumn, 5);
 
-            mParams.mIconsSet.loadIcons(keyboardAttr);
+            params.mIconsSet.loadIcons(keyboardAttr);
         } finally {
             keyAttr.recycle();
             keyboardAttr.recycle();
@@ -667,7 +739,6 @@
     }
 
     private void startRow(Row row) {
-        row.mCurrentX = 0;
         addEdgeSpace(mParams.mHorizontalEdgesPadding, row);
         mCurrentRow = row;
         mLeftEdge = true;
@@ -682,7 +753,7 @@
             mRightEdgeKey = null;
         }
         addEdgeSpace(mParams.mHorizontalEdgesPadding, row);
-        mCurrentY += mCurrentRow.mRowHeight;
+        mCurrentY += row.mRowHeight;
         mCurrentRow = null;
         mTopEdge = false;
     }
@@ -703,7 +774,7 @@
     }
 
     private void addEdgeSpace(float width, Row row) {
-        row.mCurrentX += width;
+        row.advanceXPos(width);
         mLeftEdge = false;
         mRightEdgeKey = null;
     }
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
index 593c3dc..01f9d3b 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardParams.java
@@ -32,11 +32,13 @@
 public class KeyboardParams {
     public KeyboardId mId;
 
+    /** Total height and width of the keyboard, including the paddings and keys */
     public int mOccupiedHeight;
     public int mOccupiedWidth;
 
-    public int mHeight;
-    public int mWidth;
+    /** Base height and width of the keyboard used to calculate rows' or keys' heights and widths */
+    public int mBaseHeight;
+    public int mBaseWidth;
 
     public int mTopPadding;
     public int mBottomPadding;
@@ -62,6 +64,7 @@
     public final Map<Key, Drawable> mUnshiftedIcons = new HashMap<Key, Drawable>();
     public final KeyboardIconsSet mIconsSet = new KeyboardIconsSet();
 
+    public int mMostCommonKeyHeight = 0;
     public int mMostCommonKeyWidth = 0;
 
     protected void clearKeys() {
@@ -89,21 +92,39 @@
         mShiftedIcons.put(key, icon);
     }
 
-    private int mMaxCount = 0;
-    private final Map<Integer, Integer> mHistogram = new HashMap<Integer, Integer>();
+    private int mMaxHeightCount = 0;
+    private int mMaxWidthCount = 0;
+    private final Map<Integer, Integer> mHeightHistogram = new HashMap<Integer, Integer>();
+    private final Map<Integer, Integer> mWidthHistogram = new HashMap<Integer, Integer>();
 
     private void clearHistogram() {
+        mMostCommonKeyHeight = 0;
+        mMaxHeightCount = 0;
+        mHeightHistogram.clear();
+
+        mMaxWidthCount = 0;
         mMostCommonKeyWidth = 0;
-        mMaxCount = 0;
-        mHistogram.clear();
+        mWidthHistogram.clear();
+    }
+
+    private static int updateHistogramCounter(Map<Integer, Integer> histogram, Integer key) {
+        final int count = (histogram.containsKey(key) ? histogram.get(key) : 0) + 1;
+        histogram.put(key, count);
+        return count;
     }
 
     private void updateHistogram(Key key) {
+        final Integer height = key.mHeight + key.mVerticalGap;
+        final int heightCount = updateHistogramCounter(mHeightHistogram, height);
+        if (heightCount > mMaxHeightCount) {
+            mMaxHeightCount = heightCount;
+            mMostCommonKeyHeight = height;
+        }
+
         final Integer width = key.mWidth + key.mHorizontalGap;
-        final int count = (mHistogram.containsKey(width) ? mHistogram.get(width) : 0) + 1;
-        mHistogram.put(width, count);
-        if (count > mMaxCount) {
-            mMaxCount = count;
+        final int widthCount = updateHistogramCounter(mWidthHistogram, width);
+        if (widthCount > mMaxWidthCount) {
+            mMaxWidthCount = widthCount;
             mMostCommonKeyWidth = width;
         }
     }
diff --git a/java/src/com/android/inputmethod/latin/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/MoreSuggestions.java
index 24011c4..1afa072 100644
--- a/java/src/com/android/inputmethod/latin/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/MoreSuggestions.java
@@ -92,8 +92,9 @@
                 }
                 mNumColumnsInRow[row] = pos - rowStartPos;
                 mNumRows = row + 1;
-                mWidth = mOccupiedWidth = Math.max(minWidth, calcurateMaxRowWidth(fromPos, pos));
-                mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
+                mBaseWidth = mOccupiedWidth = Math.max(
+                        minWidth, calcurateMaxRowWidth(fromPos, pos));
+                mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
                 return pos - fromPos;
             }
 
@@ -149,7 +150,7 @@
 
             public int getWidth(int pos) {
                 final int numColumnInRow = getNumColumnInRow(pos);
-                return (mWidth - mDividerWidth * (numColumnInRow - 1)) / numColumnInRow;
+                return (mOccupiedWidth - mDividerWidth * (numColumnInRow - 1)) / numColumnInRow;
             }
 
             public int getFlags(int pos) {
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 915c405..77fbe3e 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -334,10 +334,19 @@
                 final String text = textInfo.getText();
 
                 if (shouldFilterOut(text)) {
-                    final DictAndProximity dictInfo = mDictionaryPool.takeOrGetNull();
-                    if (null == dictInfo) return NOT_IN_DICT_EMPTY_SUGGESTIONS;
-                    return dictInfo.mDictionary.isValidWord(text) ? IN_DICT_EMPTY_SUGGESTIONS
-                            : NOT_IN_DICT_EMPTY_SUGGESTIONS;
+                    DictAndProximity dictInfo = null;
+                    try {
+                        dictInfo = mDictionaryPool.takeOrGetNull();
+                        if (null == dictInfo) return NOT_IN_DICT_EMPTY_SUGGESTIONS;
+                        return dictInfo.mDictionary.isValidWord(text) ? IN_DICT_EMPTY_SUGGESTIONS
+                                : NOT_IN_DICT_EMPTY_SUGGESTIONS;
+                    } finally {
+                        if (null != dictInfo) {
+                            if (!mDictionaryPool.offer(dictInfo)) {
+                                Log.e(TAG, "Can't re-insert a dictionary into its pool");
+                            }
+                        }
+                    }
                 }
 
                 final SuggestionsGatherer suggestionsGatherer =
@@ -361,19 +370,25 @@
 
                 final int capitalizeType = getCapitalizationType(text);
                 boolean isInDict = true;
-                final DictAndProximity dictInfo = mDictionaryPool.takeOrGetNull();
-                if (null == dictInfo) return NOT_IN_DICT_EMPTY_SUGGESTIONS;
-                dictInfo.mDictionary.getWords(composer, suggestionsGatherer,
-                        dictInfo.mProximityInfo);
-                isInDict = dictInfo.mDictionary.isValidWord(text);
-                if (!isInDict && CAPITALIZE_NONE != capitalizeType) {
-                    // We want to test the word again if it's all caps or first caps only.
-                    // If it's fully down, we already tested it, if it's mixed case, we don't
-                    // want to test a lowercase version of it.
-                    isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale));
-                }
-                if (!mDictionaryPool.offer(dictInfo)) {
-                    Log.e(TAG, "Can't re-insert a dictionary into its pool");
+                DictAndProximity dictInfo = null;
+                try {
+                    dictInfo = mDictionaryPool.takeOrGetNull();
+                    if (null == dictInfo) return NOT_IN_DICT_EMPTY_SUGGESTIONS;
+                    dictInfo.mDictionary.getWords(composer, suggestionsGatherer,
+                            dictInfo.mProximityInfo);
+                    isInDict = dictInfo.mDictionary.isValidWord(text);
+                    if (!isInDict && CAPITALIZE_NONE != capitalizeType) {
+                        // We want to test the word again if it's all caps or first caps only.
+                        // If it's fully down, we already tested it, if it's mixed case, we don't
+                        // want to test a lowercase version of it.
+                        isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale));
+                    }
+                } finally {
+                    if (null != dictInfo) {
+                        if (!mDictionaryPool.offer(dictInfo)) {
+                            Log.e(TAG, "Can't re-insert a dictionary into its pool");
+                        }
+                    }
                 }
 
                 final SuggestionsGatherer.Result result = suggestionsGatherer.getResults(text,