Merge "Import revised translations."
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_popup_background_holo.9.png b/java/res/drawable-hdpi/keyboard_popup_panel_background_holo.9.png
similarity index 100%
rename from java/res/drawable-hdpi/btn_keyboard_key_popup_background_holo.9.png
rename to java/res/drawable-hdpi/keyboard_popup_panel_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_search_holo.png b/java/res/drawable-hdpi/sym_keyboard_search_holo.png
index 72d9e24..d888214 100644
--- a/java/res/drawable-hdpi/sym_keyboard_search_holo.png
+++ b/java/res/drawable-hdpi/sym_keyboard_search_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_popup_background_holo.9.png b/java/res/drawable-mdpi/keyboard_popup_panel_background_holo.9.png
similarity index 100%
rename from java/res/drawable-mdpi/btn_keyboard_key_popup_background_holo.9.png
rename to java/res/drawable-mdpi/keyboard_popup_panel_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_search_holo.png b/java/res/drawable-mdpi/sym_keyboard_search_holo.png
index 709012a..9eb214a 100644
--- a/java/res/drawable-mdpi/sym_keyboard_search_holo.png
+++ b/java/res/drawable-mdpi/sym_keyboard_search_holo.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_popup_background_holo.9.png b/java/res/drawable-xhdpi/keyboard_popup_panel_background_holo.9.png
similarity index 100%
rename from java/res/drawable-xhdpi/btn_keyboard_key_popup_background_holo.9.png
rename to java/res/drawable-xhdpi/keyboard_popup_panel_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_search_holo.png b/java/res/drawable-xhdpi/sym_keyboard_search_holo.png
index 1009706..0f4caad 100644
--- a/java/res/drawable-xhdpi/sym_keyboard_search_holo.png
+++ b/java/res/drawable-xhdpi/sym_keyboard_search_holo.png
Binary files differ
diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml
index 88b48fc..13560e0 100644
--- a/java/res/layout/input_view.xml
+++ b/java/res/layout/input_view.xml
@@ -25,6 +25,11 @@
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
 >
+    <View
+        android:id="@+id/key_preview_backing"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/key_preview_backing_height" />
+
     <!-- On tablets, the suggestions strip is centered with horizontal paddings on both sides
          because width of the landscape mode is too long for the suggestions strip. This
          LinearLayout is required to hold the paddings. -->
@@ -33,8 +38,6 @@
         android:orientation="horizontal"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:minHeight="@dimen/suggestions_view_minimum_height"
-        android:gravity="bottom"
     >
         <View
             android:layout_width="@dimen/suggestions_strip_padding"
diff --git a/java/res/layout/suggestions_strip.xml b/java/res/layout/suggestions_strip.xml
index 9252017..cbf31e6 100644
--- a/java/res/layout/suggestions_strip.xml
+++ b/java/res/layout/suggestions_strip.xml
@@ -22,16 +22,9 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 >
-    <!-- Placer for debug information -->
-    <RelativeLayout
-        android:id="@+id/suggestions_placer"
+    <LinearLayout
+        android:id="@+id/suggestions_strip"
+        android:orientation="horizontal"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-    >
-        <LinearLayout
-            android:id="@+id/suggestions_strip"
-            android:orientation="horizontal"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" />
-    </RelativeLayout>
+        android:layout_height="match_parent" />
 </merge>
diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
index 9149b5d..0f9bde8 100644
--- a/java/res/values-land/dimens.xml
+++ b/java/res/values-land/dimens.xml
@@ -60,7 +60,10 @@
 
     <dimen name="suggestions_strip_height">36dip</dimen>
     <dimen name="more_suggestions_row_height">36dip</dimen>
-    <dimen name="suggestions_view_minimum_height">160sp</dimen>
+    <integer name="max_more_suggestions_row">2</integer>
+    <fraction name="min_more_suggestions_width">60%</fraction>
+    <!-- key_preview_backing_height = more_suggestions_row_height * max_more_suggestions_row -->
+    <dimen name="key_preview_backing_height">72dip</dimen>
     <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
     <!-- popup_key_height x 1.2 -->
     <dimen name="mini_keyboard_slide_allowance">0.336in</dimen>
diff --git a/java/res/values-sw600dp-land/dimens.xml b/java/res/values-sw600dp-land/dimens.xml
index f1715af..c1cef1d 100644
--- a/java/res/values-sw600dp-land/dimens.xml
+++ b/java/res/values-sw600dp-land/dimens.xml
@@ -51,4 +51,8 @@
     <fraction name="key_uppercase_letter_ratio">29%</fraction>
 
     <dimen name="suggestions_strip_padding">40.0mm</dimen>
+    <integer name="max_more_suggestions_row">5</integer>
+    <fraction name="min_more_suggestions_width">50%</fraction>
+    <!-- key_preview_backing_height = more_suggestions_row_height * max_more_suggestions_row -->
+    <dimen name="key_preview_backing_height">220dip</dimen>
 </resources>
diff --git a/java/res/values-sw600dp/dimens.xml b/java/res/values-sw600dp/dimens.xml
index 6955736..d02b4ea 100644
--- a/java/res/values-sw600dp/dimens.xml
+++ b/java/res/values-sw600dp/dimens.xml
@@ -68,6 +68,10 @@
 
     <dimen name="suggestions_strip_height">44dip</dimen>
     <dimen name="more_suggestions_row_height">44dip</dimen>
+    <integer name="max_more_suggestions_row">6</integer>
+    <fraction name="min_more_suggestions_width">90%</fraction>
+    <!-- key_preview_backing_height = more_suggestions_row_height * max_more_suggestions_row -->
+    <dimen name="key_preview_backing_height">264dip</dimen>
     <dimen name="suggestions_strip_padding">15.0mm</dimen>
     <dimen name="suggestion_min_width">0.3in</dimen>
     <dimen name="suggestion_padding">12dip</dimen>
diff --git a/java/res/values-sw768dp-land/dimens.xml b/java/res/values-sw768dp-land/dimens.xml
index 7303ea1..8f9b006 100644
--- a/java/res/values-sw768dp-land/dimens.xml
+++ b/java/res/values-sw768dp-land/dimens.xml
@@ -59,4 +59,5 @@
     <dimen name="key_preview_offset_ics">0.05in</dimen>
 
     <dimen name="suggestions_strip_padding">40.0mm</dimen>
+    <fraction name="min_more_suggestions_width">50%</fraction>
 </resources>
diff --git a/java/res/values-sw768dp/dimens.xml b/java/res/values-sw768dp/dimens.xml
index 7d2ac48..bfc2593 100644
--- a/java/res/values-sw768dp/dimens.xml
+++ b/java/res/values-sw768dp/dimens.xml
@@ -71,7 +71,10 @@
 
     <dimen name="suggestions_strip_height">44dip</dimen>
     <dimen name="more_suggestions_row_height">44dip</dimen>
-    <dimen name="suggestions_view_minimum_height">200sp</dimen>
+    <integer name="max_more_suggestions_row">6</integer>
+    <fraction name="min_more_suggestions_width">90%</fraction>
+    <!-- key_preview_backing_height = more_suggestions_row_height * max_more_suggestions_row -->
+    <dimen name="key_preview_backing_height">264dip</dimen>
     <dimen name="suggestions_strip_padding">15.0mm</dimen>
     <dimen name="suggestion_min_width">46dip</dimen>
     <dimen name="suggestion_padding">8dip</dimen>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index fa6b2eb..e964889 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -22,16 +22,18 @@
         <attr name="latinKeyboardStyle" format="reference" />
         <!-- KeyboardView style -->
         <attr name="keyboardViewStyle" format="reference" />
+        <!-- MiniKeyboard style -->
+        <attr name="miniKeyboardStyle" format="reference" />
         <!-- MiniKeyboardView style -->
         <attr name="miniKeyboardViewStyle" format="reference" />
         <attr name="miniKeyboardPanelStyle" format="reference" />
         <!-- Suggestions strip style -->
         <attr name="suggestionsStripBackgroundStyle" format="reference" />
-        <attr name="suggestionsPaneViewStyle" format="reference" />
+        <attr name="suggestionsViewStyle" format="reference" />
+        <attr name="moreSuggestionsViewStyle" format="reference" />
         <attr name="suggestionBackgroundStyle" format="reference" />
         <attr name="suggestionPreviewBackgroundStyle" format="reference" />
-        <attr name="suggestionsViewStyle" format="reference" />
-    </declare-styleable>
+        </declare-styleable>
 
     <declare-styleable name="KeyboardView">
         <!-- Image for the key. This image needs to be a StateListDrawable, with the following
@@ -124,19 +126,21 @@
         <attr name="colorSuggested" format="color" />
         <attr name="suggestionsCountInStrip" format="integer" />
         <attr name="centerSuggestionPercentile" format="integer" />
+        <attr name="maxMoreSuggestionsRow" format="integer" />
+        <attr name="minMoreSuggestionsWidth" format="float" />
     </declare-styleable>
 
     <declare-styleable name="Keyboard">
         <!-- Default keyboard height -->
-        <attr name="keyboardHeight" format="dimension" />
+        <attr name="keyboardHeight" format="dimension|fraction" />
         <!-- Maximum keyboard height, in pixels or percentage of display height -->
         <attr name="maxKeyboardHeight" format="dimension|fraction" />
         <!-- 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. -->
-        <attr name="keyboardTopPadding" format="dimension" />
-        <attr name="keyboardBottomPadding" format="dimension" />
+        <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.
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index 1ffbbac..d9ff8d7 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -80,6 +80,8 @@
              will be subject to auto-correction. -->
         <item>0</item>
     </string-array>
+    <!-- Threshold of the normalized score of the best suggestion for the spell checker to declare a word to be a typo -->
+    <string name="spellchecker_typo_threshold_value">0.11</string>
     <!--  Screen metrics for logging. 0 = "mdpi", 1 = "hdpi", 2 = "xlarge" -->
     <integer name="log_screen_metrics">0</integer>
     <bool name="config_require_umlaut_processing">false</bool>
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index a506ed7..feb119d 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -48,7 +48,7 @@
     <fraction name="keyboard_bottom_padding_ics">4.669%p</fraction>
     <fraction name="key_bottom_gap_ics">6.127%p</fraction>
     <fraction name="key_horizontal_gap_ics">1.739%p</fraction>
-    <dimen name="mini_keyboard_horizontal_edges_padding_ics">6dp</dimen>
+    <dimen name="mini_keyboard_horizontal_edges_padding_ics">4dip</dimen>
 
     <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
     <!-- popup_key_height x 1.2 -->
@@ -79,9 +79,14 @@
     <dimen name="suggestions_strip_height">40dip</dimen>
     <dimen name="more_suggestions_key_horizontal_padding">12dip</dimen>
     <dimen name="more_suggestions_row_height">40dip</dimen>
-    <dimen name="more_suggestions_slide_allowance">0.2in</dimen>
-    <fraction name="more_suggestions_info_ratio">12%</fraction>
-    <dimen name="suggestions_view_minimum_height">200sp</dimen>
+    <dimen name="more_suggestions_bottom_gap">6dip</dimen>
+    <dimen name="more_suggestions_modal_tolerance">0.05in</dimen>
+    <dimen name="more_suggestions_slide_allowance">0.1in</dimen>
+    <integer name="max_more_suggestions_row">6</integer>
+    <fraction name="min_more_suggestions_width">90%</fraction>
+    <fraction name="more_suggestions_info_ratio">18%</fraction>
+    <!-- key_preview_backing_height = more_suggestions_row_height * max_more_suggestions_row -->
+    <dimen name="key_preview_backing_height">160dip</dimen>
     <dimen name="suggestions_strip_padding">0dip</dimen>
     <dimen name="suggestion_min_width">44dip</dimen>
     <dimen name="suggestion_padding">6dip</dimen>
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index 17b3d14..0e8216b 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -68,6 +68,14 @@
         <item name="backgroundDimAmount">0.5</item>
     </style>
     <style
+        name="MiniKeyboard"
+        parent="Keyboard"
+    >
+        <item name="keyboardTopPadding">0dip</item>
+        <item name="keyboardBottomPadding">0dip</item>
+        <item name="horizontalGap">0dip</item>
+    </style>
+    <style
         name="MiniKeyboardView"
         parent="KeyboardView"
     >
@@ -79,20 +87,9 @@
         <item name="android:paddingLeft">@dimen/mini_keyboard_horizontal_edges_padding</item>
         <item name="android:paddingRight">@dimen/mini_keyboard_horizontal_edges_padding</item>
     </style>
-    <style
-        name="SuggestionsPaneViewStyle"
-        parent="MiniKeyboardView"
-    >
-    </style>
     <style name="SuggestionsStripBackgroundStyle">
         <item name="android:background">@drawable/keyboard_suggest_strip</item>
     </style>
-    <style name="SuggestionBackgroundStyle">
-        <item name="android:background">@drawable/btn_suggestion</item>
-    </style>
-    <style name="SuggestionPreviewBackgroundStyle">
-        <item name="android:background">@drawable/suggestion_feedback_background</item>
-    </style>
     <style
         name="SuggestionsViewStyle"
         parent="SuggestionsStripBackgroundStyle"
@@ -103,6 +100,19 @@
         <item name="colorSuggested">#FFFCAE00</item>
         <item name="suggestionsCountInStrip">@integer/suggestions_count_in_strip</item>
         <item name="centerSuggestionPercentile">@integer/center_suggestion_percentile</item>
+        <item name="maxMoreSuggestionsRow">@integer/max_more_suggestions_row</item>
+        <item name="minMoreSuggestionsWidth">@fraction/min_more_suggestions_width</item>
+    </style>
+    <style
+        name="MoreSuggestionsViewStyle"
+        parent="MiniKeyboardView"
+    >
+    </style>
+    <style name="SuggestionBackgroundStyle">
+        <item name="android:background">@drawable/btn_suggestion</item>
+    </style>
+    <style name="SuggestionPreviewBackgroundStyle">
+        <item name="android:background">@drawable/suggestion_feedback_background</item>
     </style>
     <!-- Theme "Basic high contrast" -->
     <style
@@ -144,6 +154,14 @@
         <item name="shadowColor">#FFFFFFFF</item>
     </style>
     <style
+        name="MiniKeyboard.Stone"
+        parent="Keyboard.Stone"
+    >
+        <item name="keyboardTopPadding">0dip</item>
+        <item name="keyboardBottomPadding">0dip</item>
+        <item name="horizontalGap">0dip</item>
+    </style>
+    <style
         name="MiniKeyboardView.Stone"
         parent="MiniKeyboardView"
     >
@@ -175,6 +193,14 @@
         <item name="keyTextStyle">bold</item>
     </style>
     <style
+        name="MiniKeyboard.Gingerbread"
+        parent="Keyboard.Gingerbread"
+    >
+        <item name="keyboardTopPadding">0dip</item>
+        <item name="keyboardBottomPadding">0dip</item>
+        <item name="horizontalGap">0dip</item>
+    </style>
+    <style
         name="MiniKeyboardView.Gingerbread"
         parent="MiniKeyboardView"
     >
@@ -218,6 +244,14 @@
         <item name="shadowRadius">0.0</item>
     </style>
     <style
+        name="MiniKeyboard.IceCreamSandwich"
+        parent="Keyboard.IceCreamSandwich"
+    >
+        <item name="keyboardTopPadding">0dip</item>
+        <item name="keyboardBottomPadding">0dip</item>
+        <item name="horizontalGap">0dip</item>
+    </style>
+    <style
         name="MiniKeyboardView.IceCreamSandwich"
         parent="MiniKeyboardView"
     >
@@ -225,26 +259,13 @@
         <item name="keyBackground">@drawable/btn_keyboard_key_popup_ics</item>
     </style>
     <style name="MiniKeyboardPanelStyle.IceCreamSandwich">
-        <item name="android:background">@drawable/btn_keyboard_key_popup_background_holo</item>
+        <item name="android:background">@drawable/keyboard_popup_panel_background_holo</item>
         <item name="android:paddingLeft">@dimen/mini_keyboard_horizontal_edges_padding_ics</item>
         <item name="android:paddingRight">@dimen/mini_keyboard_horizontal_edges_padding_ics</item>
     </style>
     <style name="SuggestionsStripBackgroundStyle.IceCreamSandwich">
         <item name="android:background">@drawable/keyboard_suggest_strip_holo</item>
     </style>
-    <style name="SuggestionBackgroundStyle.IceCreamSandwich">
-        <item name="android:background">@drawable/btn_suggestion_ics</item>
-    </style>
-    <style
-        name="SuggestionPreviewBackgroundStyle.IceCreamSandwich"
-        parent="MiniKeyboardPanelStyle.IceCreamSandwich"
-    >
-    </style>
-    <style
-        name="SuggestionsPaneViewStyle.IceCreamSandwich"
-        parent="MiniKeyboardView.IceCreamSandwich"
-    >
-    </style>
     <style
         name="SuggestionsViewStyle.IceCreamSandwich"
         parent="SuggestionsStripBackgroundStyle.IceCreamSandwich"
@@ -255,6 +276,21 @@
         <item name="colorSuggested">#FFA7A9AC</item>
         <item name="suggestionsCountInStrip">@integer/suggestions_count_in_strip</item>
         <item name="centerSuggestionPercentile">@integer/center_suggestion_percentile</item>
+        <item name="maxMoreSuggestionsRow">@integer/max_more_suggestions_row</item>
+        <item name="minMoreSuggestionsWidth">@fraction/min_more_suggestions_width</item>
+    </style>
+    <style
+        name="MoreSuggestionsViewStyle.IceCreamSandwich"
+        parent="MiniKeyboardView.IceCreamSandwich"
+    >
+    </style>
+    <style name="SuggestionBackgroundStyle.IceCreamSandwich">
+        <item name="android:background">@drawable/btn_suggestion_ics</item>
+    </style>
+    <style
+        name="SuggestionPreviewBackgroundStyle.IceCreamSandwich"
+        parent="MiniKeyboardPanelStyle.IceCreamSandwich"
+    >
     </style>
     <style name="MiniKeyboardAnimation">
         <item name="android:windowEnterAnimation">@anim/mini_keyboard_fadein</item>
diff --git a/java/res/values/themes-basic-highcontrast.xml b/java/res/values/themes-basic-highcontrast.xml
index ee41093..ce05980 100644
--- a/java/res/values/themes-basic-highcontrast.xml
+++ b/java/res/values/themes-basic-highcontrast.xml
@@ -19,12 +19,13 @@
         <item name="keyboardStyle">@style/Keyboard</item>
         <item name="latinKeyboardStyle">@style/LatinKeyboard</item>
         <item name="keyboardViewStyle">@style/KeyboardView.HighContrast</item>
+        <item name="miniKeyboardStyle">@style/MiniKeyboard</item>
         <item name="miniKeyboardViewStyle">@style/MiniKeyboardView</item>
         <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
         <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
-        <item name="suggestionsPaneViewStyle">@style/SuggestionsPaneViewStyle</item>
+        <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
+        <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
         <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
         <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
-        <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
     </style>
 </resources>
diff --git a/java/res/values/themes-basic.xml b/java/res/values/themes-basic.xml
index ff7f9ed..ff9fed5 100644
--- a/java/res/values/themes-basic.xml
+++ b/java/res/values/themes-basic.xml
@@ -19,12 +19,13 @@
         <item name="keyboardStyle">@style/Keyboard</item>
         <item name="latinKeyboardStyle">@style/LatinKeyboard</item>
         <item name="keyboardViewStyle">@style/KeyboardView</item>
+        <item name="miniKeyboardStyle">@style/MiniKeyboard</item>
         <item name="miniKeyboardViewStyle">@style/MiniKeyboardView</item>
         <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
         <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
-        <item name="suggestionsPaneViewStyle">@style/SuggestionsPaneViewStyle</item>
+        <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
+        <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
         <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
         <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
-        <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
     </style>
 </resources>
diff --git a/java/res/values/themes-gingerbread.xml b/java/res/values/themes-gingerbread.xml
index af91c3b..be853eb 100644
--- a/java/res/values/themes-gingerbread.xml
+++ b/java/res/values/themes-gingerbread.xml
@@ -19,12 +19,13 @@
         <item name="keyboardStyle">@style/Keyboard.Gingerbread</item>
         <item name="latinKeyboardStyle">@style/LatinKeyboard</item>
         <item name="keyboardViewStyle">@style/KeyboardView.Gingerbread</item>
+        <item name="miniKeyboardStyle">@style/MiniKeyboard.Gingerbread</item>
         <item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Gingerbread</item>
         <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
         <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
-        <item name="suggestionsPaneViewStyle">@style/SuggestionsPaneViewStyle</item>
+        <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
+        <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
         <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
         <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
-        <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
     </style>
 </resources>
diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml
index 341afcc..618aaed 100644
--- a/java/res/values/themes-ics.xml
+++ b/java/res/values/themes-ics.xml
@@ -19,12 +19,13 @@
         <item name="keyboardStyle">@style/Keyboard.IceCreamSandwich</item>
         <item name="latinKeyboardStyle">@style/LatinKeyboard.IceCreamSandwich</item>
         <item name="keyboardViewStyle">@style/KeyboardView.IceCreamSandwich</item>
+        <item name="miniKeyboardStyle">@style/MiniKeyboard.IceCreamSandwich</item>
         <item name="miniKeyboardViewStyle">@style/MiniKeyboardView.IceCreamSandwich</item>
         <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle.IceCreamSandwich</item>
         <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle.IceCreamSandwich</item>
-        <item name="suggestionsPaneViewStyle">@style/SuggestionsPaneViewStyle.IceCreamSandwich</item>
+        <item name="suggestionsViewStyle">@style/SuggestionsViewStyle.IceCreamSandwich</item>
+        <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle.IceCreamSandwich</item>
         <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle.IceCreamSandwich</item>
         <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle.IceCreamSandwich</item>
-        <item name="suggestionsViewStyle">@style/SuggestionsViewStyle.IceCreamSandwich</item>
     </style>
 </resources>
diff --git a/java/res/values/themes-stone-bold.xml b/java/res/values/themes-stone-bold.xml
index 915f226..fdf9c51 100644
--- a/java/res/values/themes-stone-bold.xml
+++ b/java/res/values/themes-stone-bold.xml
@@ -19,12 +19,13 @@
         <item name="keyboardStyle">@style/Keyboard.Stone</item>
         <item name="latinKeyboardStyle">@style/LatinKeyboard.Stone</item>
         <item name="keyboardViewStyle">@style/KeyboardView.Stone.Bold</item>
+        <item name="miniKeyboardStyle">@style/MiniKeyboard.Stone</item>
         <item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Stone</item>
         <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
         <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
-        <item name="suggestionsPaneViewStyle">@style/SuggestionsPaneViewStyle</item>
-            <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
-        <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
         <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
+        <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
+        <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
+        <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
     </style>
 </resources>
diff --git a/java/res/values/themes-stone.xml b/java/res/values/themes-stone.xml
index 6d5b9db..cb3edc5 100644
--- a/java/res/values/themes-stone.xml
+++ b/java/res/values/themes-stone.xml
@@ -19,12 +19,13 @@
         <item name="keyboardStyle">@style/Keyboard.Stone</item>
         <item name="latinKeyboardStyle">@style/LatinKeyboard.Stone</item>
         <item name="keyboardViewStyle">@style/KeyboardView.Stone</item>
+        <item name="miniKeyboardStyle">@style/MiniKeyboard.Stone</item>
         <item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Stone</item>
         <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
         <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
-        <item name="suggestionsPaneViewStyle">@style/SuggestionsPaneViewStyle</item>
+        <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
+        <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
         <item name="suggestionBackgroundStyle">@style/SuggestionBackgroundStyle</item>
         <item name="suggestionPreviewBackgroundStyle">@style/SuggestionPreviewBackgroundStyle</item>
-        <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
     </style>
 </resources>
diff --git a/java/res/xml/kbd_mini_keyboard_template.xml b/java/res/xml/kbd_mini_keyboard_template.xml
index d25878b..ad6cf51 100644
--- a/java/res/xml/kbd_mini_keyboard_template.xml
+++ b/java/res/xml/kbd_mini_keyboard_template.xml
@@ -21,5 +21,6 @@
 <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
     latin:keyWidth="10%p"
     latin:rowHeight="@dimen/popup_key_height"
+    style="?attr/miniKeyboardStyle"
     >
 </Keyboard>
diff --git a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
index b6b86a4..a6bb83a 100644
--- a/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/InputMethodSubtypeCompatWrapper.java
@@ -100,8 +100,7 @@
     public String getLocale() {
         if (mObj == null) return mDummyLocale;
         final String s = (String)CompatUtils.invoke(mObj, null, METHOD_getLocale);
-        if (TextUtils.isEmpty(s)) return DEFAULT_LOCALE;
-        return s;
+        return s != null ? s : DEFAULT_LOCALE;
     }
 
     public String getMode() {
diff --git a/java/src/com/android/inputmethod/compat/LinearLayoutCompatUtils.java b/java/src/com/android/inputmethod/compat/LinearLayoutCompatUtils.java
deleted file mode 100644
index 674cbe7..0000000
--- a/java/src/com/android/inputmethod/compat/LinearLayoutCompatUtils.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.inputmethod.compat;
-
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.util.AttributeSet;
-import android.util.Log;
-
-import java.lang.reflect.Field;
-
-public class LinearLayoutCompatUtils {
-    private static final String TAG = LinearLayoutCompatUtils.class.getSimpleName();
-
-    private static final Class<?> CLASS_R_STYLEABLE = CompatUtils.getClass(
-            "com.android.internal.R$styleable");
-    private static final Field STYLEABLE_VIEW = CompatUtils.getField(
-            CLASS_R_STYLEABLE, "View");
-    private static final Field STYLEABLE_VIEW_BACKGROUND = CompatUtils.getField(
-            CLASS_R_STYLEABLE, "View_background");
-    private static final Object VALUE_STYLEABLE_VIEW = CompatUtils.getFieldValue(
-            null, null, STYLEABLE_VIEW);
-    private static final Integer VALUE_STYLEABLE_VIEW_BACKGROUND =
-            (Integer)CompatUtils.getFieldValue(null, null, STYLEABLE_VIEW_BACKGROUND);
-
-    public static Drawable getBackgroundDrawable(Context context, AttributeSet attrs,
-            int defStyleAttr, int defStyleRes) {
-        if (!(VALUE_STYLEABLE_VIEW instanceof int[]) || VALUE_STYLEABLE_VIEW_BACKGROUND == null) {
-            Log.w(TAG, "Can't get View background attribute using reflection");
-            return null;
-        }
-
-        final int[] styleableView = (int[])VALUE_STYLEABLE_VIEW;
-        final TypedArray a = context.obtainStyledAttributes(
-                attrs, styleableView, defStyleAttr, defStyleRes);
-        final Drawable background = a.getDrawable(VALUE_STYLEABLE_VIEW_BACKGROUND);
-        a.recycle();
-        return background;
-    }
-}
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index d9089e1..4ec16bd 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -438,8 +438,6 @@
             mMoreKeysWindow = new PopupWindow(getContext());
             mMoreKeysWindow.setBackgroundDrawable(null);
             mMoreKeysWindow.setAnimationStyle(R.style.MiniKeyboardAnimation);
-            // Allow popup window to be drawn off the screen.
-            mMoreKeysWindow.setClippingEnabled(false);
         }
         mMoreKeysPanel = moreKeysPanel;
         mMoreKeysPanelPointerTrackerId = tracker.mPointerId;
@@ -552,7 +550,7 @@
                 mOldKeyIndex = tracker.getKeyIndexOn(lastX, lastY);
                 tracker.onUpEvent(lastX, lastY, eventTime);
             } else if (pointerCount == 1 && oldPointerCount == 1) {
-                processMotionEvent(tracker, action, x, y, eventTime, this);
+                tracker.processMotionEvent(action, x, y, eventTime, this);
             } else {
                 Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount
                         + " (old " + oldPointerCount + ")");
@@ -575,32 +573,12 @@
                 tracker.onMoveEvent(px, py, eventTime);
             }
         } else {
-            processMotionEvent(getPointerTracker(id), action, x, y, eventTime, this);
+            getPointerTracker(id).processMotionEvent(action, x, y, eventTime, this);
         }
 
         return true;
     }
 
-    private static void processMotionEvent(PointerTracker tracker, int action, int x, int y,
-            long eventTime, PointerTracker.KeyEventHandler handler) {
-        switch (action) {
-        case MotionEvent.ACTION_DOWN:
-        case MotionEvent.ACTION_POINTER_DOWN:
-            tracker.onDownEvent(x, y, eventTime, handler);
-            break;
-        case MotionEvent.ACTION_UP:
-        case MotionEvent.ACTION_POINTER_UP:
-            tracker.onUpEvent(x, y, eventTime);
-            break;
-        case MotionEvent.ACTION_MOVE:
-            tracker.onMoveEvent(x, y, eventTime);
-            break;
-        case MotionEvent.ACTION_CANCEL:
-            tracker.onCancelEvent(x, y, eventTime);
-            break;
-        }
-    }
-
     @Override
     public void closing() {
         super.closing();
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
index da91b62..ad8056c 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
@@ -123,7 +123,9 @@
                 }
 
                 mWidth = mOccupiedWidth = mNumColumns * mDefaultKeyWidth;
-                mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
+                // Need to subtract the bottom row's gutter only.
+                mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight - mVerticalGap
+                        + mTopPadding + mBottomPadding;
             }
 
             // Return key position according to column count (0 is default).
@@ -209,20 +211,9 @@
             super(view.getContext(), new MiniKeyboardParams());
             load(parentKeyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId));
 
-            // HACK: Current mini keyboard design totally relies on the 9-patch
-            // padding about horizontal
-            // and vertical key spacing. To keep the visual of mini keyboard as
-            // is, these hacks are
-            // needed to keep having the same horizontal and vertical key
-            // spacing.
-            mParams.mHorizontalGap = 0;
-            mParams.mVerticalGap = mParams.mTopPadding = parentKeyboard.mVerticalGap / 2;
-            // TODO: When we have correctly padded key background 9-patch
-            // drawables for mini keyboard,
-            // revert the above hacks and uncomment the following lines.
-            // mParams.mHorizontalGap = parentKeyboard.mHorizontalGap;
-            // mParams.mVerticalGap = parentKeyboard.mVerticalGap;
-
+            // TODO: Mini keyboard's vertical gap is currently calculated heuristically.
+            // Should revise the algorithm.
+            mParams.mVerticalGap = parentKeyboard.mVerticalGap / 2;
             mParams.mIsRtlKeyboard = parentKeyboard.mIsRtlKeyboard;
             mMoreKeys = parentKey.mMoreKeys;
 
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java
index 29861fe..0e6e129 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java
@@ -79,10 +79,8 @@
         super(context, attrs, defStyle);
 
         final Resources res = context.getResources();
-        // Override default ProximityKeyDetector.
-        mKeyDetector = new MoreKeysDetector(res.getDimension(
-                R.dimen.mini_keyboard_slide_allowance));
-        // Remove gesture detector on mini-keyboard
+        mKeyDetector = new MoreKeysDetector(
+                res.getDimension(R.dimen.mini_keyboard_slide_allowance));
         setKeyPreviewPopupEnabled(false, 0);
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 0314867..38c419d 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.util.Log;
+import android.view.MotionEvent;
 import android.widget.TextView;
 
 import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
@@ -398,6 +399,26 @@
         return onMoveKeyInternal(x, y);
     }
 
+    public void processMotionEvent(int action, int x, int y, long eventTime,
+            KeyEventHandler handler) {
+        switch (action) {
+        case MotionEvent.ACTION_DOWN:
+        case MotionEvent.ACTION_POINTER_DOWN:
+            onDownEvent(x, y, eventTime, handler);
+            break;
+        case MotionEvent.ACTION_UP:
+        case MotionEvent.ACTION_POINTER_UP:
+            onUpEvent(x, y, eventTime);
+            break;
+        case MotionEvent.ACTION_MOVE:
+            onMoveEvent(x, y, eventTime);
+            break;
+        case MotionEvent.ACTION_CANCEL:
+            onCancelEvent(x, y, eventTime);
+            break;
+        }
+    }
+
     public void onDownEvent(int x, int y, long eventTime, KeyEventHandler handler) {
         if (DEBUG_EVENT)
             printTouchEvent("onDownEvent:", x, y, eventTime);
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index cea59fe..191ae58 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -157,6 +157,7 @@
 
     private Settings.Values mSettingsValues;
 
+    private View mKeyPreviewBackingView;
     private View mSuggestionsContainer;
     private int mSuggestionsStripHeight;
     private SuggestionsView mSuggestionsView;
@@ -607,6 +608,7 @@
     @Override
     public void setInputView(View view) {
         super.setInputView(view);
+        mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing);
         mSuggestionsContainer = view.findViewById(R.id.suggestions_container);
         mSuggestionsView = (SuggestionsView) view.findViewById(R.id.suggestions_view);
         if (mSuggestionsView != null)
@@ -945,12 +947,13 @@
                     && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true);
             if (isFullscreenMode()) {
                 // No need to have extra space to show the key preview.
-                mSuggestionsContainer.setMinimumHeight(0);
+                mKeyPreviewBackingView.setVisibility(View.GONE);
                 mSuggestionsContainer.setVisibility(
                         shouldShowSuggestions ? View.VISIBLE : View.GONE);
             } else {
                 // We must control the visibility of the suggestion strip in order to avoid clipped
                 // key previews, even when we don't show the suggestion strip.
+                mKeyPreviewBackingView.setVisibility(View.VISIBLE);
                 mSuggestionsContainer.setVisibility(
                         shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE);
             }
@@ -967,15 +970,17 @@
         final KeyboardView inputView = mKeyboardSwitcher.getKeyboardView();
         if (inputView == null || mSuggestionsContainer == null)
             return;
-        final int containerHeight = mSuggestionsContainer.getHeight();
-        int touchY = containerHeight;
+        final int backingHeight = (mKeyPreviewBackingView.getVisibility() == View.GONE) ? 0
+                : mKeyPreviewBackingView.getHeight();
+        final int extraHeight = mSuggestionsContainer.getHeight() + backingHeight;
+        int touchY = extraHeight;
         // Need to set touchable region only if input view is being shown
         if (mKeyboardSwitcher.isInputViewShown()) {
             if (mSuggestionsContainer.getVisibility() == View.VISIBLE) {
                 touchY -= mSuggestionsStripHeight;
             }
             final int touchWidth = inputView.getWidth();
-            final int touchHeight = inputView.getHeight() + containerHeight
+            final int touchHeight = inputView.getHeight() + extraHeight
                     // Extend touchable region below the keyboard.
                     + EXTENDED_TOUCHABLE_REGION_HEIGHT;
             if (DEBUG) {
diff --git a/java/src/com/android/inputmethod/latin/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/MoreSuggestions.java
index a9e75b7..10d5b5c 100644
--- a/java/src/com/android/inputmethod/latin/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/MoreSuggestions.java
@@ -50,8 +50,8 @@
             private static final int MAX_COLUMNS_IN_ROW = 3;
             private int mNumRows;
 
-            public int layout(SuggestedWords suggestions, int fromPos, int maxWidth, int maxHeight,
-                    KeyboardView view) {
+            public int layout(SuggestedWords suggestions, int fromPos, int maxWidth, int minWidth,
+                    int maxRow, KeyboardView view) {
                 clearKeys();
                 final Paint paint = new Paint();
                 paint.setAntiAlias(true);
@@ -68,7 +68,7 @@
                     final int numColumn = pos - rowStartPos + 1;
                     if (numColumn > MAX_COLUMNS_IN_ROW
                             || !fitInWidth(rowStartPos, pos + 1, maxWidth / numColumn)) {
-                        if ((row + 1) * mDefaultRowHeight > maxHeight) {
+                        if ((row + 1) >= maxRow) {
                             break;
                         }
                         mNumColumnsInRow[row] = pos - rowStartPos;
@@ -81,7 +81,7 @@
                 }
                 mNumColumnsInRow[row] = pos - rowStartPos;
                 mNumRows = row + 1;
-                mWidth = mOccupiedWidth = calcurateMaxRowWidth(fromPos, pos);
+                mWidth = mOccupiedWidth = Math.max(minWidth, calcurateMaxRowWidth(fromPos, pos));
                 mHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight + mVerticalGap;
                 return pos - fromPos;
             }
@@ -163,13 +163,14 @@
         }
 
         public Builder layout(SuggestedWords suggestions, int fromPos, int maxWidth,
-                int maxHeight) {
+                int minWidth, int maxRow) {
             final Keyboard keyboard = KeyboardSwitcher.getInstance().getLatinKeyboard();
             final int xmlId = R.xml.kbd_suggestions_pane_template;
             load(keyboard.mId.cloneWithNewXml(mResources.getResourceEntryName(xmlId), xmlId));
             mParams.mVerticalGap = mParams.mTopPadding = keyboard.mVerticalGap / 2;
 
-            final int count = mParams.layout(suggestions, fromPos, maxWidth, maxHeight, mPaneView);
+            final int count = mParams.layout(suggestions, fromPos, maxWidth, minWidth, maxRow,
+                    mPaneView);
             mFromPos = fromPos;
             mToPos = fromPos + count;
             mSuggestions = suggestions;
diff --git a/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java
index 9fd9024..f595510 100644
--- a/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/MoreSuggestionsView.java
@@ -20,6 +20,7 @@
 import android.content.res.Resources;
 import android.util.AttributeSet;
 import android.view.Gravity;
+import android.view.MotionEvent;
 import android.view.View;
 import android.widget.PopupWindow;
 
@@ -29,7 +30,9 @@
 import com.android.inputmethod.keyboard.KeyboardView;
 import com.android.inputmethod.keyboard.MoreKeysDetector;
 import com.android.inputmethod.keyboard.MoreKeysPanel;
+import com.android.inputmethod.keyboard.PointerTracker;
 import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
+import com.android.inputmethod.keyboard.PointerTracker.KeyEventHandler;
 import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
 
 
@@ -40,7 +43,8 @@
 public class MoreSuggestionsView extends KeyboardView implements MoreKeysPanel {
     private final int[] mCoordinates = new int[2];
 
-    private final KeyDetector mKeyDetector;
+    private final KeyDetector mModalPanelKeyDetector;
+    private final KeyDetector mSlidingPanelKeyDetector;
 
     private Controller mController;
     private KeyboardActionListener mListener;
@@ -73,17 +77,16 @@
     };
 
     public MoreSuggestionsView(Context context, AttributeSet attrs) {
-        this(context, attrs, R.attr.suggestionsPaneViewStyle);
+        this(context, attrs, R.attr.moreSuggestionsViewStyle);
     }
 
     public MoreSuggestionsView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
         final Resources res = context.getResources();
-        // Override default ProximityKeyDetector.
-        mKeyDetector = new MoreKeysDetector(res.getDimension(
-                R.dimen.more_suggestions_slide_allowance));
-        // Remove gesture detector on suggestions pane
+        mModalPanelKeyDetector = new KeyDetector(/* keyHysteresisDistance */ 0);
+        mSlidingPanelKeyDetector = new MoreKeysDetector(
+                res.getDimension(R.dimen.more_suggestions_slide_allowance));
         setKeyPreviewPopupEnabled(false, 0);
     }
 
@@ -102,13 +105,14 @@
     @Override
     public void setKeyboard(Keyboard keyboard) {
         super.setKeyboard(keyboard);
-        mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
+        mModalPanelKeyDetector.setKeyboard(keyboard, -getPaddingLeft(), -getPaddingTop());
+        mSlidingPanelKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
                 -getPaddingTop() + mVerticalCorrection);
     }
 
     @Override
     public KeyDetector getKeyDetector() {
-        return mKeyDetector;
+        return mSlidingPanelKeyDetector;
     }
 
     @Override
@@ -187,4 +191,39 @@
     public int translateY(int y) {
         return y - mOriginY;
     }
+
+    private final KeyEventHandler mModalPanelKeyEventHandler = new KeyEventHandler() {
+        @Override
+        public KeyDetector getKeyDetector() {
+            return mModalPanelKeyDetector;
+        }
+
+        @Override
+        public KeyboardActionListener getKeyboardActionListener() {
+            return mSuggestionsPaneListener;
+        }
+
+        @Override
+        public DrawingProxy getDrawingProxy() {
+            return MoreSuggestionsView.this;
+        }
+
+        @Override
+        public TimerProxy getTimerProxy() {
+            return EMPTY_TIMER_PROXY;
+        }
+    };
+
+    @Override
+    public boolean onTouchEvent(MotionEvent me) {
+        final int action = me.getAction();
+        final long eventTime = me.getEventTime();
+        final int index = me.getActionIndex();
+        final int id = me.getPointerId(index);
+        final PointerTracker tracker = PointerTracker.getPointerTracker(id, this);
+        final int x = (int)me.getX(index);
+        final int y = (int)me.getY(index);
+        tracker.processMotionEvent(action, x, y, eventTime, mModalPanelKeyEventHandler);
+        return true;
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/SuggestionsView.java b/java/src/com/android/inputmethod/latin/SuggestionsView.java
index 10cd73d..22aa5e2 100644
--- a/java/src/com/android/inputmethod/latin/SuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/SuggestionsView.java
@@ -35,7 +35,6 @@
 import android.text.style.StyleSpan;
 import android.text.style.UnderlineSpan;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
@@ -45,10 +44,10 @@
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
 import android.widget.PopupWindow;
+import android.widget.RelativeLayout;
 import android.widget.TextView;
 
 import com.android.inputmethod.compat.FrameLayoutCompatUtils;
-import com.android.inputmethod.compat.LinearLayoutCompatUtils;
 import com.android.inputmethod.keyboard.KeyboardActionListener;
 import com.android.inputmethod.keyboard.KeyboardView;
 import com.android.inputmethod.keyboard.MoreKeysPanel;
@@ -58,7 +57,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class SuggestionsView extends LinearLayout implements OnClickListener, OnLongClickListener {
+public class SuggestionsView extends RelativeLayout implements OnClickListener,
+        OnLongClickListener {
     public interface Listener {
         public boolean addWordToDictionary(String word);
         public void pickSuggestionManually(int index, CharSequence word);
@@ -69,7 +69,6 @@
 
     private static final boolean DBG = LatinImeLogger.sDBG;
 
-    private final ViewGroup mSuggestionsPlacer;
     private final ViewGroup mSuggestionsStrip;
     private KeyboardView mKeyboardView;
 
@@ -146,12 +145,16 @@
     private static class SuggestionsViewParams {
         private static final int DEFAULT_SUGGESTIONS_COUNT_IN_STRIP = 3;
         private static final int DEFAULT_CENTER_SUGGESTION_PERCENTILE = 40;
+        private static final int DEFAULT_MAX_MORE_SUGGESTIONS_ROW = 2;
         private static final int PUNCTUATIONS_IN_STRIP = 6;
 
         public final int mPadding;
         public final int mDividerWidth;
         public final int mSuggestionsStripHeight;
         public final int mSuggestionsCountInStrip;
+        public final int mMaxMoreSuggestionsRow;
+        public final float mMinMoreSuggestionsWidth;
+        public final int mMoreSuggestionsBottomGap;
 
         private final List<TextView> mWords;
         private final List<View> mDividers;
@@ -211,10 +214,17 @@
             mCenterSuggestionWeight = a.getInt(
                     R.styleable.SuggestionsView_centerSuggestionPercentile,
                     DEFAULT_CENTER_SUGGESTION_PERCENTILE) / 100.0f;
+            mMaxMoreSuggestionsRow = a.getInt(
+                    R.styleable.SuggestionsView_maxMoreSuggestionsRow,
+                    DEFAULT_MAX_MORE_SUGGESTIONS_ROW);
+            mMinMoreSuggestionsWidth = getRatio(a,
+                    R.styleable.SuggestionsView_minMoreSuggestionsWidth);
             a.recycle();
 
             mCenterSuggestionIndex = mSuggestionsCountInStrip / 2;
             mMoreSuggestionsHint = res.getDrawable(R.drawable.more_suggestions_hint);
+            mMoreSuggestionsBottomGap = res.getDimensionPixelOffset(
+                    R.dimen.more_suggestions_bottom_gap);
 
             mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff);
             mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord);
@@ -225,6 +235,11 @@
             mHintToSaveText = context.getText(R.string.hint_add_to_dictionary);
         }
 
+        // Read fraction value in TypedArray as float.
+        private static float getRatio(TypedArray a, int index) {
+            return a.getFraction(index, 1000, 1000, 1) / 1000.0f;
+        }
+
         private CharSequence getStyledSuggestionWord(SuggestedWords suggestions, int pos) {
             final CharSequence word = suggestions.getWord(pos);
             final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions);
@@ -451,18 +466,7 @@
     }
 
     public SuggestionsView(Context context, AttributeSet attrs, int defStyle) {
-        // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument
-        // constructor.
-        // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon
-        // backward compatibility with the version 10 or earlier of the API.
-        super(context, attrs);
-        if (defStyle != R.attr.suggestionsViewStyle) {
-            throw new IllegalArgumentException(
-                    "can't accept defStyle other than R.attr.suggestionsViewStyle: defStyle="
-                    + defStyle);
-        }
-        setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable(
-                context, attrs, defStyle, R.style.SuggestionsViewStyle));
+        super(context, attrs, defStyle);
 
         final LayoutInflater inflater = LayoutInflater.from(context);
         inflater.inflate(R.layout.suggestions_strip, this);
@@ -474,7 +478,6 @@
         mPreviewPopup.setContentView(mPreviewText);
         mPreviewPopup.setBackgroundDrawable(null);
 
-        mSuggestionsPlacer = (ViewGroup)findViewById(R.id.suggestions_placer);
         mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip);
         for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) {
             final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null);
@@ -500,6 +503,9 @@
         mMoreSuggestionsWindow.setWindowLayoutMode(
                 ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
         mMoreSuggestionsWindow.setBackgroundDrawable(null);
+        final Resources res = context.getResources();
+        mMoreSuggestionsModalTolerance = res.getDimensionPixelOffset(
+                R.dimen.more_suggestions_modal_tolerance);
     }
 
     /**
@@ -527,7 +533,7 @@
         if (mSuggestions.size() == 0)
             return;
 
-        mParams.layout(mSuggestions, mSuggestionsStrip, mSuggestionsPlacer, getWidth());
+        mParams.layout(mSuggestions, mSuggestionsStrip, this, getWidth());
     }
 
     private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) {
@@ -648,9 +654,9 @@
 
     public void clear() {
         mShowingAutoCorrectionInverted = false;
-        mSuggestionsPlacer.removeAllViews();
-        mSuggestionsPlacer.addView(mSuggestionsStrip);
         mSuggestionsStrip.removeAllViews();
+        removeAllViews();
+        addView(mSuggestionsStrip);
         dismissMoreSuggestions();
     }
 
@@ -730,27 +736,23 @@
             final View container = mMoreSuggestionsContainer;
             final int maxWidth = stripWidth - container.getPaddingLeft()
                     - container.getPaddingRight();
-            final DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
-            // TODO: Revise how we determine the height
-            final int maxHeight = dm.heightPixels - mKeyboardView.getHeight() - getHeight() * 3;
             final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder;
-            builder.layout(mSuggestions, params.mSuggestionsCountInStrip, maxWidth, maxHeight);
+            builder.layout(mSuggestions, params.mSuggestionsCountInStrip, maxWidth,
+                    (int)(maxWidth * params.mMinMoreSuggestionsWidth),
+                    params.mMaxMoreSuggestionsRow);
             mMoreSuggestionsView.setKeyboard(builder.build());
             container.measure(
                     ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
 
             final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
             final int pointX = stripWidth / 2;
-            final int pointY = 0;
+            final int pointY = -params.mMoreSuggestionsBottomGap;
             moreKeysPanel.showMoreKeysPanel(
                     this, mMoreSuggestionsController, pointX, pointY,
                     mMoreSuggestionsWindow, mMoreSuggestionsListener);
-            // TODO: Should figure out how to select the pointer tracker correctly.
-            final PointerTracker tracker = PointerTracker.getPointerTracker(0, moreKeysPanel);
-            final int translatedX = moreKeysPanel.translateX(tracker.getLastX());
-            final int translatedY = moreKeysPanel.translateY(tracker.getLastY());
-            tracker.onShowMoreKeysPanel(
-                    translatedX, translatedY, SystemClock.uptimeMillis(), moreKeysPanel);
+            mCheckingIfModalOrSlidingMode = true;
+            mOriginX = mLastX;
+            mOriginY = mLastY;
             view.setPressed(false);
             mKeyboardView.dimEntireKeyboard(true);
             return true;
@@ -758,34 +760,51 @@
         return false;
     }
 
+    // Working variables for onLongClick and dispatchTouchEvent.
+    private boolean mCheckingIfModalOrSlidingMode;
+    private int mLastX;
+    private int mLastY;
+    private int mOriginX;
+    private int mOriginY;
+    private final int mMoreSuggestionsModalTolerance;
+
     @Override
     public boolean dispatchTouchEvent(MotionEvent me) {
         if (!mMoreSuggestionsWindow.isShowing()) {
+            mLastX = (int)me.getX();
+            mLastY = (int)me.getY();
             return super.dispatchTouchEvent(me);
         }
+
+        final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView;
         final int action = me.getAction();
         final long eventTime = me.getEventTime();
         final int index = me.getActionIndex();
         final int id = me.getPointerId(index);
-        final PointerTracker tracker = PointerTracker.getPointerTracker(id, mMoreSuggestionsView);
-        final int x = mMoreSuggestionsView.translateX((int)me.getX(index));
-        final int y = mMoreSuggestionsView.translateY((int)me.getY(index));
-        switch (action) {
-        case MotionEvent.ACTION_DOWN:
-        case MotionEvent.ACTION_POINTER_DOWN:
-            tracker.onDownEvent(x, y, eventTime, mMoreSuggestionsView);
-            break;
-        case MotionEvent.ACTION_UP:
-        case MotionEvent.ACTION_POINTER_UP:
-            tracker.onUpEvent(x, y, eventTime);
-            break;
-        case MotionEvent.ACTION_MOVE:
-            tracker.onMoveEvent(x, y, eventTime);
-            break;
-        case MotionEvent.ACTION_CANCEL:
-            tracker.onCancelEvent(x, y, eventTime);
-            break;
+        final PointerTracker tracker = PointerTracker.getPointerTracker(id, moreKeysPanel);
+        final int x = (int)me.getX(index);
+        final int y = (int)me.getY(index);
+        final int translatedX = moreKeysPanel.translateX(x);
+        final int translatedY = moreKeysPanel.translateY(y);
+
+        if (mCheckingIfModalOrSlidingMode) {
+            final int deltaX = Math.abs(x - mOriginX);
+            final int deltaY = Math.abs(y - mOriginY);
+            if (deltaX >= mMoreSuggestionsModalTolerance
+                    || deltaY >= mMoreSuggestionsModalTolerance) {
+                // Decided to be in the sliding input mode
+                mCheckingIfModalOrSlidingMode = false;
+                tracker.onShowMoreKeysPanel(
+                        translatedX, translatedY, SystemClock.uptimeMillis(), moreKeysPanel);
+            } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) {
+                // Decided to be in the modal input mode
+                mCheckingIfModalOrSlidingMode = false;
+            }
+            return true;
         }
+
+        // Process sliding motion events
+        tracker.processMotionEvent(action, translatedX, translatedY, eventTime, moreKeysPanel);
         return true;
     }
 
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index a6a5b6d..85c142f 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -34,6 +34,7 @@
 import com.android.inputmethod.latin.DictionaryCollection;
 import com.android.inputmethod.latin.DictionaryFactory;
 import com.android.inputmethod.latin.LocaleUtils;
+import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SynchronouslyLoadedUserDictionary;
 import com.android.inputmethod.latin.UserDictionary;
 import com.android.inputmethod.latin.Utils;
@@ -62,18 +63,38 @@
     private Map<String, Dictionary> mUserDictionaries =
             Collections.synchronizedMap(new TreeMap<String, Dictionary>());
 
+    private double mTypoThreshold;
+
+    @Override public void onCreate() {
+        super.onCreate();
+        mTypoThreshold = Double.parseDouble(getString(R.string.spellchecker_typo_threshold_value));
+    }
+
     @Override
     public Session createSession() {
-        return new AndroidSpellCheckerSession();
+        return new AndroidSpellCheckerSession(this);
     }
 
     private static class SuggestionsGatherer implements WordCallback {
+        public static class Result {
+            public final String[] mSuggestions;
+            public final boolean mLooksLikeTypo;
+            public Result(final String[] gatheredSuggestions, final boolean looksLikeTypo) {
+                mSuggestions = gatheredSuggestions;
+                mLooksLikeTypo = looksLikeTypo;
+            }
+        }
+
         private final int DEFAULT_SUGGESTION_LENGTH = 16;
         private final ArrayList<CharSequence> mSuggestions;
         private final int[] mScores;
         private final int mMaxLength;
         private int mLength = 0;
-        private boolean mSeenSuggestions = false;
+
+        // The two following attributes are only ever filled if the requested max length
+        // is 0 (or less, which is treated the same).
+        private String mBestSuggestion = null;
+        private int mBestScore = Integer.MIN_VALUE; // As small as possible
 
         SuggestionsGatherer(final int maxLength) {
             mMaxLength = maxLength;
@@ -89,14 +110,26 @@
             // if it doesn't. See documentation for binarySearch.
             final int insertIndex = positionIndex >= 0 ? positionIndex : -positionIndex - 1;
 
-            mSeenSuggestions = true;
             if (mLength < mMaxLength) {
                 final int copyLen = mLength - insertIndex;
                 ++mLength;
                 System.arraycopy(mScores, insertIndex, mScores, insertIndex + 1, copyLen);
                 mSuggestions.add(insertIndex, new String(word, wordOffset, wordLength));
             } else {
-                if (insertIndex == 0) return true;
+                if (insertIndex == 0) {
+                    // If the maxLength is 0 (should never be less, but if it is, it's treated as 0)
+                    // then we need to keep track of the best suggestion in mBestScore and
+                    // mBestSuggestion. This is so that we know whether the best suggestion makes
+                    // the score cutoff, since we need to know that to return a meaningful
+                    // looksLikeTypo.
+                    if (0 >= mMaxLength) {
+                        if (score > mBestScore) {
+                            mBestScore = score;
+                            mBestSuggestion = new String(word, wordOffset, wordLength);
+                        }
+                    }
+                    return true;
+                }
                 System.arraycopy(mScores, 1, mScores, 0, insertIndex);
                 mSuggestions.add(insertIndex, new String(word, wordOffset, wordLength));
                 mSuggestions.remove(0);
@@ -106,20 +139,41 @@
             return true;
         }
 
-        public String[] getGatheredSuggestions() {
-            if (!mSeenSuggestions) return null;
-            if (0 == mLength) return EMPTY_STRING_ARRAY;
-
-            if (DBG) {
-                if (mLength != mSuggestions.size()) {
-                    Log.e(TAG, "Suggestion size is not the same as stored mLength");
+        public Result getResults(final CharSequence originalText, final double threshold) {
+            final String[] gatheredSuggestions;
+            final boolean looksLikeTypo;
+            if (0 == mLength) {
+                // Either we found no suggestions, or we found some BUT the max length was 0.
+                // If we found some mBestSuggestion will not be null. If it is null, then
+                // we found none, regardless of the max length.
+                if (null == mBestSuggestion) {
+                    gatheredSuggestions = null;
+                    looksLikeTypo = false;
+                } else {
+                    gatheredSuggestions = EMPTY_STRING_ARRAY;
+                    final double normalizedScore =
+                            Utils.calcNormalizedScore(originalText, mBestSuggestion, mBestScore);
+                    looksLikeTypo = (normalizedScore > threshold);
                 }
+            } else {
+                if (DBG) {
+                    if (mLength != mSuggestions.size()) {
+                        Log.e(TAG, "Suggestion size is not the same as stored mLength");
+                    }
+                }
+                Collections.reverse(mSuggestions);
+                Utils.removeDupes(mSuggestions);
+                // This returns a String[], while toArray() returns an Object[] which cannot be cast
+                // into a String[].
+                gatheredSuggestions = mSuggestions.toArray(EMPTY_STRING_ARRAY);
+
+                final int bestScore = mScores[0];
+                final CharSequence bestSuggestion = mSuggestions.get(0);
+                final double normalizedScore =
+                        Utils.calcNormalizedScore(originalText, bestSuggestion, bestScore);
+                looksLikeTypo = (normalizedScore > threshold);
             }
-            Collections.reverse(mSuggestions);
-            Utils.removeDupes(mSuggestions);
-            // This returns a String[], while toArray() returns an Object[] which cannot be cast
-            // into a String[].
-            return mSuggestions.toArray(EMPTY_STRING_ARRAY);
+            return new Result(gatheredSuggestions, looksLikeTypo);
         }
     }
 
@@ -164,16 +218,22 @@
         return new DictAndProximity(dictionaryCollection, proximityInfo);
     }
 
-    private class AndroidSpellCheckerSession extends Session {
+    private static class AndroidSpellCheckerSession extends Session {
         // Immutable, but need the locale which is not available in the constructor yet
-        DictionaryPool mDictionaryPool;
+        private DictionaryPool mDictionaryPool;
         // Likewise
-        Locale mLocale;
+        private Locale mLocale;
+
+        private final AndroidSpellCheckerService mService;
+
+        AndroidSpellCheckerSession(final AndroidSpellCheckerService service) {
+            mService = service;
+        }
 
         @Override
         public void onCreate() {
             final String localeString = getLocale();
-            mDictionaryPool = getDictionaryPool(localeString);
+            mDictionaryPool = mService.getDictionaryPool(localeString);
             mLocale = LocaleUtils.constructLocaleFromString(localeString);
         }
 
@@ -242,13 +302,14 @@
                 return EMPTY_SUGGESTIONS_INFO;
             }
 
-            final String[] suggestions = suggestionsGatherer.getGatheredSuggestions();
+            final SuggestionsGatherer.Result result =
+                    suggestionsGatherer.getResults(text, mService.mTypoThreshold);
 
             final int flags =
                     (isInDict ? SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY : 0)
-                            | (null != suggestions
+                            | (result.mLooksLikeTypo
                                     ? SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO : 0);
-            return new SuggestionsInfo(flags, suggestions);
+            return new SuggestionsInfo(flags, result.mSuggestions);
         }
     }
 }