diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal.9.png
index 0c4820b34c55f88b8030693a2431cd553f7b9061..01fc8ca780342b16e22a395f702af499a2eb21b3 100644
Binary files a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal.9.png and b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal.9.png differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off.9.png
index 5a20da1dbb60d404790a46b704f8fccccaf995b4..af4017e2c6f7e8ec7b98fb9641d81b25e9bc138f 100644
Binary files a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off.9.png and b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off.9.png differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on.9.png
index 4ec703d6ceac885c2895b9b0f1919d615498cc90..4c35aca95dd88e92c4bc76673d2509917b0383c3 100644
Binary files a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on.9.png and b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on.9.png differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed.9.png
index 93322d2e279dc2efe8de56c94f008f6077520cb0..174f3452c684ba190fc3aa012a825ba1dd3c1e06 100644
Binary files a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed.9.png and b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed.9.png differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off.9.png
index 5a9c722cefb461a02dced268bf12e418a38f0e54..1fcbd9a887085ef01807d36e6309f95457beab4a 100644
Binary files a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off.9.png and b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off.9.png differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on.9.png
index 99b6cb17068737696c287a2f12f821afc8bb815f..072753f37dfc12ec6c24858aae888bbd9f58d426 100644
Binary files a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on.9.png and b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on.9.png differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_light_normal.9.png b/java/res/drawable-hdpi/btn_keyboard_key_light_normal.9.png
index 7dc59bf82268abee3656297857d3e43da52115e3..1ad746053df532f5b8fa9f87c5558456dc2bd725 100644
Binary files a/java/res/drawable-hdpi/btn_keyboard_key_light_normal.9.png and b/java/res/drawable-hdpi/btn_keyboard_key_light_normal.9.png differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_light_pressed.9.png b/java/res/drawable-hdpi/btn_keyboard_key_light_pressed.9.png
index c150341e364f8a3a291a90e8f9c2767920775dbe..ccd59d5fa6e3b25756993299aac599a65e636685 100644
Binary files a/java/res/drawable-hdpi/btn_keyboard_key_light_pressed.9.png and b/java/res/drawable-hdpi/btn_keyboard_key_light_pressed.9.png differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal.9.png
index 53fe9c97d4ab0b350bbefd61883ce63cc2a4e489..4e337fa0836e56404e74b1c9e250e9088dfc1794 100644
Binary files a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal.9.png and b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal.9.png differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off.9.png
index 649ef9773b893b964913e1b3aae6d734bffa72df..fe18497d82a1c7d9c1138230ffdd14c24b59ecba 100644
Binary files a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off.9.png and b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off.9.png differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on.9.png
index 93f7d87c2b238061186cc2a4a93cda10a4ecb3a3..00aab3d5af5cb97ad0bf3989b2a6f027887a3b40 100644
Binary files a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on.9.png and b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on.9.png differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed.9.png
index 8560b3ba70053c37e19ef7beb7d11e00ba082b6a..ac0bfd3c1e754d21c87d5e6f7e9ba1e93153dbe8 100644
Binary files a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed.9.png and b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed.9.png differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off.9.png
index 778abaf2491f0f97dadb4d71c3f50790c225f683..ea2f357895aa2c321234be50fe45c019bd8eb31e 100644
Binary files a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off.9.png and b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off.9.png differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on.9.png
index 2a23945e503eec0a6cb07ab6880123bea34d3d96..6195ac0d4f52af9ae965d5a31e1ad9b88f1e3b84 100644
Binary files a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on.9.png and b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on.9.png differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_normal.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_normal.9.png
index 6af2d8d0c2ee2ef405fa05dc3757b2541165fd7b..50cd06ae3685154ecdf450fe3055e3bc4adf5035 100644
Binary files a/java/res/drawable-mdpi/btn_keyboard_key_light_normal.9.png and b/java/res/drawable-mdpi/btn_keyboard_key_light_normal.9.png differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_pressed.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_pressed.9.png
index fdaf69966a8e87e7781ce70303605907e4c549b7..7ce52f0f585605e632f2e9810677c62098b77419 100644
Binary files a/java/res/drawable-mdpi/btn_keyboard_key_light_pressed.9.png and b/java/res/drawable-mdpi/btn_keyboard_key_light_pressed.9.png differ
diff --git a/java/res/layout/input_gingerbread.xml b/java/res/layout/input_gingerbread.xml
index 8f59cae216235b2f7511a8aef85dcc64b09325df..73cf0a3fac35364b8b5ee19cd8ae85da080b606e 100644
--- a/java/res/layout/input_gingerbread.xml
+++ b/java/res/layout/input_gingerbread.xml
@@ -25,6 +25,7 @@
         android:layout_alignParentBottom="true"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:paddingBottom="@dimen/keyboard_bottom_padding"
         android:background="@drawable/keyboard_dark_background"
         android:textStyle="bold"
 
diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
index 1396bff9bcce2dfcdaef23329b7a0eec3030eabb..043f4b3632ff220141d3be476044d3875450356c 100644
--- a/java/res/values-land/dimens.xml
+++ b/java/res/values-land/dimens.xml
@@ -19,13 +19,17 @@
 -->
 
 <resources>
-    <dimen name="key_height">47dip</dimen>
+    <!-- key_height + key_bottom_gap = popup_key_height -->
+    <dimen name="key_height">0.250in</dimen>
+    <dimen name="key_bottom_gap">0.020in</dimen>
+    <dimen name="popup_key_height">0.270in</dimen>
+    <dimen name="keyboard_bottom_padding">0.0in</dimen>
     <dimen name="candidate_strip_height">38dip</dimen>
     <dimen name="candidate_strip_fading_edge_length">63dip</dimen>
     <dimen name="spacebar_vertical_correction">2dip</dimen>
     <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
-    <!-- key_height x 1.7 -->
-    <dimen name="mini_keyboard_slide_allowance">79.9dip</dimen>
-    <!-- -key_height x 1.0 -->
-    <dimen name="mini_keyboard_vertical_correction">-47dip</dimen>
+    <!-- popup_key_height x 1.7 -->
+    <dimen name="mini_keyboard_slide_allowance">0.459in</dimen>
+    <!-- popup_key_height x 1.0 -->
+    <dimen name="mini_keyboard_vertical_correction">-0.270in</dimen>
 </resources>
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 1378be72cdc15b4db25fb32044c032cb589d7a06..c00c56a893b61b8ef8f508fa8deacc38163e31e4 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -19,7 +19,11 @@
 -->
 
 <resources>
-    <dimen name="key_height">54dip</dimen>
+    <!-- key_height + key_bottom_gap = popup_key_height -->
+    <dimen name="key_height">0.290in</dimen>
+    <dimen name="key_bottom_gap">0.035in</dimen>
+    <dimen name="popup_key_height">0.325in</dimen>
+    <dimen name="keyboard_bottom_padding">0.06in</dimen>
     <dimen name="bubble_pointer_offset">22dip</dimen>
     <dimen name="candidate_strip_height">42dip</dimen>
     <dimen name="candidate_strip_fading_edge_length">63dip</dimen>
@@ -27,18 +31,20 @@
     <!-- If the screen height in landscape is larger than the below value, then the keyboard
          will not go into extract (fullscreen) mode. -->
     <dimen name="max_height_for_fullscreen">2.5in</dimen>
-    <dimen name="key_text_size">22sp</dimen>
-    <dimen name="key_label_text_size">14sp</dimen>
-    <dimen name="key_preview_offset">0dip</dimen>
-    <dimen name="key_preview_height">80dip</dimen>
+    <dimen name="key_text_size">0.13in</dimen>
+    <dimen name="key_label_text_size">0.083in</dimen>
+    <dimen name="key_preview_text_size_large">0.236in</dimen>
+    <dimen name="key_preview_offset">0.000in</dimen>
+    <!-- key_height x 1.6 -->
+    <dimen name="key_preview_height">0.464in</dimen>
     <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
-    <!-- key_height x 1.7 -->
-    <dimen name="mini_keyboard_slide_allowance">91.8dip</dimen>
-    <!-- -key_height x 1.0 -->
-    <dimen name="mini_keyboard_vertical_correction">-54dip</dimen>
+    <!-- popup_key_height x 1.7 -->
+    <dimen name="mini_keyboard_slide_allowance">0.553in</dimen>
+    <!-- popup_key_height x 1.0 -->
+    <dimen name="mini_keyboard_vertical_correction">-0.325in</dimen>
     <dimen name="key_hysteresis_distance">0.05in</dimen>
     <!-- We use "inch", not "dip" because this value tries dealing with physical distance related
          to user's finger. -->
-    <dimen name="keyboard_vertical_correction">-0.06in</dimen>
+    <dimen name="keyboard_vertical_correction">-0.05in</dimen>
     <dimen name="candidate_min_touchable_width">0.3in</dimen>
 </resources>
diff --git a/java/res/xml-da/kbd_qwerty.xml b/java/res/xml-da/kbd_qwerty.xml
index 084795463eb7b2485710bf02f7807d88594172b5..6e2e692083870c4c141be4368525fc54141ef5a9 100644
--- a/java/res/xml-da/kbd_qwerty.xml
+++ b/java/res/xml-da/kbd_qwerty.xml
@@ -28,10 +28,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="9.09%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="q"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-da/kbd_qwerty_black.xml b/java/res/xml-da/kbd_qwerty_black.xml
index 9a64e869d550f156aaf06fa391aa9fa14fed2f1c..36656ed24e366a8c55ec9b75cf0f6eb820462fbe 100644
--- a/java/res/xml-da/kbd_qwerty_black.xml
+++ b/java/res/xml-da/kbd_qwerty_black.xml
@@ -28,10 +28,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="9.09%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="q"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-de/kbd_qwerty.xml b/java/res/xml-de/kbd_qwerty.xml
index b60c50dd6bf6abda54ac38e1f11d71e3c48c1dac..e74f137e5e4b17fdbc3b6cd11066eb25806d4795 100644
--- a/java/res/xml-de/kbd_qwerty.xml
+++ b/java/res/xml-de/kbd_qwerty.xml
@@ -22,10 +22,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="q"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-de/kbd_qwerty_black.xml b/java/res/xml-de/kbd_qwerty_black.xml
index 5cca5a62225114fa00e3386fad4b8b20fde8987b..2c0d6d59d3235ad58125a572c9124fbabd9674a9 100644
--- a/java/res/xml-de/kbd_qwerty_black.xml
+++ b/java/res/xml-de/kbd_qwerty_black.xml
@@ -22,10 +22,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="q"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-fr/kbd_qwerty.xml b/java/res/xml-fr/kbd_qwerty.xml
index ab78b37bb4761559d872d12d2b3ed6a6b4634505..bded3e3b3f9d2b9bc3f5ecd48596641025c81b85 100644
--- a/java/res/xml-fr/kbd_qwerty.xml
+++ b/java/res/xml-fr/kbd_qwerty.xml
@@ -22,10 +22,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="a"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-fr/kbd_qwerty_black.xml b/java/res/xml-fr/kbd_qwerty_black.xml
index 97b55dccd29b24e0862afbc44975981b9461c944..679d940f8498cf2b0623e16e0c8d84fa3902da25 100644
--- a/java/res/xml-fr/kbd_qwerty_black.xml
+++ b/java/res/xml-fr/kbd_qwerty_black.xml
@@ -22,10 +22,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="a"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-iw/kbd_qwerty.xml b/java/res/xml-iw/kbd_qwerty.xml
index a48c849d07c4d876c27e3ba4c716ec9fa8620ad4..0ad2ca3c32252843f986ef5eeb8322ad1102056a 100644
--- a/java/res/xml-iw/kbd_qwerty.xml
+++ b/java/res/xml-iw/kbd_qwerty.xml
@@ -22,10 +22,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="ק"
             android:horizontalGap="5%p"
diff --git a/java/res/xml-iw/kbd_qwerty_black.xml b/java/res/xml-iw/kbd_qwerty_black.xml
index a72b036f40bcfdffe5c39ec596a5fefc5aabf2d1..10ca0fc12f4e15d489765a6fd6c9fb0246b348a2 100644
--- a/java/res/xml-iw/kbd_qwerty_black.xml
+++ b/java/res/xml-iw/kbd_qwerty_black.xml
@@ -22,10 +22,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="ק"
             android:horizontalGap="5%p"
diff --git a/java/res/xml-nb/kbd_qwerty.xml b/java/res/xml-nb/kbd_qwerty.xml
index 7e16106845e22316a2443a9db42e49d928448f3a..8377bbf3f271e0837ddb6dac86685cb7bb032969 100644
--- a/java/res/xml-nb/kbd_qwerty.xml
+++ b/java/res/xml-nb/kbd_qwerty.xml
@@ -28,10 +28,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="9.09%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="q"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-nb/kbd_qwerty_black.xml b/java/res/xml-nb/kbd_qwerty_black.xml
index f6a034ee9f52f80f75e69e1830473bb3de090217..ab14984884c786c89de24910b5103266b25082f9 100644
--- a/java/res/xml-nb/kbd_qwerty_black.xml
+++ b/java/res/xml-nb/kbd_qwerty_black.xml
@@ -28,10 +28,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="9.09%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="q"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-ru/kbd_qwerty.xml b/java/res/xml-ru/kbd_qwerty.xml
index 9f16b9b7ddd2e53847dfa7044b259bdeced07c2a..d40ccef10aa7f33acc9e9b2c2a37f8ded243b6fb 100644
--- a/java/res/xml-ru/kbd_qwerty.xml
+++ b/java/res/xml-ru/kbd_qwerty.xml
@@ -22,10 +22,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="9.09%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="й"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-ru/kbd_qwerty_black.xml b/java/res/xml-ru/kbd_qwerty_black.xml
index 73008befd6f848e63f10dd95ea6be225efb10b93..cc71b0812d16cf156b6de8f7f6d50c57bfc36f4d 100644
--- a/java/res/xml-ru/kbd_qwerty_black.xml
+++ b/java/res/xml-ru/kbd_qwerty_black.xml
@@ -22,10 +22,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="9.09%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="й"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-sr/kbd_qwerty.xml b/java/res/xml-sr/kbd_qwerty.xml
index c671166d1bc290bfe7cf9362f49366675470e421..835f8c166cbfeb8ac57783a94af48e478827eb2c 100644
--- a/java/res/xml-sr/kbd_qwerty.xml
+++ b/java/res/xml-sr/kbd_qwerty.xml
@@ -23,10 +23,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="9.09%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="Ñ™"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-sr/kbd_qwerty_black.xml b/java/res/xml-sr/kbd_qwerty_black.xml
index 5e5bceec0011e1c34c7df1c0b50e25106af7a861..76a9e55c1086d5a2628ea5e289f219bd1c1124f9 100644
--- a/java/res/xml-sr/kbd_qwerty_black.xml
+++ b/java/res/xml-sr/kbd_qwerty_black.xml
@@ -23,10 +23,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="9.09%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="Ñ™"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-sv/kbd_qwerty.xml b/java/res/xml-sv/kbd_qwerty.xml
index 44117fc1f6287188294441ef0e1b256332a524e6..f88bd3c39035715ec40f58fe004647d43cdeb936 100644
--- a/java/res/xml-sv/kbd_qwerty.xml
+++ b/java/res/xml-sv/kbd_qwerty.xml
@@ -30,10 +30,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="9.09%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="q"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml-sv/kbd_qwerty_black.xml b/java/res/xml-sv/kbd_qwerty_black.xml
index 13ed3d1bf16504261ee91cdbb8714d6a03216958..8493237b242dd9a9ef9ebd9523faa4c30ce80449 100644
--- a/java/res/xml-sv/kbd_qwerty_black.xml
+++ b/java/res/xml-sv/kbd_qwerty_black.xml
@@ -30,10 +30,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="9.09%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="q"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml/kbd_phone.xml b/java/res/xml/kbd_phone.xml
index 0a01fa00ec4eaae51653cbf3915841e8a3f639d6..10774c6669565ded414c2466a44184d56c7da0a1 100644
--- a/java/res/xml/kbd_phone.xml
+++ b/java/res/xml/kbd_phone.xml
@@ -22,7 +22,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="26.67%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
     <Row
diff --git a/java/res/xml/kbd_phone_black.xml b/java/res/xml/kbd_phone_black.xml
index 7a956b796c8993c5bbc0fce200eab6453d81e6e1..5afa9a19481ec0ccd37969fbdbf96ee34154e1b2 100644
--- a/java/res/xml/kbd_phone_black.xml
+++ b/java/res/xml/kbd_phone_black.xml
@@ -22,7 +22,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="26.67%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
     <Row
diff --git a/java/res/xml/kbd_phone_symbols.xml b/java/res/xml/kbd_phone_symbols.xml
index 2dc93c15ffabaedcd693d04547089093ec9ee71b..4c928a8d8dc6799330098e257a30ce8b7e5a9964 100644
--- a/java/res/xml/kbd_phone_symbols.xml
+++ b/java/res/xml/kbd_phone_symbols.xml
@@ -22,7 +22,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="26.67%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
     <Row
diff --git a/java/res/xml/kbd_phone_symbols_black.xml b/java/res/xml/kbd_phone_symbols_black.xml
index 5bc628965c39da212c7f8fdeb31136ffe35ad4f9..4d686e1457814914afcff0c2d464164d351a3659 100644
--- a/java/res/xml/kbd_phone_symbols_black.xml
+++ b/java/res/xml/kbd_phone_symbols_black.xml
@@ -22,7 +22,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="26.67%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
     <Row
diff --git a/java/res/xml/kbd_popup_narrow_template.xml b/java/res/xml/kbd_popup_narrow_template.xml
index ed3b1300310b96e206843f9d567d5b83cc6825bf..23c686e8bc4670c60ed48cc40a0eca549fc32f08 100644
--- a/java/res/xml/kbd_popup_narrow_template.xml
+++ b/java/res/xml/kbd_popup_narrow_template.xml
@@ -22,6 +22,6 @@
     android:keyWidth="9.45%p"
     android:horizontalGap="0px"
     android:verticalGap="0px"
-    android:keyHeight="@dimen/key_height"
+    android:keyHeight="@dimen/popup_key_height"
     >
 </Keyboard>
diff --git a/java/res/xml/kbd_popup_template.xml b/java/res/xml/kbd_popup_template.xml
index aca46930fa35763fcfa9bdf0abd698af341a0905..a287be1fdc1caa395860ac5902dc67bf6399de35 100644
--- a/java/res/xml/kbd_popup_template.xml
+++ b/java/res/xml/kbd_popup_template.xml
@@ -22,6 +22,6 @@
     android:keyWidth="10%p"
     android:horizontalGap="0px"
     android:verticalGap="0px"
-    android:keyHeight="@dimen/key_height"
+    android:keyHeight="@dimen/popup_key_height"
     >
 </Keyboard>
diff --git a/java/res/xml/kbd_qwerty.xml b/java/res/xml/kbd_qwerty.xml
index c6113abf797710d5b6b8f098ef79deb3991c56ba..a2c9b2b8ea2f2f0754e87b4899aa0bbf46d454da 100644
--- a/java/res/xml/kbd_qwerty.xml
+++ b/java/res/xml/kbd_qwerty.xml
@@ -22,10 +22,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="q"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml/kbd_qwerty_black.xml b/java/res/xml/kbd_qwerty_black.xml
index 33cec94746b20de688d8a3f07d047cebbd302540..d9943a93fb04c6c276e1ddbf96070bbdafa35815 100644
--- a/java/res/xml/kbd_qwerty_black.xml
+++ b/java/res/xml/kbd_qwerty_black.xml
@@ -22,10 +22,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
-    <Row>
+    <Row
+        android:rowEdgeFlags="top"
+    >
         <Key
             android:keyLabel="q"
             android:popupKeyboard="@xml/kbd_popup_template"
diff --git a/java/res/xml/kbd_symbols.xml b/java/res/xml/kbd_symbols.xml
index cb8b3b38f7766a18cec23569569253337fb55f92..dfc5bd0ec75b2675119a9cb9a340af34bf2054ac 100644
--- a/java/res/xml/kbd_symbols.xml
+++ b/java/res/xml/kbd_symbols.xml
@@ -22,7 +22,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
     <Row
diff --git a/java/res/xml/kbd_symbols_black.xml b/java/res/xml/kbd_symbols_black.xml
index bfb1646f460a0be84b0ac4a665d9aa0b79cd5395..add7f9fb22db48739e6c1e289791f99dbeefff4c 100644
--- a/java/res/xml/kbd_symbols_black.xml
+++ b/java/res/xml/kbd_symbols_black.xml
@@ -22,7 +22,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
     <Row
diff --git a/java/res/xml/kbd_symbols_shift.xml b/java/res/xml/kbd_symbols_shift.xml
index 21cbb7132893172898ef20bb50a3fd1a93805b8b..9bee2206998009892951756a76c823a2755e6d38 100644
--- a/java/res/xml/kbd_symbols_shift.xml
+++ b/java/res/xml/kbd_symbols_shift.xml
@@ -22,7 +22,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
     <Row
diff --git a/java/res/xml/kbd_symbols_shift_black.xml b/java/res/xml/kbd_symbols_shift_black.xml
index d5d49ce0d7d324d4483ba9c0b5fb312a209930aa..52b67c3de25002ad21f167945901466d6135d5bc 100644
--- a/java/res/xml/kbd_symbols_shift_black.xml
+++ b/java/res/xml/kbd_symbols_shift_black.xml
@@ -22,7 +22,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:keyWidth="10%p"
     android:horizontalGap="0px"
-    android:verticalGap="0px"
+    android:verticalGap="@dimen/key_bottom_gap"
     android:keyHeight="@dimen/key_height"
 >
     <Row
diff --git a/java/res/xml/popup_comma.xml b/java/res/xml/popup_comma.xml
index 540dc9615b16e49053dafb9a12217edf14b0555e..7666f4b622b6cf2b17dda1be81cdb0a8c3af5627 100644
--- a/java/res/xml/popup_comma.xml
+++ b/java/res/xml/popup_comma.xml
@@ -23,7 +23,7 @@
     android:keyWidth="10%p"
     android:horizontalGap="0px"
     android:verticalGap="0px"
-    android:keyHeight="@dimen/key_height"
+    android:keyHeight="@dimen/popup_key_height"
 >
     <Row
         android:rowEdgeFlags="top|bottom"
diff --git a/java/res/xml/popup_domains.xml b/java/res/xml/popup_domains.xml
index 0f7d97691bbcdb7f94842a3eb9aa7081dbcf5038..4e9789ff785c8ffef36017aacd2e613127d13121 100644
--- a/java/res/xml/popup_domains.xml
+++ b/java/res/xml/popup_domains.xml
@@ -23,7 +23,7 @@
     android:keyWidth="15%p"
     android:horizontalGap="0px"
     android:verticalGap="0px"
-    android:keyHeight="@dimen/key_height"
+    android:keyHeight="@dimen/popup_key_height"
 >
     <Row
         android:rowEdgeFlags="top|bottom"
diff --git a/java/res/xml/popup_mic.xml b/java/res/xml/popup_mic.xml
index f3cc63817e21842e86427a775fde016079636960..5bbd7dfa5dfe4f0d7cc94c0ebc5ff1c06d336466 100644
--- a/java/res/xml/popup_mic.xml
+++ b/java/res/xml/popup_mic.xml
@@ -23,7 +23,7 @@
     android:keyWidth="10%p"
     android:horizontalGap="0px"
     android:verticalGap="0px"
-    android:keyHeight="@dimen/key_height"
+    android:keyHeight="@dimen/popup_key_height"
 >
     <Row
         android:rowEdgeFlags="top|bottom"
diff --git a/java/res/xml/popup_punctuation.xml b/java/res/xml/popup_punctuation.xml
index ee1feabecde8cae139502dae3b2458de94d59fd4..c429e38bcd6e52d889799a12b3b7ffcefb0e35f7 100644
--- a/java/res/xml/popup_punctuation.xml
+++ b/java/res/xml/popup_punctuation.xml
@@ -23,7 +23,7 @@
     android:keyWidth="10%p"
     android:horizontalGap="0px"
     android:verticalGap="0px"
-    android:keyHeight="@dimen/key_height"
+    android:keyHeight="@dimen/popup_key_height"
 >
     <Row
         android:rowEdgeFlags="top"
diff --git a/java/res/xml/popup_smileys.xml b/java/res/xml/popup_smileys.xml
index 3b556da77e6b43a1304e1838f86e7e44e1150dee..1a14e1df1404383a4a4b5d95fd8c55098d07d818 100644
--- a/java/res/xml/popup_smileys.xml
+++ b/java/res/xml/popup_smileys.xml
@@ -23,7 +23,7 @@
     android:keyWidth="15%p"
     android:horizontalGap="0px"
     android:verticalGap="0px"
-    android:keyHeight="@dimen/key_height"
+    android:keyHeight="@dimen/popup_key_height"
 >
     <Row
         android:rowEdgeFlags="top"
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboard.java b/java/src/com/android/inputmethod/latin/LatinKeyboard.java
index 43d0a7beb310fc2cbeabd78dbb6d385e8db84c26..f0d5ef60aefc002cc9516406c0fa7455b6bba306 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboard.java
+++ b/java/src/com/android/inputmethod/latin/LatinKeyboard.java
@@ -90,6 +90,10 @@ public class LatinKeyboard extends Keyboard {
     // TODO: generalize for any keyboardId
     private boolean mIsBlackSym;
 
+    // TODO: remove this attribute when either Keyboard.mDefaultVerticalGap or Key.parent becomes
+    // non-private.
+    private final int mVerticalGap;
+
     private static final int SHIFT_OFF = 0;
     private static final int SHIFT_ON = 1;
     private static final int SHIFT_LOCKED = 2;
@@ -120,9 +124,7 @@ public class LatinKeyboard extends Keyboard {
         mRes = res;
         mShiftLockIcon = res.getDrawable(R.drawable.sym_keyboard_shift_locked);
         mShiftLockPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_shift_locked);
-        mShiftLockPreviewIcon.setBounds(0, 0, 
-                mShiftLockPreviewIcon.getIntrinsicWidth(),
-                mShiftLockPreviewIcon.getIntrinsicHeight());
+        setDefaultBounds(mShiftLockPreviewIcon);
         mSpaceIcon = res.getDrawable(R.drawable.sym_keyboard_space);
         mSpaceAutoCompletionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led);
         mSpacePreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_space);
@@ -140,6 +142,8 @@ public class LatinKeyboard extends Keyboard {
                 || xmlLayoutResId == R.xml.kbd_qwerty_black;
         mSpaceKeyIndex = indexOf(LatinIME.KEYCODE_SPACE);
         initializeNumberHintResources(context);
+        // TODO remove this initialization after cleanup
+        mVerticalGap = super.getVerticalGap();
     }
 
     private void initializeNumberHintResources(Context context) {
@@ -196,6 +200,7 @@ public class LatinKeyboard extends Keyboard {
     }
 
     void setImeOptions(Resources res, int mode, int options) {
+        // TODO should clean up this method
         if (mEnterKey != null) {
             // Reset some of the rarely used attributes.
             mEnterKey.popupCharacters = null;
@@ -247,9 +252,7 @@ public class LatinKeyboard extends Keyboard {
             }
             // Set the initial size of the preview icon
             if (mEnterKey.iconPreview != null) {
-                mEnterKey.iconPreview.setBounds(0, 0, 
-                        mEnterKey.iconPreview.getIntrinsicWidth(),
-                        mEnterKey.iconPreview.getIntrinsicHeight());
+                setDefaultBounds(mEnterKey.iconPreview);
             }
         }
     }
@@ -736,6 +739,7 @@ public class LatinKeyboard extends Keyboard {
         return textSize;
     }
 
+    // TODO LatinKey could be static class
     class LatinKey extends Keyboard.Key {
 
         // functional normal state (with properties)
@@ -784,6 +788,8 @@ public class LatinKeyboard extends Keyboard {
          */
         @Override
         public boolean isInside(int x, int y) {
+            // TODO This should be done by parent.isInside(this, x, y)
+            // if Key.parent were protected.
             boolean result = LatinKeyboard.this.isInside(this, x, y);
             return result;
         }
@@ -803,6 +809,15 @@ public class LatinKeyboard extends Keyboard {
             }
             return super.getCurrentDrawableState();
         }
+
+        @Override
+        public int squaredDistanceFrom(int x, int y) {
+            // We should count vertical gap between rows to calculate the center of this Key.
+            final int verticalGap = LatinKeyboard.this.mVerticalGap;
+            final int xDist = this.x + width / 2 - x;
+            final int yDist = this.y + (height + verticalGap) / 2 - y;
+            return xDist * xDist + yDist * yDist;
+        }
     }
 
     /**
@@ -828,8 +843,7 @@ public class LatinKeyboard extends Keyboard {
 
         public SlidingLocaleDrawable(Drawable background, int width, int height) {
             mBackground = background;
-            mBackground.setBounds(0, 0,
-                    mBackground.getIntrinsicWidth(), mBackground.getIntrinsicHeight());
+            setDefaultBounds(mBackground);
             mWidth = width;
             mHeight = height;
             mTextPaint = new TextPaint();
@@ -887,7 +901,7 @@ public class LatinKeyboard extends Keyboard {
                 canvas.drawText(mNextLanguage, diff - width / 2, baseline, paint);
                 canvas.drawText(mPrevLanguage, diff + width + width / 2, baseline, paint);
 
-                lArrow.setBounds(0, 0, lArrow.getIntrinsicWidth(), lArrow.getIntrinsicHeight());
+                setDefaultBounds(lArrow);
                 rArrow.setBounds(width - rArrow.getIntrinsicWidth(), 0, width,
                         rArrow.getIntrinsicHeight());
                 lArrow.draw(canvas);
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
index 0989dbdd34786e54b0ba39866ad1d5979615745c..9ff7b9aef0952a2e7dd45c53e4456fadfbd944e1 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
+++ b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
@@ -47,6 +47,7 @@ import android.widget.PopupWindow;
 import android.widget.TextView;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.WeakHashMap;
@@ -158,6 +159,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
     // Miscellaneous constants
     /* package */ static final int NOT_A_KEY = -1;
     private static final int[] LONG_PRESSABLE_STATE_SET = { android.R.attr.state_long_pressable };
+    private static final int NUMBER_HINT_VERTICAL_ADJUSTMENT_PIXEL = -1;
 
     // XML attribute
     private int mKeyTextSize;
@@ -178,6 +180,8 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
     // Main keyboard
     private Keyboard mKeyboard;
     private Key[] mKeys;
+    // TODO this attribute should be gotten from Keyboard.
+    private int mKeyboardVerticalGap;
 
     // Key preview popup
     private TextView mPreviewText;
@@ -237,6 +241,11 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
     private final Paint mPaint;
     private final Rect mPadding;
     private final Rect mClipRegion = new Rect(0, 0, 0, 0);
+    // This map caches key label text height in pixel as value and key label text size as map key.
+    private final HashMap<Integer, Integer> mTextHeightCache = new HashMap<Integer, Integer>();
+    // Distance from horizontal center of the key, proportional to key label text height.
+    private final float KEY_LABEL_VERTICAL_ADJUSTMENT_FACTOR = 0.55f;
+    private final String KEY_LABEL_HEIGHT_REFERENCE_CHAR = "H";
 
     private final UIHandler mHandler = new UIHandler();
 
@@ -465,7 +474,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
         mPreviewPopup = new PopupWindow(context);
         if (previewLayout != 0) {
             mPreviewText = (TextView) inflate.inflate(previewLayout, null);
-            mPreviewTextSizeLarge = (int) mPreviewText.getTextSize();
+            mPreviewTextSizeLarge = (int) res.getDimension(R.dimen.key_preview_text_size_large);
             mPreviewPopup.setContentView(mPreviewText);
             mPreviewPopup.setBackgroundDrawable(null);
         } else {
@@ -576,6 +585,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
         LatinImeLogger.onSetKeyboard(keyboard);
         mKeys = mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
                 -getPaddingTop() + mVerticalCorrection);
+        mKeyboardVerticalGap = (int)getResources().getDimension(R.dimen.key_bottom_gap);
         for (PointerTracker tracker : mPointerTrackers) {
             tracker.setKeyboard(mKeys, mKeyHysteresisDistance);
         }
@@ -720,7 +730,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
         int dimensionSum = 0;
         for (int i = 0; i < length; i++) {
             Key key = keys[i];
-            dimensionSum += Math.min(key.width, key.height) + key.gap;
+            dimensionSum += Math.min(key.width, key.height + mKeyboardVerticalGap) + key.gap;
         }
         if (dimensionSum < 0 || length == 0) return;
         mKeyDetector.setProximityThreshold((int) (dimensionSum * 1.4f / length));
@@ -772,13 +782,14 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
         paint.setColor(mKeyTextColor);
         boolean drawSingleKey = false;
         if (invalidKey != null && canvas.getClipBounds(clipRegion)) {
-          // Is clipRegion completely contained within the invalidated key?
-          if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left &&
-                  invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top &&
-                  invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right &&
-                  invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) {
-              drawSingleKey = true;
-          }
+            // TODO we should use Rect.inset and Rect.contains here.
+            // Is clipRegion completely contained within the invalidated key?
+            if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left &&
+                    invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top &&
+                    invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right &&
+                    invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) {
+                drawSingleKey = true;
+            }
         }
         canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
         final int keyCount = keys.length;
@@ -794,8 +805,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
             String label = key.label == null? null : adjustCase(key.label).toString();
 
             final Rect bounds = keyBackground.getBounds();
-            if (key.width != bounds.right ||
-                    key.height != bounds.bottom) {
+            if (key.width != bounds.right || key.height != bounds.bottom) {
                 keyBackground.setBounds(0, 0, key.width, key.height);
             }
             canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop);
@@ -804,22 +814,34 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
             boolean shouldDrawIcon = true;
             if (label != null) {
                 // For characters, use large font. For labels like "Done", use small font.
+                final int labelSize;
                 if (label.length() > 1 && key.codes.length < 2) {
-                    paint.setTextSize(mLabelTextSize);
+                    labelSize = mLabelTextSize;
                     paint.setTypeface(Typeface.DEFAULT_BOLD);
                 } else {
-                    paint.setTextSize(mKeyTextSize);
+                    labelSize = mKeyTextSize;
                     paint.setTypeface(mKeyTextStyle);
                 }
+                paint.setTextSize(labelSize);
+
+                Integer labelHeightValue = mTextHeightCache.get(labelSize);
+                final int labelHeight;
+                if (labelHeightValue != null) {
+                    labelHeight = labelHeightValue;
+                } else {
+                    Rect textBounds = new Rect();
+                    paint.getTextBounds(KEY_LABEL_HEIGHT_REFERENCE_CHAR, 0, 1, textBounds);
+                    labelHeight = textBounds.height();
+                    mTextHeightCache.put(labelSize, labelHeight);
+                }
+
                 // Draw a drop shadow for the text
                 paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor);
-                // Draw the text
-                canvas.drawText(label,
-                    (key.width - padding.left - padding.right) / 2
-                            + padding.left,
-                    (key.height - padding.top - padding.bottom) / 2
-                            + (paint.getTextSize() - paint.descent()) / 2 + padding.top,
-                    paint);
+                final int centerX = (key.width + padding.left - padding.right) / 2;
+                final int centerY = (key.height + padding.top - padding.bottom) / 2;
+                final float baseline = centerY
+                        + labelHeight * KEY_LABEL_VERTICAL_ADJUSTMENT_FACTOR;
+                canvas.drawText(label, centerX, baseline, paint);
                 // Turn off drop shadow
                 paint.setShadowLayer(0, 0, 0, 0);
 
@@ -829,15 +851,23 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
             }
             if (key.icon != null && shouldDrawIcon) {
                 // Special handing for the upper-right number hint icons
-                final int drawableWidth = isNumberAtEdgeOfPopupChars(key) ?
-                        key.width : key.icon.getIntrinsicWidth();
-                final int drawableHeight = isNumberAtEdgeOfPopupChars(key) ?
-                        key.height : key.icon.getIntrinsicHeight();
-
-                final int drawableX = (key.width - padding.left - padding.right
-                        - drawableWidth) / 2 + padding.left;
-                final int drawableY = (key.height - padding.top - padding.bottom
-                        - drawableHeight) / 2 + padding.top;
+                final int drawableWidth;
+                final int drawableHeight;
+                final int drawableX;
+                final int drawableY;
+                if (isNumberAtEdgeOfPopupChars(key)) {
+                    drawableWidth = key.width;
+                    drawableHeight = key.height;
+                    drawableX = 0;
+                    drawableY = NUMBER_HINT_VERTICAL_ADJUSTMENT_PIXEL;
+                } else {
+                    drawableWidth = key.icon.getIntrinsicWidth();
+                    drawableHeight = key.icon.getIntrinsicHeight();
+                    drawableX = (key.width - padding.left - padding.right - drawableWidth)
+                            / 2 + padding.left;
+                    drawableY = (key.height - padding.top - padding.bottom - drawableHeight)
+                            / 2 + padding.top;
+                }
                 canvas.translate(drawableX, drawableY);
                 key.icon.setBounds(0, 0, drawableWidth, drawableHeight);
                 key.icon.draw(canvas);
@@ -1003,6 +1033,7 @@ public class LatinKeyboardBaseView extends View implements PointerTracker.UIProx
         if (key == null)
             return;
         mInvalidatedKey = key;
+        // TODO we should clean up this and record key's region to use in onBufferDraw.
         mDirtyRect.union(key.x + getPaddingLeft(), key.y + getPaddingTop(),
                 key.x + key.width + getPaddingLeft(), key.y + key.height + getPaddingTop());
         onBufferDraw();