Merge "Improved shift key and symbol/alpha switch key accessibility feedback."
diff --git a/java/proguard.flags b/java/proguard.flags
index caf1ea1..5ce0c27 100644
--- a/java/proguard.flags
+++ b/java/proguard.flags
@@ -35,6 +35,6 @@
   *;
 }
 
--keep class com.android.inputmethod.keyboard.MiniKeyboard$Builder$MiniKeyboardParams {
+-keep class com.android.inputmethod.keyboard.MoreKeysKeyboard$Builder$MoreKeysKeyboardParams {
   <init>(...);
 }
diff --git a/java/res/anim/mini_keyboard_fadein.xml b/java/res/anim/more_keys_keyboard_fadein.xml
similarity index 91%
rename from java/res/anim/mini_keyboard_fadein.xml
rename to java/res/anim/more_keys_keyboard_fadein.xml
index f80e8b8..c781f36 100644
--- a/java/res/anim/mini_keyboard_fadein.xml
+++ b/java/res/anim/more_keys_keyboard_fadein.xml
@@ -25,5 +25,5 @@
     <alpha
         android:fromAlpha="0.5"
         android:toAlpha="1.0"
-        android:duration="@integer/config_mini_keyboard_fadein_anim_time" />
+        android:duration="@integer/config_more_keys_keyboard_fadein_anim_time" />
 </set>
diff --git a/java/res/anim/mini_keyboard_fadeout.xml b/java/res/anim/more_keys_keyboard_fadeout.xml
similarity index 91%
rename from java/res/anim/mini_keyboard_fadeout.xml
rename to java/res/anim/more_keys_keyboard_fadeout.xml
index 535b100..32fae6b 100644
--- a/java/res/anim/mini_keyboard_fadeout.xml
+++ b/java/res/anim/more_keys_keyboard_fadeout.xml
@@ -25,5 +25,5 @@
     <alpha
         android:fromAlpha="1.0"
         android:toAlpha="0.0"
-        android:duration="@integer/config_mini_keyboard_fadeout_anim_time" />
+        android:duration="@integer/config_more_keys_keyboard_fadeout_anim_time" />
 </set>
diff --git a/java/res/layout/mini_keyboard.xml b/java/res/layout/more_keys_keyboard.xml
similarity index 87%
rename from java/res/layout/mini_keyboard.xml
rename to java/res/layout/more_keys_keyboard.xml
index 6964ec5..89161c6 100644
--- a/java/res/layout/mini_keyboard.xml
+++ b/java/res/layout/more_keys_keyboard.xml
@@ -22,11 +22,11 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
-        style="?attr/miniKeyboardPanelStyle"
+        style="?attr/moreKeysKeyboardPanelStyle"
         >
-    <com.android.inputmethod.keyboard.MiniKeyboardView
+    <com.android.inputmethod.keyboard.MoreKeysKeyboardView
             xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
-            android:id="@+id/mini_keyboard_view"
+            android:id="@+id/more_keys_keyboard_view"
             android:layout_alignParentBottom="true"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
diff --git a/java/res/layout/more_suggestions.xml b/java/res/layout/more_suggestions.xml
index 1e59b89..34f54f9 100644
--- a/java/res/layout/more_suggestions.xml
+++ b/java/res/layout/more_suggestions.xml
@@ -22,7 +22,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:orientation="horizontal"
-        style="?attr/miniKeyboardPanelStyle"
+        style="?attr/moreKeysKeyboardPanelStyle"
         >
     <com.android.inputmethod.latin.suggestions.MoreSuggestionsView
             xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
index 081f604..0ca0e90 100644
--- a/java/res/values-af/strings.xml
+++ b/java/res/values-af/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Gestoor"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Gaan"</string>
     <string name="label_next_key" msgid="362972844525672568">"Volgende"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Klaar"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Stuur"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
index b45e1c3..ea64dae 100644
--- a/java/res/values-am/strings.xml
+++ b/java/res/values-am/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ተቀምጧል"</string>
     <string name="label_go_key" msgid="1635148082137219148">"ሂድ"</string>
     <string name="label_next_key" msgid="362972844525672568">"በመቀጠል"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"ተከናውኗል"</string>
     <string name="label_send_key" msgid="2815056534433717444">" ይላኩ"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-ar/donottranslate-more-keys.xml b/java/res/values-ar/donottranslate-more-keys.xml
index 9a7a026..df093b3 100644
--- a/java/res/values-ar/donottranslate-more-keys.xml
+++ b/java/res/values-ar/donottranslate-more-keys.xml
@@ -38,7 +38,7 @@
     <!-- In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label. -->
     <!-- TODO: Will introduce "grouping marks" to the more characters specification. -->
     <string name="more_keys_for_punctuation">"\u060c,\u061b,\u061f,!,:,-,/,\',\",\u0640\u0640\u0640|\u0640,\u064e,\u0650,\u064b,\u064d,\u0670,\u0656,\u0655,\u0654,\u0653,\u0652,\u0651,\u064c,\u064f"</string>
-    <integer name="mini_keyboard_column_for_punctuation">9</integer>
+    <integer name="more_keys_keyboard_column_for_punctuation">9</integer>
     <string name="keyhintlabel_for_punctuation">\u064b</string>
     <string name="keylabel_for_symbols_1">"١"</string>
     <string name="keylabel_for_symbols_2">"٢"</string>
@@ -104,14 +104,14 @@
     <string name="more_keys_for_star">★,\u066d</string>
     <!-- The all letters need to be mirrored are found at
          http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt -->
-    <string name="output_text_for_left_parenthesis">)</string>
-    <string name="output_text_for_right_parenthesis">(</string>
+    <integer name="keycode_for_left_parenthesis">0x0029</integer>
+    <integer name="keycode_for_right_parenthesis">0x0028</integer>
     <!-- \ufd3e: ORNATE LEFT PARENTHESIS
          \ufd3f: ORNATE RIGHT PARENTHESIS -->
     <string name="more_keys_for_left_parenthesis">[|],{|},&lt;|&gt;,\ufd3e|\ufd3f</string>
     <string name="more_keys_for_right_parenthesis">]|[,}|{,&gt;|&lt;,\ufd3f|\ufd3e</string>
-    <string name="output_text_for_less_than">&gt;</string>
-    <string name="output_text_for_greater_than">&lt;</string>
+    <integer name="keycode_for_less_than">0x003e</integer>
+    <integer name="keycode_for_greater_than">0x003c</integer>
     <!-- \u2264: LESS-THAN OR EQUAL TO
          \u2265: GREATER-THAN EQUAL TO
          \u00ab: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
@@ -129,10 +129,10 @@
          \u201f: DOUBLE HIGH-REVERSED-9 QUOTATION MARK -->
     <string name="more_keys_for_less_than">\u2264|\u2265,\u00ab|\u00bb,\u2039|\u203a</string>
     <string name="more_keys_for_greater_than">\u2265|\u2264,\u00bb|\u00ab,\u203a|\u2039</string>
-    <string name="output_text_for_left_square_bracket">]</string>
-    <string name="output_text_for_right_square_bracket">[</string>
-    <string name="output_text_for_left_curly_bracket">}</string>
-    <string name="output_text_for_right_curly_bracket">{</string>
+    <integer name="keycode_for_left_square_bracket">0x005d</integer>
+    <integer name="keycode_for_right_square_bracket">0x005b</integer>
+    <integer name="keycode_for_left_curly_bracket">0x007d</integer>
+    <integer name="keycode_for_right_curly_bracket">0x007b</integer>
     <!-- Note: Neither DroidSans nor Roboto have a glyph for DOUBLE HIGH-REVERSED-9 QUOTATION MARK. -->
     <!-- <string name="more_keys_for_double_quote">\u201c,\u201d,\u201e,\u201f,\u00ab,\u00bb</string> -->
     <!-- The 4-more keys will be displayed in order of "3,1,2,4". -->
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index 80d4b0d..c4aa441 100644
--- a/java/res/values-ar/strings.xml
+++ b/java/res/values-ar/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : تم الحفظ"</string>
     <string name="label_go_key" msgid="1635148082137219148">"تنفيذ"</string>
     <string name="label_next_key" msgid="362972844525672568">"التالي"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"تم"</string>
     <string name="label_send_key" msgid="2815056534433717444">"إرسال"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"أ ب ج"</string>
diff --git a/java/res/values-be/strings.xml b/java/res/values-be/strings.xml
index 6682128..c009474 100644
--- a/java/res/values-be/strings.xml
+++ b/java/res/values-be/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Захаваныя"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Пачаць"</string>
     <string name="label_next_key" msgid="362972844525672568">"Далей"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Гатова"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Адправіць"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
index 5a3b60f..900a7fd 100644
--- a/java/res/values-bg/strings.xml
+++ b/java/res/values-bg/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Запазено"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Старт"</string>
     <string name="label_next_key" msgid="362972844525672568">"Напред"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Изпращане"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
index 149867f..0fae132 100644
--- a/java/res/values-ca/strings.xml
+++ b/java/res/values-ca/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: desada"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Vés"</string>
     <string name="label_next_key" msgid="362972844525672568">"Següent"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Fet"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Envia"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index 6b7842c..7c4c31a 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Uloženo"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Přejít"</string>
     <string name="label_next_key" msgid="362972844525672568">"Další"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Hotovo"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Odeslat"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
index a046d61..bc871e7 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -65,6 +65,7 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Gemt"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Gå"</string>
     <string name="label_next_key" msgid="362972844525672568">"Næste"</string>
+    <string name="label_previous_key" msgid="1211868118071386787">"Forr."</string>
     <string name="label_done_key" msgid="2441578748772529288">"Udfør"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Send"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
index eb0a3fb..da5823a 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: gespeichert"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Los"</string>
     <string name="label_next_key" msgid="362972844525672568">"Weiter"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Fertig"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Senden"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index 9ca1c4e..d126edb 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Αποθηκεύτηκε"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Μετ."</string>
     <string name="label_next_key" msgid="362972844525672568">"Επόμενο"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Τέλος"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Αποστολή"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ΑΒΓ"</string>
diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
index 9e0f150..bce6a51 100644
--- a/java/res/values-en-rGB/strings.xml
+++ b/java/res/values-en-rGB/strings.xml
@@ -65,6 +65,7 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Saved"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Go"</string>
     <string name="label_next_key" msgid="362972844525672568">"Next"</string>
+    <string name="label_previous_key" msgid="1211868118071386787">"Prev"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Done"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Send"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index f4c2b45..29df462 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Ir"</string>
     <string name="label_next_key" msgid="362972844525672568">"Siguiente"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Hecho"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
index 675a426..4e47069 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -65,6 +65,7 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Ir"</string>
     <string name="label_next_key" msgid="362972844525672568">"Sig."</string>
+    <string name="label_previous_key" msgid="1211868118071386787">"Anterior"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Ok"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml
index 84f4b7f..a65bd4a 100644
--- a/java/res/values-et/strings.xml
+++ b/java/res/values-et/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : salvestatud"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Mine"</string>
     <string name="label_next_key" msgid="362972844525672568">"Edasi"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Valmis"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Saada"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
index 05f3a7a..9b75750 100644
--- a/java/res/values-fa/strings.xml
+++ b/java/res/values-fa/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ذخیره شد"</string>
     <string name="label_go_key" msgid="1635148082137219148">"برو"</string>
     <string name="label_next_key" msgid="362972844525672568">"بعدی"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"انجام شد"</string>
     <string name="label_send_key" msgid="2815056534433717444">"ارسال"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml
index f77604d..c4da3cb 100644
--- a/java/res/values-fi/strings.xml
+++ b/java/res/values-fi/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Tallennettu"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Siirry"</string>
     <string name="label_next_key" msgid="362972844525672568">"Seur."</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Valmis"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Lähetä"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
@@ -105,7 +107,7 @@
     <string name="voice_server_error" msgid="7807129913977261644">"Palvelinvirhe"</string>
     <string name="voice_speech_timeout" msgid="8461817525075498795">"Puhetta ei kuulu"</string>
     <string name="voice_no_match" msgid="4285117547030179174">"Ei vastineita"</string>
-    <string name="voice_not_installed" msgid="5552450909753842415">"Äänihakua ei asennettu"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Puhehakua ei asennettu"</string>
     <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Vihje:"</b>" liu\'uta sormea näppäimistöllä ja puhu"</string>
     <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Vihje:"</b>" kokeile seuraavalla kerralla puhua välimerkit, kuten \"period\" (piste), \"comma\" (pilkku) tai \"question mark\" (kysymysmerkki)."</string>
     <string name="cancel" msgid="6830980399865683324">"Peruuta"</string>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index 4eaac40..e9536ec 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : enregistré"</string>
     <string name="label_go_key" msgid="1635148082137219148">"OK"</string>
     <string name="label_next_key" msgid="362972844525672568">"Suiv."</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"OK"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Envoi"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index 229bb8a..6b17d67 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: सहेजा गया"</string>
     <string name="label_go_key" msgid="1635148082137219148">"जाएं"</string>
     <string name="label_next_key" msgid="362972844525672568">"अगला"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"पूर्ण"</string>
     <string name="label_send_key" msgid="2815056534433717444">"भेजें"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index 8fa730f..1d35c61 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Spremljeno"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Idi"</string>
     <string name="label_next_key" msgid="362972844525672568">"Dalje"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Gotovo"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Pošalji"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
index f397e0b..de2e812 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : mentve"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Ugrás"</string>
     <string name="label_next_key" msgid="362972844525672568">"Tovább"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Kész"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Küldés"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
index 6096cc1..92b4856 100644
--- a/java/res/values-in/strings.xml
+++ b/java/res/values-in/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Telah disimpan"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Buka"</string>
     <string name="label_next_key" msgid="362972844525672568">"Berikutnya"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Selesai"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Kirimkan"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml
index 6c34bee..38e622c 100644
--- a/java/res/values-it/strings.xml
+++ b/java/res/values-it/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : parola salvata"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Vai"</string>
     <string name="label_next_key" msgid="362972844525672568">"Avanti"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Fine"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Invia"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-iw/donottranslate-more-keys.xml b/java/res/values-iw/donottranslate-more-keys.xml
index 6fc3360..f44ff21 100644
--- a/java/res/values-iw/donottranslate-more-keys.xml
+++ b/java/res/values-iw/donottranslate-more-keys.xml
@@ -22,12 +22,12 @@
     <string name="more_keys_for_plus">±,﬩</string>
     <!-- The all letters need to be mirrored are found at
          http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt -->
-    <string name="output_text_for_left_parenthesis">)</string>
-    <string name="output_text_for_right_parenthesis">(</string>
+    <integer name="keycode_for_left_parenthesis">0x0029</integer>
+    <integer name="keycode_for_right_parenthesis">0x0028</integer>
     <string name="more_keys_for_left_parenthesis">[|],{|},&lt;|&gt;</string>
     <string name="more_keys_for_right_parenthesis">]|[,}|{,&gt;|&lt;</string>
-    <string name="output_text_for_less_than">&gt;</string>
-    <string name="output_text_for_greater_than">&lt;</string>
+    <integer name="keycode_for_less_than">0x003e</integer>
+    <integer name="keycode_for_greater_than">0x003c</integer>
     <!-- \u2264: LESS-THAN OR EQUAL TO
          \u2265: GREATER-THAN EQUAL TO
          \u00ab: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
@@ -45,10 +45,10 @@
          \u201f: DOUBLE HIGH-REVERSED-9 QUOTATION MARK -->
     <string name="more_keys_for_less_than">\u2264|\u2265,\u00ab|\u00bb,\u2039|\u203a</string>
     <string name="more_keys_for_greater_than">\u2265|\u2264,\u00bb|\u00ab,\u203a|\u2039</string>
-    <string name="output_text_for_left_square_bracket">]</string>
-    <string name="output_text_for_right_square_bracket">[</string>
-    <string name="output_text_for_left_curly_bracket">}</string>
-    <string name="output_text_for_right_curly_bracket">{</string>
+    <integer name="keycode_for_left_square_bracket">0x005d</integer>
+    <integer name="keycode_for_right_square_bracket">0x005b</integer>
+    <integer name="keycode_for_left_curly_bracket">0x007d</integer>
+    <integer name="keycode_for_right_curly_bracket">0x007b</integer>
     <!-- Note: Neither DroidSans nor Roboto have a glyph for DOUBLE HIGH-REVERSED-9 QUOTATION MARK. -->
     <!-- <string name="more_keys_for_double_quote">\u201c,\u201d,\u201e,\u201f,\u00ab,\u00bb</string> -->
     <!-- The 4-more keys will be displayed in order of "3,1,2,4". -->
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index dea0b41..9aeaffd 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : נשמרה"</string>
     <string name="label_go_key" msgid="1635148082137219148">"בצע"</string>
     <string name="label_next_key" msgid="362972844525672568">"הבא"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"סיום"</string>
     <string name="label_send_key" msgid="2815056534433717444">"שלח"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"אבג"</string>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index d6f967a..f684e21 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:保存しました"</string>
     <string name="label_go_key" msgid="1635148082137219148">"実行"</string>
     <string name="label_next_key" msgid="362972844525672568">"次へ"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"完了"</string>
     <string name="label_send_key" msgid="2815056534433717444">"送信"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
index 7382a0c..5670595 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: 저장됨"</string>
     <string name="label_go_key" msgid="1635148082137219148">"이동"</string>
     <string name="label_next_key" msgid="362972844525672568">"다음"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"완료"</string>
     <string name="label_send_key" msgid="2815056534433717444">"전송"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
index dcbfe46..f9cce83 100644
--- a/java/res/values-land/dimens.xml
+++ b/java/res/values-land/dimens.xml
@@ -66,7 +66,7 @@
     <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>
+    <dimen name="more_keys_keyboard_slide_allowance">0.336in</dimen>
     <!-- popup_key_height x -1.0 -->
-    <dimen name="mini_keyboard_vertical_correction">-0.280in</dimen>
+    <dimen name="more_keys_keyboard_vertical_correction">-0.280in</dimen>
 </resources>
diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml
index 646548d..93b52b5 100644
--- a/java/res/values-lt/strings.xml
+++ b/java/res/values-lt/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: išsaugota"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Pradėti"</string>
     <string name="label_next_key" msgid="362972844525672568">"Kitas"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Atlikta"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Siųsti"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
index b3406c3..6fc1d99 100644
--- a/java/res/values-lv/strings.xml
+++ b/java/res/values-lv/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: saglabāts"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Sākt"</string>
     <string name="label_next_key" msgid="362972844525672568">"Tālāk"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Gatavs"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Sūtīt"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml
index 2a9f516..e75cc80 100644
--- a/java/res/values-ms/strings.xml
+++ b/java/res/values-ms/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Disimpan"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Pergi"</string>
     <string name="label_next_key" msgid="362972844525672568">"Seterusnya"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Selesai"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Hantar"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
index 413c7ae..1141e33 100644
--- a/java/res/values-nb/strings.xml
+++ b/java/res/values-nb/strings.xml
@@ -65,6 +65,7 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: Lagret"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Gå"</string>
     <string name="label_next_key" msgid="362972844525672568">"Neste"</string>
+    <string name="label_previous_key" msgid="1211868118071386787">"Tidl."</string>
     <string name="label_done_key" msgid="2441578748772529288">"Utfør"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Send"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
index ba6dd40..6da587a 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: opgeslagen"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Start"</string>
     <string name="label_next_key" msgid="362972844525672568">"Verder"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Gereed"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Zenden"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
index 3ad3831..cda725b 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Zapisano"</string>
     <string name="label_go_key" msgid="1635148082137219148">"OK"</string>
     <string name="label_next_key" msgid="362972844525672568">"Dalej"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"OK"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Wyślij"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index ae7443a..52a497f 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: guardada"</string>
     <string name="label_go_key" msgid="1635148082137219148">"OK"</string>
     <string name="label_next_key" msgid="362972844525672568">"Avançar"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Feito"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index 16003f6..8d12189 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Salvo"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Ir"</string>
     <string name="label_next_key" msgid="362972844525672568">"Avançar"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Feito"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml
index 57173af..7138da4 100644
--- a/java/res/values-rm/strings.xml
+++ b/java/res/values-rm/strings.xml
@@ -100,6 +100,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Memorisà"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Dai"</string>
     <string name="label_next_key" msgid="362972844525672568">"Vinavant"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Finì"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Trametter"</string>
     <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index 3971dc8..b967eac 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: salvat"</string>
     <string name="label_go_key" msgid="1635148082137219148">"OK"</string>
     <string name="label_next_key" msgid="362972844525672568">"Înainte"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Terminat"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Trimiteţi"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index 62f84d4..13607ff 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: сохранено"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Поиск"</string>
     <string name="label_next_key" msgid="362972844525672568">"Далее"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Отправить"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"АБВ"</string>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
index 188c3b6..c9a5f00 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Uložené"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Hľadať"</string>
     <string name="label_next_key" msgid="362972844525672568">"Ďalej"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Hotovo"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Odoslať"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index cea30bb..c1e8a6f 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: shranjeno"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Pojdi"</string>
     <string name="label_next_key" msgid="362972844525672568">"Naprej"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Dokončano"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Pošlji"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index b66bf05..20279a8 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Сачувано"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Иди"</string>
     <string name="label_next_key" msgid="362972844525672568">"Следеће"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Пошаљи"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
index 06f706a..eb20073 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: sparat"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Kör"</string>
     <string name="label_next_key" msgid="362972844525672568">"Nästa"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Färdig"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Skicka"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml
index c50c910..9837540 100644
--- a/java/res/values-sw/strings.xml
+++ b/java/res/values-sw/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Imehifadhiwa"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Nenda"</string>
     <string name="label_next_key" msgid="362972844525672568">"Ifuatayo"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Kwisha"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Tuma"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw600dp/config.xml
index 40c6741..ecc5b71 100644
--- a/java/res/values-sw600dp/config.xml
+++ b/java/res/values-sw600dp/config.xml
@@ -39,6 +39,7 @@
         Configuration for LatinKeyboardView
     -->
     <bool name="config_sliding_key_input_enabled">false</bool>
-    <!-- Showing mini keyboard, just above the touched point if true, aligned to the key if false -->
-    <bool name="config_show_mini_keyboard_at_touched_point">true</bool>
+    <!-- Showing more keys keyboard, just above the touched point if true, aligned to the key if
+         false -->
+    <bool name="config_show_more_keys_keyboard_at_touched_point">true</bool>
 </resources>
diff --git a/java/res/values-sw600dp/dimens.xml b/java/res/values-sw600dp/dimens.xml
index e393be5..e04609f 100644
--- a/java/res/values-sw600dp/dimens.xml
+++ b/java/res/values-sw600dp/dimens.xml
@@ -40,12 +40,12 @@
 
     <fraction name="keyboard_bottom_padding_ics">0.0%p</fraction>
 
-    <dimen name="mini_keyboard_key_horizontal_padding">6dip</dimen>
+    <dimen name="more_keys_keyboard_key_horizontal_padding">6dip</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">15.6mm</dimen>
+    <dimen name="more_keys_keyboard_slide_allowance">15.6mm</dimen>
     <!-- popup_key_height x -1.0 -->
-    <dimen name="mini_keyboard_vertical_correction">-13.0mm</dimen>
+    <dimen name="more_keys_keyboard_vertical_correction">-13.0mm</dimen>
 
     <!-- left or right padding of label alignment -->
     <dimen name="key_label_horizontal_padding">6dip</dimen>
diff --git a/java/res/values-sw768dp/config.xml b/java/res/values-sw768dp/config.xml
index 98d722a..c1f9179 100644
--- a/java/res/values-sw768dp/config.xml
+++ b/java/res/values-sw768dp/config.xml
@@ -37,8 +37,9 @@
         Configuration for LatinKeyboardView
     -->
     <bool name="config_sliding_key_input_enabled">false</bool>
-    <!-- Showing mini keyboard, just above the touched point if true, aligned to the key if false -->
-    <bool name="config_show_mini_keyboard_at_touched_point">true</bool>
+    <!-- Showing more keys keyboard, just above the touched point if true, aligned to the key if
+         false -->
+    <bool name="config_show_more_keys_keyboard_at_touched_point">true</bool>
     <!--  Screen metrics for logging.
             0 = "mdpi phone screen"
             1 = "hdpi phone screen"
diff --git a/java/res/values-sw768dp/dimens.xml b/java/res/values-sw768dp/dimens.xml
index dbbd844..f33a657 100644
--- a/java/res/values-sw768dp/dimens.xml
+++ b/java/res/values-sw768dp/dimens.xml
@@ -43,12 +43,12 @@
 
     <dimen name="popup_key_height">10.0mm</dimen>
 
-    <dimen name="mini_keyboard_key_horizontal_padding">12dip</dimen>
+    <dimen name="more_keys_keyboard_key_horizontal_padding">12dip</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">15.6mm</dimen>
+    <dimen name="more_keys_keyboard_slide_allowance">15.6mm</dimen>
     <!-- popup_key_height x -1.0 -->
-    <dimen name="mini_keyboard_vertical_correction">-13.0mm</dimen>
+    <dimen name="more_keys_keyboard_vertical_correction">-13.0mm</dimen>
 
     <!-- left or right padding of label alignment -->
     <dimen name="key_label_horizontal_padding">6dip</dimen>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
index 64d6c3f..700361a 100644
--- a/java/res/values-th/strings.xml
+++ b/java/res/values-th/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : บันทึกแล้ว"</string>
     <string name="label_go_key" msgid="1635148082137219148">"ไป"</string>
     <string name="label_next_key" msgid="362972844525672568">"ถัดไป"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"เสร็จสิ้น"</string>
     <string name="label_send_key" msgid="2815056534433717444">"ส่ง"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
index 7f8f056..812d200 100644
--- a/java/res/values-tl/strings.xml
+++ b/java/res/values-tl/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Na-save"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Punta"</string>
     <string name="label_next_key" msgid="362972844525672568">"Susunod"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Tapos na"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Ipadala"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index 1295fb6..d67def9 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Kaydedildi"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Git"</string>
     <string name="label_next_key" msgid="362972844525672568">"İleri"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Bitti"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Gönder"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
index 4716800..71ae6d1 100644
--- a/java/res/values-uk/strings.xml
+++ b/java/res/values-uk/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : збережено"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Іти"</string>
     <string name="label_next_key" msgid="362972844525672568">"Далі"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Надісл."</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"Алфавіт"</string>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
index 343a12a..7d6a854 100644
--- a/java/res/values-vi/strings.xml
+++ b/java/res/values-vi/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Đã lưu"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Tìm"</string>
     <string name="label_next_key" msgid="362972844525672568">"Tiếp theo"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Xong"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Gửi"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index a2a0928..6572926 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已保存"</string>
     <string name="label_go_key" msgid="1635148082137219148">"开始"</string>
     <string name="label_next_key" msgid="362972844525672568">"下一步"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"完成"</string>
     <string name="label_send_key" msgid="2815056534433717444">"发送"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index f393589..5ac3a38 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>:已儲存"</string>
     <string name="label_go_key" msgid="1635148082137219148">"開始"</string>
     <string name="label_next_key" msgid="362972844525672568">"繼續"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"完成"</string>
     <string name="label_send_key" msgid="2815056534433717444">"傳送"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml
index d1dbeac..012bf7f 100644
--- a/java/res/values-zu/strings.xml
+++ b/java/res/values-zu/strings.xml
@@ -65,6 +65,8 @@
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Kulondoloziwe"</string>
     <string name="label_go_key" msgid="1635148082137219148">"Iya"</string>
     <string name="label_next_key" msgid="362972844525672568">"Okulandelayo"</string>
+    <!-- no translation found for label_previous_key (1211868118071386787) -->
+    <skip />
     <string name="label_done_key" msgid="2441578748772529288">"Kwenziwe"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Thumela"</string>
     <string name="label_to_alpha_key" msgid="4793983863798817523">"ABC"</string>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 410a942..2dea8fb 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -25,11 +25,11 @@
         <attr name="keyboardViewStyle" format="reference" />
         <!-- LatinKeyboardView style -->
         <attr name="latinKeyboardViewStyle" format="reference" />
-        <!-- MiniKeyboard style -->
-        <attr name="miniKeyboardStyle" format="reference" />
-        <!-- MiniKeyboardView style -->
-        <attr name="miniKeyboardViewStyle" format="reference" />
-        <attr name="miniKeyboardPanelStyle" format="reference" />
+        <!-- MoreKeysKeyboard style -->
+        <attr name="moreKeysKeyboardStyle" format="reference" />
+        <!-- MoreKeysKeyboardView style -->
+        <attr name="moreKeysKeyboardViewStyle" format="reference" />
+        <attr name="moreKeysKeyboardPanelStyle" format="reference" />
         <!-- Suggestions strip style -->
         <attr name="suggestionsStripBackgroundStyle" format="reference" />
         <attr name="suggestionsViewStyle" format="reference" />
@@ -152,8 +152,8 @@
         <attr name="longPressSpaceKeyTimeout" format="integer" />
         <!-- Ignore special key timeout while typing in millisecond. -->
         <attr name="ignoreSpecialKeyTimeout" format="integer" />
-        <!-- Mini-keyboard will shown at touched point. -->
-        <attr name="showMiniKeyboardAtTouchedPoint" format="boolean" />
+        <!-- More keys keyboard will shown at touched point. -->
+        <attr name="showMoreKeysKeyboardAtTouchedPoint" format="boolean" />
     </declare-styleable>
 
     <declare-styleable name="SuggestionsView">
@@ -278,10 +278,13 @@
             <!-- If true, use keyShiftedLetterHintActivatedColor for the shifted letter hint and
                  keyTextInactivatedColor for the primary key top label. -->
             <flag name="shiftedLetterActivated" value="0x10000" />
+            <!-- If true, use EditorInfo.actionLabel for the key label. -->
+            <flag name="fromCustomActionLabel" value="0x20000" />
         </attr>
         <!-- The icon to display on the key instead of the label. -->
         <attr name="keyIcon" format="enum">
             <!-- This should be aligned with the KeyboardIconsSet.ICON_* -->
+            <enum name="iconUndefined" value="0" />
             <enum name="iconShiftKey" value="1" />
             <enum name="iconDeleteKey" value="2" />
             <enum name="iconSettingsKey" value="3" />
@@ -365,6 +368,7 @@
         <attr name="clobberSettingsKey" format="boolean" />
         <attr name="shortcutKeyEnabled" format="boolean" />
         <attr name="hasShortcutKey" format="boolean" />
+        <attr name="isMultiLine" format="boolean" />
         <attr name="imeAction" format="enum">
             <!-- This should be aligned with EditorInfo.IME_ACTION_* -->
             <enum name="actionUnspecified" value="0" />
@@ -375,6 +379,8 @@
             <enum name="actionNext" value="5" />
             <enum name="actionDone" value="6" />
             <enum name="actionPrevious" value="7" />
+            <!--  This should be aligned with KeyboardId.IME_ACTION_* -->
+            <enum name="actionCustomLabel" value="0x100" />
         </attr>
         <attr name="localeCode" format="string" />
         <attr name="languageCode" format="string" />
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index c3f8edf..cb13ba3 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -44,8 +44,8 @@
     <integer name="config_delay_update_shift_state">100</integer>
     <integer name="config_duration_of_fadeout_language_on_spacebar">50</integer>
     <integer name="config_final_fadeout_percentage_of_language_on_spacebar">50</integer>
-    <integer name="config_mini_keyboard_fadein_anim_time">0</integer>
-    <integer name="config_mini_keyboard_fadeout_anim_time">100</integer>
+    <integer name="config_more_keys_keyboard_fadein_anim_time">0</integer>
+    <integer name="config_more_keys_keyboard_fadeout_anim_time">100</integer>
     <integer name="config_keyboard_grid_width">32</integer>
     <integer name="config_keyboard_grid_height">16</integer>
     <integer name="config_double_spaces_turn_into_period_timeout">1100</integer>
@@ -69,10 +69,12 @@
     <!-- Long pressing shift will invoke caps-lock if > 0, never invoke caps-lock if == 0 -->
     <integer name="config_long_press_shift_key_timeout">1200</integer>
     <!-- Long pressing space will invoke IME switcher if > 0, never invoke IME switcher if == 0 -->
-    <integer name="config_long_press_space_key_timeout">@integer/config_long_press_key_timeout</integer>
+    <integer name="config_long_press_space_key_timeout">
+            @integer/config_long_press_key_timeout</integer>
     <integer name="config_ignore_special_key_timeout">700</integer>
-    <!-- Showing mini keyboard, just above the touched point if true, aligned to the key if false -->
-    <bool name="config_show_mini_keyboard_at_touched_point">false</bool>
+    <!-- Showing more keys keyboard, just above the touched point if true, aligned to the key if
+         false -->
+    <bool name="config_show_more_keys_keyboard_at_touched_point">false</bool>
     <!--
         Configuration for auto correction
      -->
@@ -88,9 +90,11 @@
              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 "recommended" -->
+    <!-- Threshold of the normalized score of the best suggestion for the spell checker to declare
+         a word to be "recommended" -->
     <string name="spellchecker_recommended_threshold_value" translatable="false">0.11</string>
-    <!-- Threshold of the normalized score of any dictionary lookup to be offered as a suggestion by the spell checker -->
+    <!-- Threshold of the normalized score of any dictionary lookup to be offered as a suggestion
+         by the spell checker -->
     <string name="spellchecker_suggestion_threshold_value" translatable="false">0.03</string>
     <!--  Screen metrics for logging.
             0 = "mdpi phone screen"
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 95c4e5b..41a2979 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -26,8 +26,8 @@
 
     <dimen name="popup_key_height">0.330in</dimen>
 
-    <dimen name="mini_keyboard_horizontal_edges_padding">16dip</dimen>
-    <dimen name="mini_keyboard_key_horizontal_padding">8dip</dimen>
+    <dimen name="more_keys_keyboard_horizontal_edges_padding">16dip</dimen>
+    <dimen name="more_keys_keyboard_key_horizontal_padding">8dip</dimen>
 
     <fraction name="keyboard_top_padding">1.556%p</fraction>
     <fraction name="keyboard_bottom_padding">4.669%p</fraction>
@@ -48,13 +48,13 @@
     <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">4dip</dimen>
+    <dimen name="more_keys_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 -->
-    <dimen name="mini_keyboard_slide_allowance">0.396in</dimen>
+    <dimen name="more_keys_keyboard_slide_allowance">0.396in</dimen>
     <!-- popup_key_height x -1.0 -->
-    <dimen name="mini_keyboard_vertical_correction">-0.330in</dimen>
+    <dimen name="more_keys_keyboard_vertical_correction">-0.330in</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.0in</dimen>
diff --git a/java/res/values/donottranslate-more-keys.xml b/java/res/values/donottranslate-more-keys.xml
index d7b1ff5..57a6d6b 100644
--- a/java/res/values/donottranslate-more-keys.xml
+++ b/java/res/values/donottranslate-more-keys.xml
@@ -56,7 +56,7 @@
     <string name="more_keys_for_currency_general">¢,$,€,£,¥,₱</string>
     <string name="more_keys_for_smiley">":-)|:-) ,:-(|:-( ,;-)|;-) ,:-P|:-P ,=-O|=-O ,:-*|:-* ,:O|:O ,B-)|B-) ,:-$|:-$ ,:-!|:-! ,:-[|:-[ ,O:-)|O:-) ,:-\\\\|:-\\\\ ,:\'(|:\'( ,:-D|:-D "</string>
     <string name="more_keys_for_punctuation">"\\,,\?,!,:,-,\',\",(,),/,;,+,&amp;,\@"</string>
-    <integer name="mini_keyboard_column_for_punctuation">7</integer>
+    <integer name="more_keys_keyboard_column_for_punctuation">7</integer>
     <string name="keyhintlabel_for_punctuation"></string>
     <string name="keylabel_for_popular_domain">".com"</string>
     <!-- popular web domains for the locale - most popular, displayed on the keyboard -->
@@ -114,12 +114,12 @@
     <string name="more_keys_for_plus">±</string>
     <!-- The all letters need to be mirrored are found at
          http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt -->
-    <string name="output_text_for_left_parenthesis">(</string>
-    <string name="output_text_for_right_parenthesis">)</string>
+    <integer name="keycode_for_left_parenthesis">0x0028</integer>
+    <integer name="keycode_for_right_parenthesis">0x0029</integer>
     <string name="more_keys_for_left_parenthesis">[,{,&lt;</string>
     <string name="more_keys_for_right_parenthesis">],},&gt;</string>
-    <string name="output_text_for_less_than">&lt;</string>
-    <string name="output_text_for_greater_than">&gt;</string>
+    <integer name="keycode_for_less_than">0x003c</integer>
+    <integer name="keycode_for_greater_than">0x003e</integer>
     <!-- \u2264: LESS-THAN OR EQUAL TO
          \u2265: GREATER-THAN EQUAL TO
          \u00ab: LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
@@ -137,10 +137,10 @@
          \u201f: DOUBLE HIGH-REVERSED-9 QUOTATION MARK -->
     <string name="more_keys_for_less_than">\u2264,\u00ab,\u2039</string>
     <string name="more_keys_for_greater_than">\u2265,\u00bb,\u203a</string>
-    <string name="output_text_for_left_square_bracket">[</string>
-    <string name="output_text_for_right_square_bracket">]</string>
-    <string name="output_text_for_left_curly_bracket">{</string>
-    <string name="output_text_for_right_curly_bracket">}</string>
+    <integer name="keycode_for_left_square_bracket">0x005b</integer>
+    <integer name="keycode_for_right_square_bracket">0x005d</integer>
+    <integer name="keycode_for_left_curly_bracket">0x007b</integer>
+    <integer name="keycode_for_right_curly_bracket">0x007d</integer>
     <!-- The 4-more keys will be displayed in order of "3,1,2,4". -->
     <string name="more_keys_for_single_quote">\u2019,\u201a,\u2018,\u201b</string>
     <!-- Note: Neither DroidSans nor Roboto have a glyph for DOUBLE HIGH-REVERSED-9 QUOTATION MARK. -->
diff --git a/java/res/values/keycodes.xml b/java/res/values/keycodes.xml
index 2a91a3d..c85c022 100644
--- a/java/res/values/keycodes.xml
+++ b/java/res/values/keycodes.xml
@@ -21,13 +21,14 @@
 <resources>
     <!-- These code should be aligned with Keyboard.CODE_*. -->
     <integer name="key_tab">9</integer>
-    <integer name="key_return">10</integer>
+    <integer name="key_enter">10</integer>
     <integer name="key_space">32</integer>
     <integer name="key_shift">-1</integer>
     <integer name="key_switch_alpha_symbol">-2</integer>
-    <integer name="key_output_text">-4</integer>
-    <integer name="key_delete">-5</integer>
-    <integer name="key_settings">-6</integer>
-    <integer name="key_shortcut">-7</integer>
+    <integer name="key_output_text">-3</integer>
+    <integer name="key_delete">-4</integer>
+    <integer name="key_settings">-5</integer>
+    <integer name="key_shortcut">-6</integer>
+    <integer name="key_action_enter">-7</integer>
     <integer name="key_unspecified">-9</integer>
 </resources>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 95e50ef..1e8b7db 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -128,6 +128,8 @@
     <string name="label_go_key">Go</string>
     <!-- Label for soft enter key when it performs NEXT action.  Must be short to fit on key! [CHAR LIMIT=5] -->
     <string name="label_next_key">Next</string>
+    <!-- Label for soft enter key when it performs PREVIOUS action.  Must be short to fit on key! [CHAR LIMIT=5] -->
+    <string name="label_previous_key">Prev</string>
     <!-- Label for soft enter key when it performs DONE action.  Must be short to fit on key! [CHAR LIMIT=5] -->
     <string name="label_done_key">Done</string>
     <!-- Label for soft enter key when it performs SEND action.  Must be short to fit on key! [CHAR LIMIT=5] -->
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index f690782..b9e8b26 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -23,7 +23,7 @@
         <item name="keyboardHeight">@dimen/keyboardHeight</item>
         <item name="maxKeyboardHeight">@fraction/maxKeyboardHeight</item>
         <item name="minKeyboardHeight">@fraction/minKeyboardHeight</item>
-        <item name="moreKeysTemplate">@xml/kbd_mini_keyboard_template</item>
+        <item name="moreKeysTemplate">@xml/kbd_more_keys_keyboard_template</item>
         <item name="keyboardTopPadding">@fraction/keyboard_top_padding</item>
         <item name="keyboardBottomPadding">@fraction/keyboard_bottom_padding</item>
         <item name="keyboardHorizontalEdgesPadding">@fraction/keyboard_horizontal_edges_padding</item>
@@ -60,7 +60,7 @@
         <item name="keyPreviewHeight">@dimen/key_preview_height</item>
         <item name="keyPreviewTextRatio">@fraction/key_preview_text_ratio</item>
         <item name="keyPreviewLingerTimeout">@integer/config_key_preview_linger_timeout</item>
-        <item name="moreKeysLayout">@layout/mini_keyboard</item>
+        <item name="moreKeysLayout">@layout/more_keys_keyboard</item>
         <item name="verticalCorrection">@dimen/keyboard_vertical_correction</item>
         <item name="shadowColor">#BB000000</item>
         <item name="shadowRadius">2.75</item>
@@ -76,7 +76,7 @@
         <item name="longPressShiftKeyTimeout">@integer/config_long_press_shift_key_timeout</item>
         <item name="longPressSpaceKeyTimeout">@integer/config_long_press_space_key_timeout</item>
         <item name="ignoreSpecialKeyTimeout">@integer/config_ignore_special_key_timeout</item>
-        <item name="showMiniKeyboardAtTouchedPoint">@bool/config_show_mini_keyboard_at_touched_point</item>
+        <item name="showMoreKeysKeyboardAtTouchedPoint">@bool/config_show_more_keys_keyboard_at_touched_point</item>
     </style>
     <style
         name="LatinKeyboardView"
@@ -88,7 +88,7 @@
         <item name="spacebarTextShadowColor">#80000000</item>
     </style>
     <style
-        name="MiniKeyboard"
+        name="MoreKeysKeyboard"
         parent="Keyboard"
     >
         <item name="keyboardTopPadding">0dip</item>
@@ -96,16 +96,16 @@
         <item name="horizontalGap">0dip</item>
     </style>
     <style
-        name="MiniKeyboardView"
+        name="MoreKeysKeyboardView"
         parent="KeyboardView"
     >
         <item name="keyBackground">@drawable/btn_keyboard_key_popup</item>
-        <item name="verticalCorrection">@dimen/mini_keyboard_vertical_correction</item>
+        <item name="verticalCorrection">@dimen/more_keys_keyboard_vertical_correction</item>
     </style>
-    <style name="MiniKeyboardPanelStyle">
+    <style name="MoreKeysKeyboardPanelStyle">
         <item name="android:background">@drawable/keyboard_popup_panel_background</item>
-        <item name="android:paddingLeft">@dimen/mini_keyboard_horizontal_edges_padding</item>
-        <item name="android:paddingRight">@dimen/mini_keyboard_horizontal_edges_padding</item>
+        <item name="android:paddingLeft">@dimen/more_keys_keyboard_horizontal_edges_padding</item>
+        <item name="android:paddingRight">@dimen/more_keys_keyboard_horizontal_edges_padding</item>
     </style>
     <style name="SuggestionsStripBackgroundStyle">
         <item name="android:background">@drawable/keyboard_suggest_strip</item>
@@ -127,7 +127,7 @@
     </style>
     <style
         name="MoreSuggestionsViewStyle"
-        parent="MiniKeyboardView"
+        parent="MoreKeysKeyboardView"
     >
     </style>
     <style name="SuggestionBackgroundStyle">
@@ -196,7 +196,7 @@
         <item name="spacebarTextShadowColor">#D0FFFFFF</item>
     </style>
     <style
-        name="MiniKeyboard.Stone"
+        name="MoreKeysKeyboard.Stone"
         parent="Keyboard.Stone"
     >
         <item name="keyboardTopPadding">0dip</item>
@@ -204,8 +204,8 @@
         <item name="horizontalGap">0dip</item>
     </style>
     <style
-        name="MiniKeyboardView.Stone"
-        parent="MiniKeyboardView"
+        name="MoreKeysKeyboardView.Stone"
+        parent="MoreKeysKeyboardView"
     >
         <item name="keyBackground">@drawable/btn_keyboard_key_stone</item>
         <item name="keyTextColor">#FF000000</item>
@@ -263,7 +263,7 @@
         <item name="spacebarTextShadowColor">#80000000</item>
     </style>
     <style
-        name="MiniKeyboard.Gingerbread"
+        name="MoreKeysKeyboard.Gingerbread"
         parent="Keyboard.Gingerbread"
     >
         <item name="keyboardTopPadding">0dip</item>
@@ -271,8 +271,8 @@
         <item name="horizontalGap">0dip</item>
     </style>
     <style
-        name="MiniKeyboardView.Gingerbread"
-        parent="MiniKeyboardView"
+        name="MoreKeysKeyboardView.Gingerbread"
+        parent="MoreKeysKeyboardView"
     >
         <item name="android:background">@null</item>
     </style>
@@ -322,7 +322,7 @@
         <item name="spacebarTextShadowColor">#80000000</item>
     </style>
     <style
-        name="MiniKeyboard.IceCreamSandwich"
+        name="MoreKeysKeyboard.IceCreamSandwich"
         parent="Keyboard.IceCreamSandwich"
     >
         <item name="keyboardTopPadding">0dip</item>
@@ -330,16 +330,16 @@
         <item name="horizontalGap">0dip</item>
     </style>
     <style
-        name="MiniKeyboardView.IceCreamSandwich"
-        parent="MiniKeyboardView"
+        name="MoreKeysKeyboardView.IceCreamSandwich"
+        parent="MoreKeysKeyboardView"
     >
         <item name="android:background">@null</item>
         <item name="keyBackground">@drawable/btn_keyboard_key_popup_ics</item>
     </style>
-    <style name="MiniKeyboardPanelStyle.IceCreamSandwich">
+    <style name="MoreKeysKeyboardPanelStyle.IceCreamSandwich">
         <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>
+        <item name="android:paddingLeft">@dimen/more_keys_keyboard_horizontal_edges_padding_ics</item>
+        <item name="android:paddingRight">@dimen/more_keys_keyboard_horizontal_edges_padding_ics</item>
     </style>
     <style name="SuggestionsStripBackgroundStyle.IceCreamSandwich">
         <item name="android:background">@drawable/keyboard_suggest_strip_holo</item>
@@ -365,7 +365,7 @@
     </style>
     <style
         name="MoreSuggestionsViewStyle.IceCreamSandwich"
-        parent="MiniKeyboardView.IceCreamSandwich"
+        parent="MoreKeysKeyboardView.IceCreamSandwich"
     >
     </style>
     <style name="SuggestionBackgroundStyle.IceCreamSandwich">
@@ -373,11 +373,11 @@
     </style>
     <style
         name="SuggestionPreviewBackgroundStyle.IceCreamSandwich"
-        parent="MiniKeyboardPanelStyle.IceCreamSandwich"
+        parent="MoreKeysKeyboardPanelStyle.IceCreamSandwich"
     >
     </style>
-    <style name="MiniKeyboardAnimation">
-        <item name="android:windowEnterAnimation">@anim/mini_keyboard_fadein</item>
-        <item name="android:windowExitAnimation">@anim/mini_keyboard_fadeout</item>
+    <style name="MoreKeysKeyboardAnimation">
+        <item name="android:windowEnterAnimation">@anim/more_keys_keyboard_fadein</item>
+        <item name="android:windowExitAnimation">@anim/more_keys_keyboard_fadeout</item>
     </style>
 </resources>
diff --git a/java/res/values/themes-basic-highcontrast.xml b/java/res/values/themes-basic-highcontrast.xml
index 0062b28..19df42c 100644
--- a/java/res/values/themes-basic-highcontrast.xml
+++ b/java/res/values/themes-basic-highcontrast.xml
@@ -19,9 +19,9 @@
         <item name="keyboardStyle">@style/Keyboard.HighContrast</item>
         <item name="keyboardViewStyle">@style/KeyboardView.HighContrast</item>
         <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.HighContrast</item>
-        <item name="miniKeyboardStyle">@style/MiniKeyboard</item>
-        <item name="miniKeyboardViewStyle">@style/MiniKeyboardView</item>
-        <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
+        <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard</item>
+        <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView</item>
+        <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item>
         <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
         <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
         <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
diff --git a/java/res/values/themes-basic.xml b/java/res/values/themes-basic.xml
index 0786e08..5d47720 100644
--- a/java/res/values/themes-basic.xml
+++ b/java/res/values/themes-basic.xml
@@ -19,9 +19,9 @@
         <item name="keyboardStyle">@style/Keyboard</item>
         <item name="keyboardViewStyle">@style/KeyboardView</item>
         <item name="latinKeyboardViewStyle">@style/LatinKeyboardView</item>
-        <item name="miniKeyboardStyle">@style/MiniKeyboard</item>
-        <item name="miniKeyboardViewStyle">@style/MiniKeyboardView</item>
-        <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
+        <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard</item>
+        <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView</item>
+        <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item>
         <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
         <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
         <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
diff --git a/java/res/values/themes-gingerbread.xml b/java/res/values/themes-gingerbread.xml
index 44338d8..a139798 100644
--- a/java/res/values/themes-gingerbread.xml
+++ b/java/res/values/themes-gingerbread.xml
@@ -19,9 +19,9 @@
         <item name="keyboardStyle">@style/Keyboard.Gingerbread</item>
         <item name="keyboardViewStyle">@style/KeyboardView.Gingerbread</item>
         <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.Gingerbread</item>
-        <item name="miniKeyboardStyle">@style/MiniKeyboard.Gingerbread</item>
-        <item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Gingerbread</item>
-        <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
+        <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.Gingerbread</item>
+        <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.Gingerbread</item>
+        <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item>
         <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
         <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
         <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml
index dbc8f32..e6fd4f4 100644
--- a/java/res/values/themes-ics.xml
+++ b/java/res/values/themes-ics.xml
@@ -19,9 +19,9 @@
         <item name="keyboardStyle">@style/Keyboard.IceCreamSandwich</item>
         <item name="keyboardViewStyle">@style/KeyboardView.IceCreamSandwich</item>
         <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.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="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.IceCreamSandwich</item>
+        <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.IceCreamSandwich</item>
+        <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle.IceCreamSandwich</item>
         <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle.IceCreamSandwich</item>
         <item name="suggestionsViewStyle">@style/SuggestionsViewStyle.IceCreamSandwich</item>
         <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle.IceCreamSandwich</item>
diff --git a/java/res/values/themes-stone-bold.xml b/java/res/values/themes-stone-bold.xml
index 60f130d..47de99e 100644
--- a/java/res/values/themes-stone-bold.xml
+++ b/java/res/values/themes-stone-bold.xml
@@ -19,9 +19,9 @@
         <item name="keyboardStyle">@style/Keyboard.Stone.Bold</item>
         <item name="keyboardViewStyle">@style/KeyboardView.Stone.Bold</item>
         <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.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="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.Stone</item>
+        <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.Stone</item>
+        <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item>
         <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
         <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
         <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
diff --git a/java/res/values/themes-stone.xml b/java/res/values/themes-stone.xml
index 9aaca3a..a0b39e3 100644
--- a/java/res/values/themes-stone.xml
+++ b/java/res/values/themes-stone.xml
@@ -19,9 +19,9 @@
         <item name="keyboardStyle">@style/Keyboard.Stone</item>
         <item name="keyboardViewStyle">@style/KeyboardView.Stone</item>
         <item name="latinKeyboardViewStyle">@style/LatinKeyboardView.Stone</item>
-        <item name="miniKeyboardStyle">@style/MiniKeyboard.Stone</item>
-        <item name="miniKeyboardViewStyle">@style/MiniKeyboardView.Stone</item>
-        <item name="miniKeyboardPanelStyle">@style/MiniKeyboardPanelStyle</item>
+        <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.Stone</item>
+        <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.Stone</item>
+        <item name="moreKeysKeyboardPanelStyle">@style/MoreKeysKeyboardPanelStyle</item>
         <item name="suggestionsStripBackgroundStyle">@style/SuggestionsStripBackgroundStyle</item>
         <item name="suggestionsViewStyle">@style/SuggestionsViewStyle</item>
         <item name="moreSuggestionsViewStyle">@style/MoreSuggestionsViewStyle</item>
diff --git a/java/res/xml-sw600dp-land/kbd_mini_keyboard_template.xml b/java/res/xml-sw600dp-land/kbd_more_keys_keyboard_template.xml
similarity index 95%
rename from java/res/xml-sw600dp-land/kbd_mini_keyboard_template.xml
rename to java/res/xml-sw600dp-land/kbd_more_keys_keyboard_template.xml
index 8272e02..4d8b446 100644
--- a/java/res/xml-sw600dp-land/kbd_mini_keyboard_template.xml
+++ b/java/res/xml-sw600dp-land/kbd_more_keys_keyboard_template.xml
@@ -21,6 +21,6 @@
 <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
     latin:keyWidth="5%p"
     latin:rowHeight="@dimen/popup_key_height"
-    style="?attr/miniKeyboardStyle"
+    style="?attr/moreKeysKeyboardStyle"
     >
 </Keyboard>
diff --git a/java/res/xml-sw600dp/kbd_mini_keyboard_template.xml b/java/res/xml-sw600dp/kbd_more_keys_keyboard_template.xml
similarity index 95%
rename from java/res/xml-sw600dp/kbd_mini_keyboard_template.xml
rename to java/res/xml-sw600dp/kbd_more_keys_keyboard_template.xml
index 0d5795f..d90a588 100644
--- a/java/res/xml-sw600dp/kbd_mini_keyboard_template.xml
+++ b/java/res/xml-sw600dp/kbd_more_keys_keyboard_template.xml
@@ -21,6 +21,6 @@
 <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
     latin:keyWidth="8%p"
     latin:rowHeight="@dimen/popup_key_height"
-    style="?attr/miniKeyboardStyle"
+    style="?attr/moreKeysKeyboardStyle"
     >
 </Keyboard>
diff --git a/java/res/xml-sw600dp/key_styles_common.xml b/java/res/xml-sw600dp/key_styles_common.xml
index b554147..e524aa3 100644
--- a/java/res/xml-sw600dp/key_styles_common.xml
+++ b/java/res/xml-sw600dp/key_styles_common.xml
@@ -89,12 +89,8 @@
         latin:keyIcon="iconDeleteKey"
         latin:keyActionFlags="isRepeatable|noKeyPreview"
         latin:backgroundType="functional" />
-    <key-style
-        latin:styleName="returnKeyStyle"
-        latin:code="@integer/key_return"
-        latin:keyIcon="iconReturnKey"
-        latin:keyActionFlags="noKeyPreview"
-        latin:backgroundType="functional" />
+    <include
+        latin:keyboardLayout="@xml/key_styles_enter_tablet" />
     <key-style
         latin:styleName="spaceKeyStyle"
         latin:code="@integer/key_space"
@@ -115,6 +111,7 @@
         latin:code="@integer/key_shortcut"
         latin:keyIcon="iconShortcutKey"
         latin:keyIconDisabled="iconDisabledShortcutKey"
+        latin:keyLabelFlags="preserveCase"
         latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
         latin:parentStyle="f2PopupStyle" />
     <key-style
diff --git a/java/res/xml-sw600dp/row_qwerty2.xml b/java/res/xml-sw600dp/row_qwerty2.xml
index 52a948f..cabb9cb 100644
--- a/java/res/xml-sw600dp/row_qwerty2.xml
+++ b/java/res/xml-sw600dp/row_qwerty2.xml
@@ -50,7 +50,7 @@
             latin:keyLabel="l"
             latin:moreKeys="@string/more_keys_for_l" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-14.6%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw600dp/rows_arabic.xml b/java/res/xml-sw600dp/rows_arabic.xml
index 8d4901b..1f03968 100644
--- a/java/res/xml-sw600dp/rows_arabic.xml
+++ b/java/res/xml-sw600dp/rows_arabic.xml
@@ -138,7 +138,7 @@
         <Key
             latin:keyLabel="ط" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-14.6%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw600dp/rows_azerty.xml b/java/res/xml-sw600dp/rows_azerty.xml
index aabe6b0..5c79962 100644
--- a/java/res/xml-sw600dp/rows_azerty.xml
+++ b/java/res/xml-sw600dp/rows_azerty.xml
@@ -90,7 +90,7 @@
         <Key
             latin:keyLabel="m" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-14.6%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw600dp/rows_bulgarian.xml b/java/res/xml-sw600dp/rows_bulgarian.xml
index b464158..7a23ce9 100644
--- a/java/res/xml-sw600dp/rows_bulgarian.xml
+++ b/java/res/xml-sw600dp/rows_bulgarian.xml
@@ -80,7 +80,7 @@
         <Key
             latin:keyLabel="ь" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyWidth="fillBoth" />
     </Row>
     <Row
diff --git a/java/res/xml-sw600dp/rows_hebrew.xml b/java/res/xml-sw600dp/rows_hebrew.xml
index 71fb463..812e2d6 100644
--- a/java/res/xml-sw600dp/rows_hebrew.xml
+++ b/java/res/xml-sw600dp/rows_hebrew.xml
@@ -106,7 +106,7 @@
             latin:keyLabel="ץ"
             latin:moreKeys="ץ׳" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-10.400%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw600dp/rows_number_normal.xml b/java/res/xml-sw600dp/rows_number_normal.xml
index f7eb950..3141bbd 100644
--- a/java/res/xml-sw600dp/rows_number_normal.xml
+++ b/java/res/xml-sw600dp/rows_number_normal.xml
@@ -78,7 +78,7 @@
             latin:keyLabel="6"
             latin:keyStyle="numKeyStyle" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-11.00%p"
             latin:keyWidth="fillRight" />
     </Row>
diff --git a/java/res/xml-sw600dp/rows_number_password.xml b/java/res/xml-sw600dp/rows_number_password.xml
index c3f21e1..0a71f74 100644
--- a/java/res/xml-sw600dp/rows_number_password.xml
+++ b/java/res/xml-sw600dp/rows_number_password.xml
@@ -47,7 +47,7 @@
         <Key
             latin:keyStyle="num6KeyStyle" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-11.00%p"
             latin:keyWidth="fillRight" />
     </Row>
diff --git a/java/res/xml-sw600dp/rows_phone.xml b/java/res/xml-sw600dp/rows_phone.xml
index fe85119..d61b4b2 100644
--- a/java/res/xml-sw600dp/rows_phone.xml
+++ b/java/res/xml-sw600dp/rows_phone.xml
@@ -75,7 +75,7 @@
         <Key
             latin:keyStyle="num6KeyStyle" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-11.00%p"
             latin:keyWidth="fillRight" />
     </Row>
diff --git a/java/res/xml-sw600dp/rows_scandinavian.xml b/java/res/xml-sw600dp/rows_scandinavian.xml
index 5ecb7d2..912c406 100644
--- a/java/res/xml-sw600dp/rows_scandinavian.xml
+++ b/java/res/xml-sw600dp/rows_scandinavian.xml
@@ -95,7 +95,7 @@
             latin:keyLabel="@string/keylabel_for_scandinavia_row2_11"
             latin:moreKeys="@string/more_keys_for_scandinavia_row2_11" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-14.6%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw600dp/rows_serbian.xml b/java/res/xml-sw600dp/rows_serbian.xml
index c21fd4c..ea4bb14 100644
--- a/java/res/xml-sw600dp/rows_serbian.xml
+++ b/java/res/xml-sw600dp/rows_serbian.xml
@@ -80,7 +80,7 @@
         <Key
             latin:keyLabel="ћ" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-14.6%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw600dp/rows_slavic.xml b/java/res/xml-sw600dp/rows_slavic.xml
index 889a438..020ea16 100644
--- a/java/res/xml-sw600dp/rows_slavic.xml
+++ b/java/res/xml-sw600dp/rows_slavic.xml
@@ -87,7 +87,7 @@
         <Key
             latin:keyLabel="э" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-14.6%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw600dp/rows_spanish.xml b/java/res/xml-sw600dp/rows_spanish.xml
index b516beb..2ab94e8 100644
--- a/java/res/xml-sw600dp/rows_spanish.xml
+++ b/java/res/xml-sw600dp/rows_spanish.xml
@@ -56,7 +56,7 @@
         <Key
             latin:keyLabel="ñ" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-14.6%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw600dp/rows_symbols.xml b/java/res/xml-sw600dp/rows_symbols.xml
index c2dfe2f..ce6e539 100644
--- a/java/res/xml-sw600dp/rows_symbols.xml
+++ b/java/res/xml-sw600dp/rows_symbols.xml
@@ -98,7 +98,7 @@
         <include
             latin:keyboardLayout="@xml/keys_parentheses" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-14.6%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw600dp/rows_symbols_shift.xml b/java/res/xml-sw600dp/rows_symbols_shift.xml
index 6a640c0..a10d174 100644
--- a/java/res/xml-sw600dp/rows_symbols_shift.xml
+++ b/java/res/xml-sw600dp/rows_symbols_shift.xml
@@ -80,7 +80,7 @@
         <include
             latin:keyboardLayout="@xml/keys_curly_brackets" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-14.6%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw768dp-land/kbd_mini_keyboard_template.xml b/java/res/xml-sw768dp-land/kbd_more_keys_keyboard_template.xml
similarity index 95%
rename from java/res/xml-sw768dp-land/kbd_mini_keyboard_template.xml
rename to java/res/xml-sw768dp-land/kbd_more_keys_keyboard_template.xml
index 85e864a..f593fa9 100644
--- a/java/res/xml-sw768dp-land/kbd_mini_keyboard_template.xml
+++ b/java/res/xml-sw768dp-land/kbd_more_keys_keyboard_template.xml
@@ -21,6 +21,6 @@
 <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
     latin:keyWidth="3.5%p"
     latin:rowHeight="@dimen/popup_key_height"
-    style="?attr/miniKeyboardStyle"
+    style="?attr/moreKeysKeyboardStyle"
     >
 </Keyboard>
diff --git a/java/res/xml-sw768dp/kbd_mini_keyboard_template.xml b/java/res/xml-sw768dp/kbd_more_keys_keyboard_template.xml
similarity index 95%
rename from java/res/xml-sw768dp/kbd_mini_keyboard_template.xml
rename to java/res/xml-sw768dp/kbd_more_keys_keyboard_template.xml
index 409c605..f89a0a6 100644
--- a/java/res/xml-sw768dp/kbd_mini_keyboard_template.xml
+++ b/java/res/xml-sw768dp/kbd_more_keys_keyboard_template.xml
@@ -21,6 +21,6 @@
 <Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
     latin:keyWidth="5.0%p"
     latin:rowHeight="@dimen/popup_key_height"
-    style="?attr/miniKeyboardStyle"
+    style="?attr/moreKeysKeyboardStyle"
     >
 </Keyboard>
diff --git a/java/res/xml-sw768dp/key_styles_common.xml b/java/res/xml-sw768dp/key_styles_common.xml
index 0d2ac5d..07bdd7b 100644
--- a/java/res/xml-sw768dp/key_styles_common.xml
+++ b/java/res/xml-sw768dp/key_styles_common.xml
@@ -71,12 +71,8 @@
         latin:keyIcon="iconDeleteKey"
         latin:keyActionFlags="isRepeatable|noKeyPreview"
         latin:backgroundType="functional" />
-    <key-style
-        latin:styleName="returnKeyStyle"
-        latin:code="@integer/key_return"
-        latin:keyIcon="iconReturnKey"
-        latin:keyActionFlags="noKeyPreview"
-        latin:backgroundType="functional" />
+    <include
+        latin:keyboardLayout="@xml/key_styles_enter_tablet" />
     <key-style
         latin:styleName="spaceKeyStyle"
         latin:code="@integer/key_space"
@@ -97,6 +93,7 @@
         latin:code="@integer/key_shortcut"
         latin:keyIcon="iconShortcutKey"
         latin:keyIconDisabled="iconDisabledShortcutKey"
+        latin:keyLabelFlags="preserveCase"
         latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
         latin:backgroundType="functional" />
     <key-style
diff --git a/java/res/xml-sw768dp/row_qwerty2.xml b/java/res/xml-sw768dp/row_qwerty2.xml
index 1129ecd..d348041 100644
--- a/java/res/xml-sw768dp/row_qwerty2.xml
+++ b/java/res/xml-sw768dp/row_qwerty2.xml
@@ -53,7 +53,7 @@
             latin:keyLabel="l"
             latin:moreKeys="@string/more_keys_for_l" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-15.704%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw768dp/rows_arabic.xml b/java/res/xml-sw768dp/rows_arabic.xml
index 0e4aee4..baced66 100644
--- a/java/res/xml-sw768dp/rows_arabic.xml
+++ b/java/res/xml-sw768dp/rows_arabic.xml
@@ -144,7 +144,7 @@
         <Key
             latin:keyLabel="ط" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-9.375%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw768dp/rows_azerty.xml b/java/res/xml-sw768dp/rows_azerty.xml
index b9ef898..6023e98 100644
--- a/java/res/xml-sw768dp/rows_azerty.xml
+++ b/java/res/xml-sw768dp/rows_azerty.xml
@@ -97,7 +97,7 @@
         <Key
             latin:keyLabel="m" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-15.704%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw768dp/rows_bulgarian.xml b/java/res/xml-sw768dp/rows_bulgarian.xml
index 57f39b4..d67a0d1 100644
--- a/java/res/xml-sw768dp/rows_bulgarian.xml
+++ b/java/res/xml-sw768dp/rows_bulgarian.xml
@@ -86,7 +86,7 @@
         <Key
             latin:keyLabel="ь" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyWidth="fillBoth" />
     </Row>
     <Row
diff --git a/java/res/xml-sw768dp/rows_hebrew.xml b/java/res/xml-sw768dp/rows_hebrew.xml
index 755afc8..61c5eae 100644
--- a/java/res/xml-sw768dp/rows_hebrew.xml
+++ b/java/res/xml-sw768dp/rows_hebrew.xml
@@ -111,7 +111,7 @@
             latin:keyLabel="ץ"
             latin:moreKeys="ץ׳" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-10.400%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw768dp/rows_number_normal.xml b/java/res/xml-sw768dp/rows_number_normal.xml
index 0e80e80..cf947ab 100644
--- a/java/res/xml-sw768dp/rows_number_normal.xml
+++ b/java/res/xml-sw768dp/rows_number_normal.xml
@@ -80,7 +80,7 @@
             latin:keyLabel="6"
             latin:keyStyle="numKeyStyle" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-11.172%p"
             latin:keyWidth="fillRight" />
     </Row>
diff --git a/java/res/xml-sw768dp/rows_number_password.xml b/java/res/xml-sw768dp/rows_number_password.xml
index 77fb9ca..8acfac6 100644
--- a/java/res/xml-sw768dp/rows_number_password.xml
+++ b/java/res/xml-sw768dp/rows_number_password.xml
@@ -49,7 +49,7 @@
         <Key
             latin:keyStyle="num6KeyStyle" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-11.172%p"
             latin:keyWidth="fillRight" />
     </Row>
diff --git a/java/res/xml-sw768dp/rows_phone.xml b/java/res/xml-sw768dp/rows_phone.xml
index 789c02c..0404bb1 100644
--- a/java/res/xml-sw768dp/rows_phone.xml
+++ b/java/res/xml-sw768dp/rows_phone.xml
@@ -78,7 +78,7 @@
         <Key
             latin:keyStyle="num6KeyStyle" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-11.172%p"
             latin:keyWidth="fillRight" />
     </Row>
diff --git a/java/res/xml-sw768dp/rows_scandinavian.xml b/java/res/xml-sw768dp/rows_scandinavian.xml
index 9e5ad14..4373166 100644
--- a/java/res/xml-sw768dp/rows_scandinavian.xml
+++ b/java/res/xml-sw768dp/rows_scandinavian.xml
@@ -102,7 +102,7 @@
             latin:keyLabel="@string/keylabel_for_scandinavia_row2_11"
             latin:moreKeys="@string/more_keys_for_scandinavia_row2_11" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-9.375%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw768dp/rows_serbian.xml b/java/res/xml-sw768dp/rows_serbian.xml
index 2e9e140..6659755 100644
--- a/java/res/xml-sw768dp/rows_serbian.xml
+++ b/java/res/xml-sw768dp/rows_serbian.xml
@@ -114,7 +114,7 @@
         <include
             latin:keyboardLayout="@xml/keys_comma_period" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-13.750%p"
             latin:keyWidth="fillRight" />
     </Row>
diff --git a/java/res/xml-sw768dp/rows_slavic.xml b/java/res/xml-sw768dp/rows_slavic.xml
index 86b4498..58d5a75 100644
--- a/java/res/xml-sw768dp/rows_slavic.xml
+++ b/java/res/xml-sw768dp/rows_slavic.xml
@@ -92,7 +92,7 @@
         <Key
             latin:keyLabel="э" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-9.375%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw768dp/rows_spanish.xml b/java/res/xml-sw768dp/rows_spanish.xml
index f626a45..864c435 100644
--- a/java/res/xml-sw768dp/rows_spanish.xml
+++ b/java/res/xml-sw768dp/rows_spanish.xml
@@ -59,7 +59,7 @@
         <Key
             latin:keyLabel="ñ" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-15.704%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw768dp/rows_symbols.xml b/java/res/xml-sw768dp/rows_symbols.xml
index 2ba9357..c199ae4 100644
--- a/java/res/xml-sw768dp/rows_symbols.xml
+++ b/java/res/xml-sw768dp/rows_symbols.xml
@@ -105,7 +105,7 @@
         <include
             latin:keyboardLayout="@xml/keys_parentheses" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-15.704%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml-sw768dp/rows_symbols_shift.xml b/java/res/xml-sw768dp/rows_symbols_shift.xml
index aba9c23..e88f786 100644
--- a/java/res/xml-sw768dp/rows_symbols_shift.xml
+++ b/java/res/xml-sw768dp/rows_symbols_shift.xml
@@ -87,7 +87,7 @@
         <include
             latin:keyboardLayout="@xml/keys_curly_brackets" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-15.704%p"
             latin:keyWidth="fillBoth" />
     </Row>
diff --git a/java/res/xml/kbd_mini_keyboard_template.xml b/java/res/xml/kbd_more_keys_keyboard_template.xml
similarity index 95%
rename from java/res/xml/kbd_mini_keyboard_template.xml
rename to java/res/xml/kbd_more_keys_keyboard_template.xml
index ad6cf51..8e977c5 100644
--- a/java/res/xml/kbd_mini_keyboard_template.xml
+++ b/java/res/xml/kbd_more_keys_keyboard_template.xml
@@ -21,6 +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"
+    style="?attr/moreKeysKeyboardStyle"
     >
 </Keyboard>
diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml
index ab9bc46..0e31bcb 100644
--- a/java/res/xml/key_styles_common.xml
+++ b/java/res/xml/key_styles_common.xml
@@ -98,99 +98,8 @@
         latin:keyIcon="iconDeleteKey"
         latin:keyActionFlags="isRepeatable|noKeyPreview"
         latin:backgroundType="functional" />
-    <!-- Return key style -->
-    <key-style
-        latin:styleName="defaultReturnKeyStyle"
-        latin:code="@integer/key_return"
-        latin:keyIcon="iconReturnKey"
-        latin:keyActionFlags="noKeyPreview"
-        latin:backgroundType="functional" />
-    <switch>
-        <case
-            latin:mode="im"
-        >
-            <!-- Smiley key. -->
-            <switch>
-                <case
-                    latin:keyboardSetElement="alphabetManualShifted|alphabetShiftLockShifted"
-                >
-                    <key-style
-                        latin:styleName="returnKeyStyle"
-                        latin:parentStyle="defaultReturnKeyStyle" />
-                </case>
-                <default>
-                    <key-style
-                        latin:styleName="returnKeyStyle"
-                        latin:keyLabel=":-)"
-                        latin:keyOutputText=":-) "
-                        latin:keyLabelFlags="hasPopupHint|preserveCase"
-                        latin:moreKeys="@string/more_keys_for_smiley"
-                        latin:maxMoreKeysColumn="5"
-                        latin:backgroundType="functional" />
-                </default>
-            </switch>
-        </case>
-        <case
-            latin:imeAction="actionGo"
-        >
-            <key-style
-                latin:styleName="returnKeyStyle"
-                latin:code="@integer/key_return"
-                latin:keyLabel="@string/label_go_key"
-                latin:keyLabelFlags="autoXScale|preserveCase"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="action" />
-        </case>
-        <case
-            latin:imeAction="actionNext"
-        >
-            <key-style
-                latin:styleName="returnKeyStyle"
-                latin:code="@integer/key_return"
-                latin:keyLabel="@string/label_next_key"
-                latin:keyLabelFlags="autoXScale|preserveCase"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="action" />
-        </case>
-        <case
-            latin:imeAction="actionDone"
-        >
-            <key-style
-                latin:styleName="returnKeyStyle"
-                latin:code="@integer/key_return"
-                latin:keyLabel="@string/label_done_key"
-                latin:keyLabelFlags="autoXScale|preserveCase"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="action" />
-        </case>
-        <case
-            latin:imeAction="actionSend"
-        >
-            <key-style
-                latin:styleName="returnKeyStyle"
-                latin:code="@integer/key_return"
-                latin:keyLabel="@string/label_send_key"
-                latin:keyLabelFlags="autoXScale|preserveCase"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="action" />
-        </case>
-        <case
-            latin:imeAction="actionSearch"
-        >
-            <key-style
-                latin:styleName="returnKeyStyle"
-                latin:code="@integer/key_return"
-                latin:keyIcon="iconSearchKey"
-                latin:keyLabelFlags="autoXScale"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="action" />
-        </case>
-        <default>
-            <key-style
-                latin:styleName="returnKeyStyle"
-                latin:parentStyle="defaultReturnKeyStyle" />
-        </default>
-    </switch>
+    <include
+        latin:keyboardLayout="@xml/key_styles_enter_phone" />
     <key-style
         latin:styleName="spaceKeyStyle"
         latin:code="@integer/key_space"
@@ -201,6 +110,7 @@
         latin:code="@integer/key_shortcut"
         latin:keyIcon="iconShortcutKey"
         latin:keyIconDisabled="iconDisabledShortcutKey"
+        latin:keyLabelFlags="preserveCase"
         latin:keyActionFlags="noKeyPreview|altCodeWhileTyping"
         latin:altCode="@integer/key_space"
         latin:parentStyle="f1PopupStyle" />
@@ -278,6 +188,6 @@
         latin:keyHintLabel="@string/keyhintlabel_for_punctuation"
         latin:keyLabelFlags="hasPopupHint|preserveCase"
         latin:moreKeys="@string/more_keys_for_punctuation"
-        latin:maxMoreKeysColumn="@integer/mini_keyboard_column_for_punctuation"
+        latin:maxMoreKeysColumn="@integer/more_keys_keyboard_column_for_punctuation"
         latin:backgroundType="functional" />
 </merge>
diff --git a/java/res/xml/key_styles_enter_phone.xml b/java/res/xml/key_styles_enter_phone.xml
new file mode 100644
index 0000000..6af81fb
--- /dev/null
+++ b/java/res/xml/key_styles_enter_phone.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <!-- Enter key style -->
+    <key-style
+        latin:styleName="defaultEnterKeyStyle"
+        latin:code="@integer/key_enter"
+        latin:keyIcon="iconReturnKey"
+        latin:keyLabelFlags="autoXScale|preserveCase"
+        latin:keyActionFlags="noKeyPreview"
+        latin:backgroundType="functional" />
+    <key-style
+        latin:styleName="defaultActionKeyStyle"
+        latin:code="@integer/key_action_enter"
+        latin:keyIcon="iconUndefined"
+        latin:backgroundType="action"
+        latin:parentStyle="defaultEnterKeyStyle" />
+    <switch>
+        <!-- Shift + Enter in textMultiLine field. -->
+        <case
+            latin:isMultiLine="true"
+            latin:keyboardSetElement="alphabetManualShifted|alphabetShiftLockShifted"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:parentStyle="defaultEnterKeyStyle" />
+        </case>
+        <!-- Smiley in textShortMessage field. -->
+        <case
+            latin:mode="im"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabel=":-)"
+                latin:keyOutputText=":-) "
+                latin:keyLabelFlags="hasPopupHint"
+                latin:moreKeys="@string/more_keys_for_smiley"
+                latin:maxMoreKeysColumn="5"
+                latin:backgroundType="functional" />
+        </case>
+        <case
+            latin:imeAction="actionGo"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabel="@string/label_go_key"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionNext"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabel="@string/label_next_key"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionPrevious"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabel="@string/label_previous_key"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionDone"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabel="@string/label_done_key"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionSend"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabel="@string/label_send_key"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionSearch"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyIcon="iconSearchKey"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionCustomLabel"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabelFlags="fromCustomActionLabel"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <!-- imeAction is either actionNone or actionUnspecified. -->
+        <default>
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:parentStyle="defaultEnterKeyStyle" />
+        </default>
+    </switch>
+</merge>
diff --git a/java/res/xml/key_styles_enter_tablet.xml b/java/res/xml/key_styles_enter_tablet.xml
new file mode 100644
index 0000000..7020891
--- /dev/null
+++ b/java/res/xml/key_styles_enter_tablet.xml
@@ -0,0 +1,111 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <!-- Enter key style -->
+    <key-style
+        latin:styleName="defaultEnterKeyStyle"
+        latin:code="@integer/key_enter"
+        latin:keyIcon="iconReturnKey"
+        latin:keyLabelFlags="autoXScale|preserveCase"
+        latin:keyActionFlags="noKeyPreview"
+        latin:backgroundType="functional" />
+    <key-style
+        latin:styleName="defaultActionKeyStyle"
+        latin:code="@integer/key_action_enter"
+        latin:keyIcon="iconUndefined"
+        latin:backgroundType="action"
+        latin:parentStyle="defaultEnterKeyStyle" />
+    <switch>
+        <!-- Shift + Enter in textMultiLine field. -->
+        <case
+            latin:isMultiLine="true"
+            latin:keyboardSetElement="alphabetManualShifted|alphabetShiftLockShifted"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:parentStyle="defaultEnterKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionGo"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabel="@string/label_go_key"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionNext"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabel="@string/label_next_key"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionPrevious"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabel="@string/label_previous_key"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionDone"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabel="@string/label_done_key"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionSend"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabel="@string/label_send_key"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionSearch"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyIcon="iconSearchKey"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <case
+            latin:imeAction="actionCustomLabel"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:keyLabelFlags="fromCustomActionLabel"
+                latin:parentStyle="defaultActionKeyStyle" />
+        </case>
+        <!-- imeAction is either actionNone or actionUnspecified. -->
+        <default>
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:parentStyle="defaultEnterKeyStyle" />
+        </default>
+    </switch>
+</merge>
diff --git a/java/res/xml/keys_curly_brackets.xml b/java/res/xml/keys_curly_brackets.xml
index b43fbb1..d21a092 100644
--- a/java/res/xml/keys_curly_brackets.xml
+++ b/java/res/xml/keys_curly_brackets.xml
@@ -23,8 +23,8 @@
 >
     <Key
         latin:keyLabel="{"
-        latin:keyOutputText="@string/output_text_for_left_curly_bracket" />
+        latin:code="@integer/keycode_for_left_curly_bracket" />
     <Key
         latin:keyLabel="}"
-        latin:keyOutputText="@string/output_text_for_right_curly_bracket" />
+        latin:code="@integer/keycode_for_right_curly_bracket" />
 </merge>
diff --git a/java/res/xml/keys_less_greater.xml b/java/res/xml/keys_less_greater.xml
index 8e90199..8961d9c 100644
--- a/java/res/xml/keys_less_greater.xml
+++ b/java/res/xml/keys_less_greater.xml
@@ -23,10 +23,10 @@
 >
     <Key
         latin:keyLabel="&lt;"
-        latin:keyOutputText="@string/output_text_for_less_than"
+        latin:code="@integer/keycode_for_less_than"
         latin:moreKeys="@string/more_keys_for_less_than" />
     <Key
         latin:keyLabel="&gt;"
-        latin:keyOutputText="@string/output_text_for_greater_than"
+        latin:code="@integer/keycode_for_greater_than"
         latin:moreKeys="@string/more_keys_for_greater_than" />
 </merge>
diff --git a/java/res/xml/keys_parentheses.xml b/java/res/xml/keys_parentheses.xml
index bacb26d..6853bf1 100644
--- a/java/res/xml/keys_parentheses.xml
+++ b/java/res/xml/keys_parentheses.xml
@@ -23,10 +23,10 @@
 >
     <Key
         latin:keyLabel="("
-        latin:keyOutputText="@string/output_text_for_left_parenthesis"
+        latin:code="@integer/keycode_for_left_parenthesis"
         latin:moreKeys="@string/more_keys_for_left_parenthesis" />
     <Key
         latin:keyLabel=")"
-        latin:keyOutputText="@string/output_text_for_right_parenthesis"
+        latin:code="@integer/keycode_for_right_parenthesis"
         latin:moreKeys="@string/more_keys_for_right_parenthesis" />
 </merge>
diff --git a/java/res/xml/keys_square_brackets.xml b/java/res/xml/keys_square_brackets.xml
index 3525f4d..44387c3 100644
--- a/java/res/xml/keys_square_brackets.xml
+++ b/java/res/xml/keys_square_brackets.xml
@@ -23,8 +23,8 @@
 >
     <Key
         latin:keyLabel="["
-        latin:keyOutputText="@string/output_text_for_left_square_bracket" />
+        latin:code="@integer/keycode_for_left_square_bracket" />
     <Key
         latin:keyLabel="]"
-        latin:keyOutputText="@string/output_text_for_right_square_bracket" />
+        latin:code="@integer/keycode_for_right_square_bracket" />
 </merge>
diff --git a/java/res/xml/row_qwerty4.xml b/java/res/xml/row_qwerty4.xml
index 65500a6..8c20a72 100644
--- a/java/res/xml/row_qwerty4.xml
+++ b/java/res/xml/row_qwerty4.xml
@@ -40,7 +40,7 @@
                 <Key
                     latin:keyStyle="punctuationKeyStyle" />
                 <Key
-                    latin:keyStyle="returnKeyStyle"
+                    latin:keyStyle="enterKeyStyle"
                     latin:keyWidth="fillRight" />
             </case>
             <!-- hasSettingsKey="true" or navigateAction="true" -->
@@ -59,7 +59,7 @@
                     latin:keyStyle="punctuationKeyStyle"
                     latin:keyWidth="9.2%p" />
                 <Key
-                    latin:keyStyle="returnKeyStyle"
+                    latin:keyStyle="enterKeyStyle"
                     latin:keyWidth="fillRight" />
             </default>
         </switch>
diff --git a/java/res/xml/row_symbols4.xml b/java/res/xml/row_symbols4.xml
index 8b094dd..be0c94f 100644
--- a/java/res/xml/row_symbols4.xml
+++ b/java/res/xml/row_symbols4.xml
@@ -40,7 +40,7 @@
                 <Key
                     latin:keyStyle="punctuationKeyStyle" />
                 <Key
-                    latin:keyStyle="returnKeyStyle"
+                    latin:keyStyle="enterKeyStyle"
                     latin:keyWidth="fillRight" />
             </case>
             <!-- hasSettingsKey="true" or navigateAction="true" -->
@@ -59,7 +59,7 @@
                     latin:keyStyle="punctuationKeyStyle"
                     latin:keyWidth="9.2%p" />
                 <Key
-                    latin:keyStyle="returnKeyStyle"
+                    latin:keyStyle="enterKeyStyle"
                     latin:keyWidth="fillRight" />
             </default>
         </switch>
diff --git a/java/res/xml/row_symbols_shift4.xml b/java/res/xml/row_symbols_shift4.xml
index 4e13ac7..dd13b71 100644
--- a/java/res/xml/row_symbols_shift4.xml
+++ b/java/res/xml/row_symbols_shift4.xml
@@ -45,7 +45,7 @@
                     latin:keyLabel="…"
                     latin:backgroundType="functional" />
                 <Key
-                    latin:keyStyle="returnKeyStyle"
+                    latin:keyStyle="enterKeyStyle"
                     latin:keyWidth="fillRight" />
             </case>
             <!-- hasSettingsKey="true" or navigateAction="true" -->
@@ -70,7 +70,7 @@
                     latin:keyWidth="9.2%p"
                     latin:backgroundType="functional" />
                 <Key
-                    latin:keyStyle="returnKeyStyle"
+                    latin:keyStyle="enterKeyStyle"
                     latin:keyWidth="fillRight" />
             </default>
         </switch>
diff --git a/java/res/xml/rows_number_normal.xml b/java/res/xml/rows_number_normal.xml
index 054b564..b581fb5 100644
--- a/java/res/xml/rows_number_normal.xml
+++ b/java/res/xml/rows_number_normal.xml
@@ -75,7 +75,7 @@
             latin:keyLabel="."
             latin:keyStyle="numKeyStyle" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyWidth="fillRight" />
     </Row>
 </merge>
diff --git a/java/res/xml/rows_number_password.xml b/java/res/xml/rows_number_password.xml
index ebc13c6..e4272ed 100644
--- a/java/res/xml/rows_number_password.xml
+++ b/java/res/xml/rows_number_password.xml
@@ -56,7 +56,7 @@
             latin:keyStyle="num0KeyStyle" />
         <Spacer />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyWidth="fillRight" />
     </Row>
 </merge>
diff --git a/java/res/xml/rows_phone.xml b/java/res/xml/rows_phone.xml
index 18e4c9d..60296d0 100644
--- a/java/res/xml/rows_phone.xml
+++ b/java/res/xml/rows_phone.xml
@@ -68,7 +68,7 @@
         <Key
             latin:keyStyle="numSpaceKeyStyle" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyWidth="fillRight" />
     </Row>
 </merge>
diff --git a/java/res/xml/rows_phone_symbols.xml b/java/res/xml/rows_phone_symbols.xml
index dfa1349..7841c56 100644
--- a/java/res/xml/rows_phone_symbols.xml
+++ b/java/res/xml/rows_phone_symbols.xml
@@ -78,7 +78,7 @@
         <Key
             latin:keyStyle="numSpaceKeyStyle" />
         <Key
-            latin:keyStyle="returnKeyStyle"
+            latin:keyStyle="enterKeyStyle"
             latin:keyWidth="fillRight" />
     </Row>
 </merge>
diff --git a/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java
index e1db360..3247997 100644
--- a/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/EditorInfoCompatUtils.java
@@ -67,42 +67,34 @@
         ic.performEditorAction(OBJ_IME_ACTION_PREVIOUS);
     }
 
-    public static String imeOptionsName(int imeOptions) {
-        if (imeOptions == -1)
-            return null;
+    public static String imeActionName(int imeOptions) {
         final int actionId = imeOptions & EditorInfo.IME_MASK_ACTION;
-        final String action;
         switch (actionId) {
-            case EditorInfo.IME_ACTION_UNSPECIFIED:
-                action = "actionUnspecified";
-                break;
-            case EditorInfo.IME_ACTION_NONE:
-                action = "actionNone";
-                break;
-            case EditorInfo.IME_ACTION_GO:
-                action = "actionGo";
-                break;
-            case EditorInfo.IME_ACTION_SEARCH:
-                action = "actionSearch";
-                break;
-            case EditorInfo.IME_ACTION_SEND:
-                action = "actionSend";
-                break;
-            case EditorInfo.IME_ACTION_NEXT:
-                action = "actionNext";
-                break;
-            case EditorInfo.IME_ACTION_DONE:
-                action = "actionDone";
-                break;
-            default: {
-                if (OBJ_IME_ACTION_PREVIOUS != null && actionId == OBJ_IME_ACTION_PREVIOUS) {
-                    action = "actionPrevious";
-                } else {
-                    action = "actionUnknown(" + actionId + ")";
-                }
-                break;
+        case EditorInfo.IME_ACTION_UNSPECIFIED:
+            return "actionUnspecified";
+        case EditorInfo.IME_ACTION_NONE:
+            return "actionNone";
+        case EditorInfo.IME_ACTION_GO:
+            return "actionGo";
+        case EditorInfo.IME_ACTION_SEARCH:
+            return "actionSearch";
+        case EditorInfo.IME_ACTION_SEND:
+            return "actionSend";
+        case EditorInfo.IME_ACTION_NEXT:
+            return "actionNext";
+        case EditorInfo.IME_ACTION_DONE:
+            return "actionDone";
+        default:
+            if (OBJ_IME_ACTION_PREVIOUS != null && actionId == OBJ_IME_ACTION_PREVIOUS) {
+                return "actionPrevious";
+            } else {
+                return "actionUnknown(" + actionId + ")";
             }
         }
+    }
+
+    public static String imeOptionsName(int imeOptions) {
+        final String action = imeActionName(imeOptions);
         final StringBuilder flags = new StringBuilder();
         if ((imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
             flags.append("flagNoEnterAction|");
@@ -116,6 +108,6 @@
         if (hasFlagForceAscii(imeOptions)) {
             flags.append("flagForceAscii|");
         }
-        return flags + action;
+        return (action != null) ? flags + action : flags.toString();
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 686392d..b90d45d 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -72,6 +72,7 @@
     private static final int LABEL_FLAGS_AUTO_X_SCALE = 0x4000;
     private static final int LABEL_FLAGS_PRESERVE_CASE = 0x8000;
     private static final int LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED = 0x10000;
+    private static final int LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL = 0x20000;
 
     /** Icon to display instead of a label. Icon takes precedence over a label */
     private final int mIconId;
@@ -228,9 +229,9 @@
         mDisabledIconId = style.getInt(keyAttr,
                 R.styleable.Keyboard_Key_keyIconDisabled, KeyboardIconsSet.ICON_UNDEFINED);
 
-        mLabelFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags, 0);
+        mLabelFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyLabelFlags);
         final boolean preserveCase = (mLabelFlags & LABEL_FLAGS_PRESERVE_CASE) != 0;
-        int actionFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags, 0);
+        int actionFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
         final String[] additionalMoreKeys = style.getStringArray(
                 keyAttr, R.styleable.Keyboard_Key_additionalMoreKeys);
         final String[] moreKeys = KeySpecParser.insertAddtionalMoreKeys(style.getStringArray(
@@ -245,10 +246,14 @@
         mActionFlags = actionFlags;
         mMoreKeys = moreKeys;
         mMaxMoreKeysColumn = style.getInt(keyAttr,
-                R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMiniKeyboardColumn);
+                R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMoreKeysKeyboardColumn);
 
-        mLabel = adjustCaseOfStringForKeyboardId(style.getString(
-                keyAttr, R.styleable.Keyboard_Key_keyLabel), preserveCase, params.mId);
+        if ((mLabelFlags & LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL) != 0) {
+            mLabel = params.mId.mCustomActionLabel;
+        } else {
+            mLabel = adjustCaseOfStringForKeyboardId(style.getString(
+                    keyAttr, R.styleable.Keyboard_Key_keyLabel), preserveCase, params.mId);
+        }
         mHintLabel = adjustCaseOfStringForKeyboardId(style.getString(
                 keyAttr, R.styleable.Keyboard_Key_keyHintLabel), preserveCase, params.mId);
         String outputText = adjustCaseOfStringForKeyboardId(style.getString(
@@ -274,7 +279,12 @@
                 mCode = Keyboard.CODE_OUTPUT_TEXT;
             }
         } else if (code == Keyboard.CODE_UNSPECIFIED && outputText != null) {
-            mCode = Keyboard.CODE_OUTPUT_TEXT;
+            if (Utils.codePointCount(outputText) == 1) {
+                mCode = outputText.codePointAt(0);
+                outputText = null;
+            } else {
+                mCode = Keyboard.CODE_OUTPUT_TEXT;
+            }
         } else {
             mCode = adjustCaseOfCodeForKeyboardId(code, preserveCase, params.mId);
         }
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 10e0a5b..28f71f4 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -28,7 +28,6 @@
 import android.util.Xml;
 import android.view.InflateException;
 
-import com.android.inputmethod.compat.EditorInfoCompatUtils;
 import com.android.inputmethod.keyboard.internal.KeyStyles;
 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
 import com.android.inputmethod.latin.LatinImeLogger;
@@ -95,10 +94,11 @@
      */
     public static final int CODE_SHIFT = -1;
     public static final int CODE_SWITCH_ALPHA_SYMBOL = -2;
-    public static final int CODE_OUTPUT_TEXT = -4;
-    public static final int CODE_DELETE = -5;
-    public static final int CODE_SETTINGS = -6;
-    public static final int CODE_SHORTCUT = -7;
+    public static final int CODE_OUTPUT_TEXT = -3;
+    public static final int CODE_DELETE = -4;
+    public static final int CODE_SETTINGS = -5;
+    public static final int CODE_SHORTCUT = -6;
+    public static final int CODE_ACTION_ENTER = -7;
     // Code value representing the code is not specified.
     public static final int CODE_UNSPECIFIED = -9;
 
@@ -121,8 +121,8 @@
     /** More keys keyboard template */
     public final int mMoreKeysTemplate;
 
-    /** Maximum column for mini keyboard */
-    public final int mMaxMiniKeyboardColumn;
+    /** Maximum column for more keys keyboard */
+    public final int mMaxMoreKeysKeyboardColumn;
 
     /** List of keys and icons in this keyboard */
     public final Set<Key> mKeys;
@@ -143,7 +143,7 @@
         mMostCommonKeyHeight = params.mMostCommonKeyHeight;
         mMostCommonKeyWidth = params.mMostCommonKeyWidth;
         mMoreKeysTemplate = params.mMoreKeysTemplate;
-        mMaxMiniKeyboardColumn = params.mMaxMiniKeyboardColumn;
+        mMaxMoreKeysKeyboardColumn = params.mMaxMoreKeysKeyboardColumn;
 
         mTopPadding = params.mTopPadding;
         mVerticalGap = params.mVerticalGap;
@@ -226,7 +226,7 @@
         public int mVerticalGap;
 
         public int mMoreKeysTemplate;
-        public int mMaxMiniKeyboardColumn;
+        public int mMaxMoreKeysKeyboardColumn;
 
         public int GRID_WIDTH;
         public int GRID_HEIGHT;
@@ -380,6 +380,7 @@
         case CODE_DELETE: return "delete";
         case CODE_SETTINGS: return "settings";
         case CODE_SHORTCUT: return "shortcut";
+        case CODE_ACTION_ENTER: return "actionEnter";
         case CODE_UNSPECIFIED: return "unspec";
         case CODE_TAB: return "tab";
         case CODE_ENTER: return "enter";
@@ -475,7 +476,7 @@
      */
 
     public static class Builder<KP extends Params> {
-        private static final String TAG = Builder.class.getSimpleName();
+        private static final String BUILDER_TAG = "Keyboard.Builder";
         private static final boolean DEBUG = false;
 
         // Keyboard XML Tags
@@ -643,7 +644,7 @@
             a.recycle();
             if (resourceId == 0) {
                 if (LatinImeLogger.sDBG)
-                    Log.e(TAG, "touchPositionCorrectionData is not defined");
+                    Log.e(BUILDER_TAG, "touchPositionCorrectionData is not defined");
                 return;
             }
 
@@ -680,10 +681,10 @@
             try {
                 parseKeyboard(parser);
             } catch (XmlPullParserException e) {
-                Log.w(TAG, "keyboard XML parse error: " + e);
+                Log.w(BUILDER_TAG, "keyboard XML parse error: " + e);
                 throw new IllegalArgumentException(e);
             } catch (IOException e) {
-                Log.w(TAG, "keyboard XML parse error: " + e);
+                Log.w(BUILDER_TAG, "keyboard XML parse error: " + e);
                 throw new RuntimeException(e);
             } finally {
                 parser.close();
@@ -699,9 +700,29 @@
             return new Keyboard(mParams);
         }
 
+        private int mIndent;
+        private static final String SPACES = "                                             ";
+
+        private static String spaces(int count) {
+            return (count < SPACES.length()) ? SPACES.substring(0, count) : SPACES;
+        }
+
+        private void startTag(String format, Object ... args) {
+            Log.d(BUILDER_TAG, String.format(spaces(++mIndent * 2) + format, args));
+        }
+
+        private void endTag(String format, Object ... args) {
+            Log.d(BUILDER_TAG, String.format(spaces(mIndent-- * 2) + format, args));
+        }
+
+        private void startEndTag(String format, Object ... args) {
+            Log.d(BUILDER_TAG, String.format(spaces(++mIndent * 2) + format, args));
+            mIndent--;
+        }
+
         private void parseKeyboard(XmlPullParser parser)
                 throws XmlPullParserException, IOException {
-            if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_KEYBOARD, mParams.mId));
+            if (DEBUG) startTag("<%s> %s", TAG_KEYBOARD, mParams.mId);
             int event;
             while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 if (event == XmlPullParser.START_TAG) {
@@ -770,7 +791,7 @@
 
                 params.mMoreKeysTemplate = keyboardAttr.getResourceId(
                         R.styleable.Keyboard_moreKeysTemplate, 0);
-                params.mMaxMiniKeyboardColumn = keyAttr.getInt(
+                params.mMaxMoreKeysKeyboardColumn = keyAttr.getInt(
                         R.styleable.Keyboard_Key_maxMoreKeysColumn, 5);
 
                 params.mIconsSet.loadIcons(keyboardAttr);
@@ -788,9 +809,10 @@
                     final String tag = parser.getName();
                     if (TAG_ROW.equals(tag)) {
                         Row row = parseRowAttributes(parser);
-                        if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_ROW));
-                        if (!skip)
+                        if (DEBUG) startTag("<%s>%s", TAG_ROW, skip ? " skipped" : "");
+                        if (!skip) {
                             startRow(row);
+                        }
                         parseRowContent(parser, row, skip);
                     } else if (TAG_INCLUDE.equals(tag)) {
                         parseIncludeKeyboardContent(parser, skip);
@@ -803,15 +825,13 @@
                     }
                 } else if (event == XmlPullParser.END_TAG) {
                     final String tag = parser.getName();
+                    if (DEBUG) endTag("</%s>", tag);
                     if (TAG_KEYBOARD.equals(tag)) {
                         endKeyboard();
                         break;
                     } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag)
                             || TAG_MERGE.equals(tag)) {
-                        if (DEBUG) Log.d(TAG, String.format("</%s>", tag));
                         break;
-                    } else if (TAG_KEY_STYLE.equals(tag)) {
-                        continue;
                     } else {
                         throw new XmlParseUtils.IllegalEndTag(parser, TAG_ROW);
                     }
@@ -854,17 +874,15 @@
                     }
                 } else if (event == XmlPullParser.END_TAG) {
                     final String tag = parser.getName();
+                    if (DEBUG) endTag("</%s>", tag);
                     if (TAG_ROW.equals(tag)) {
-                        if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_ROW));
-                        if (!skip)
+                        if (!skip) {
                             endRow(row);
+                        }
                         break;
                     } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag)
                             || TAG_MERGE.equals(tag)) {
-                        if (DEBUG) Log.d(TAG, String.format("</%s>", tag));
                         break;
-                    } else if (TAG_KEY_STYLE.equals(tag)) {
-                        continue;
                     } else {
                         throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY);
                     }
@@ -876,11 +894,14 @@
                 throws XmlPullParserException, IOException {
             if (skip) {
                 XmlParseUtils.checkEndTag(TAG_KEY, parser);
+                if (DEBUG) startEndTag("<%s /> skipped", TAG_KEY);
             } else {
                 final Key key = new Key(mResources, mParams, row, parser, mKeyStyles);
-                if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d moreKeys=%s />",
-                        TAG_KEY, (key.isEnabled() ? "" : " disabled"), key.mLabel, key.mCode,
-                        Arrays.toString(key.mMoreKeys)));
+                if (DEBUG) {
+                    startEndTag("<%s%s %s moreKeys=%s />", TAG_KEY,
+                            (key.isEnabled() ? "" : " disabled"), key,
+                            Arrays.toString(key.mMoreKeys));
+                }
                 XmlParseUtils.checkEndTag(TAG_KEY, parser);
                 endKey(key);
             }
@@ -890,10 +911,11 @@
                 throws XmlPullParserException, IOException {
             if (skip) {
                 XmlParseUtils.checkEndTag(TAG_SPACER, parser);
+                if (DEBUG) startEndTag("<%s /> skipped", TAG_SPACER);
             } else {
                 final Key.Spacer spacer = new Key.Spacer(
                         mResources, mParams, row, parser, mKeyStyles);
-                if (DEBUG) Log.d(TAG, String.format("<%s />", TAG_SPACER));
+                if (DEBUG) startEndTag("<%s />", TAG_SPACER);
                 XmlParseUtils.checkEndTag(TAG_SPACER, parser);
                 endKey(spacer);
             }
@@ -913,6 +935,7 @@
                 throws XmlPullParserException, IOException {
             if (skip) {
                 XmlParseUtils.checkEndTag(TAG_INCLUDE, parser);
+                if (DEBUG) startEndTag("</%s> skipped", TAG_INCLUDE);
             } else {
                 final AttributeSet attr = Xml.asAttributeSet(parser);
                 final TypedArray keyboardAttr = mResources.obtainAttributes(attr,
@@ -944,8 +967,10 @@
                 }
 
                 XmlParseUtils.checkEndTag(TAG_INCLUDE, parser);
-                if (DEBUG) Log.d(TAG, String.format("<%s keyboardLayout=%s />",
-                        TAG_INCLUDE, mResources.getResourceEntryName(keyboardLayout)));
+                if (DEBUG) {
+                    startEndTag("<%s keyboardLayout=%s />",TAG_INCLUDE,
+                            mResources.getResourceEntryName(keyboardLayout));
+                }
                 final XmlResourceParser parserForInclude = mResources.getXml(keyboardLayout);
                 try {
                     parseMerge(parserForInclude, row, skip);
@@ -961,6 +986,7 @@
 
         private void parseMerge(XmlPullParser parser, Row row, boolean skip)
                 throws XmlPullParserException, IOException {
+            if (DEBUG) startTag("<%s>", TAG_MERGE);
             int event;
             while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 if (event == XmlPullParser.START_TAG) {
@@ -992,7 +1018,7 @@
 
         private void parseSwitchInternal(XmlPullParser parser, Row row, boolean skip)
                 throws XmlPullParserException, IOException {
-            if (DEBUG) Log.d(TAG, String.format("<%s> %s", TAG_SWITCH, mParams.mId));
+            if (DEBUG) startTag("<%s> %s", TAG_SWITCH, mParams.mId);
             boolean selected = false;
             int event;
             while ((event = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -1008,7 +1034,7 @@
                 } else if (event == XmlPullParser.END_TAG) {
                     final String tag = parser.getName();
                     if (TAG_SWITCH.equals(tag)) {
-                        if (DEBUG) Log.d(TAG, String.format("</%s>", TAG_SWITCH));
+                        if (DEBUG) endTag("</%s>", TAG_SWITCH);
                         break;
                     } else {
                         throw new XmlParseUtils.IllegalEndTag(parser, TAG_KEY);
@@ -1057,10 +1083,8 @@
                         R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled);
                 final boolean hasShortcutKeyMatched = matchBoolean(a,
                         R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey);
-                // As noted at {@link KeyboardId} class, we are interested only in enum value
-                // masked by {@link android.view.inputmethod.EditorInfo#IME_MASK_ACTION} and
-                // {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_ENTER_ACTION}. So matching
-                // this attribute with id.mImeOptions as integer value is enough for our purpose.
+                final boolean isMultiLineMatched = matchBoolean(a,
+                        R.styleable.Keyboard_Case_isMultiLine, id.isMultiLine());
                 final boolean imeActionMatched = matchInteger(a,
                         R.styleable.Keyboard_Case_imeAction, id.imeAction());
                 final boolean localeCodeMatched = matchString(a,
@@ -1072,30 +1096,42 @@
                 final boolean selected = keyboardSetElementMatched && modeMatched
                         && navigateActionMatched && passwordInputMatched && hasSettingsKeyMatched
                         && f2KeyModeMatched && clobberSettingsKeyMatched
-                        && shortcutKeyEnabledMatched && hasShortcutKeyMatched && imeActionMatched
-                        && localeCodeMatched && languageCodeMatched && countryCodeMatched;
+                        && shortcutKeyEnabledMatched && hasShortcutKeyMatched && isMultiLineMatched
+                        && imeActionMatched && localeCodeMatched && languageCodeMatched
+                        && countryCodeMatched;
 
-                if (DEBUG) Log.d(TAG, String.format("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s> %s", TAG_CASE,
-                        textAttr(a.getString(R.styleable.Keyboard_Case_keyboardSetElement),
-                                "keyboardSetElement"),
-                        textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"),
-                        booleanAttr(a, R.styleable.Keyboard_Case_navigateAction, "navigateAction"),
-                        booleanAttr(a, R.styleable.Keyboard_Case_passwordInput, "passwordInput"),
-                        booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey, "hasSettingsKey"),
-                        textAttr(KeyboardId.f2KeyModeName(
-                                a.getInt(R.styleable.Keyboard_Case_f2KeyMode, -1)), "f2KeyMode"),
-                        booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey,
-                                "clobberSettingsKey"),
-                        booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled,
-                                "shortcutKeyEnabled"),
-                        booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, "hasShortcutKey"),
-                        textAttr(EditorInfoCompatUtils.imeOptionsName(
-                                a.getInt(R.styleable.Keyboard_Case_imeAction, -1)), "imeAction"),
-                        textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), "localeCode"),
-                        textAttr(a.getString(R.styleable.Keyboard_Case_languageCode),
-                                "languageCode"),
-                        textAttr(a.getString(R.styleable.Keyboard_Case_countryCode), "countryCode"),
-                        Boolean.toString(selected)));
+                if (DEBUG) {
+                    startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE,
+                            textAttr(a.getString(R.styleable.Keyboard_Case_keyboardSetElement),
+                                    "keyboardSetElement"),
+                            textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"),
+                            booleanAttr(a, R.styleable.Keyboard_Case_navigateAction,
+                                    "navigateAction"),
+                            booleanAttr(a, R.styleable.Keyboard_Case_passwordInput,
+                                    "passwordInput"),
+                            booleanAttr(a, R.styleable.Keyboard_Case_hasSettingsKey,
+                                    "hasSettingsKey"),
+                            textAttr(KeyboardId.f2KeyModeName(
+                                    a.getInt(R.styleable.Keyboard_Case_f2KeyMode, -1)),
+                                    "f2KeyMode"),
+                            booleanAttr(a, R.styleable.Keyboard_Case_clobberSettingsKey,
+                                    "clobberSettingsKey"),
+                            booleanAttr(a, R.styleable.Keyboard_Case_shortcutKeyEnabled,
+                                    "shortcutKeyEnabled"),
+                            booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey,
+                                    "hasShortcutKey"),
+                            booleanAttr(a, R.styleable.Keyboard_Case_isMultiLine,
+                                    "isMultiLine"),
+                            textAttr(a.getString(R.styleable.Keyboard_Case_imeAction),
+                                    "imeAction"),
+                            textAttr(a.getString(R.styleable.Keyboard_Case_localeCode),
+                                    "localeCode"),
+                            textAttr(a.getString(R.styleable.Keyboard_Case_languageCode),
+                                    "languageCode"),
+                            textAttr(a.getString(R.styleable.Keyboard_Case_countryCode),
+                                    "countryCode"),
+                            selected ? "" : " skipped");
+                }
 
                 return selected;
             } finally {
@@ -1148,7 +1184,7 @@
 
         private boolean parseDefault(XmlPullParser parser, Row row, boolean skip)
                 throws XmlPullParserException, IOException {
-            if (DEBUG) Log.d(TAG, String.format("<%s>", TAG_DEFAULT));
+            if (DEBUG) startTag("<%s>", TAG_DEFAULT);
             if (row == null) {
                 parseKeyboardContent(parser, skip);
             } else {
@@ -1158,7 +1194,7 @@
         }
 
         private void parseKeyStyle(XmlPullParser parser, boolean skip)
-                throws XmlPullParserException {
+                throws XmlPullParserException, IOException {
             TypedArray keyStyleAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
                     R.styleable.Keyboard_KeyStyle);
             TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser),
@@ -1167,12 +1203,18 @@
                 if (!keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_styleName))
                     throw new XmlParseUtils.ParseException("<" + TAG_KEY_STYLE
                             + "/> needs styleName attribute", parser);
+                if (DEBUG) {
+                    startEndTag("<%s styleName=%s />%s", TAG_KEY_STYLE,
+                        keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName),
+                        skip ? " skipped" : "");
+                }
                 if (!skip)
                     mKeyStyles.parseKeyStyleAttributes(keyStyleAttr, keyAttrs, parser);
             } finally {
                 keyStyleAttr.recycle();
                 keyAttrs.recycle();
             }
+            XmlParseUtils.checkEndTag(TAG_KEY_STYLE, parser);
         }
 
         private void startKeyboard() {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 0837e17..3ab2493 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.keyboard;
 
+import android.text.InputType;
 import android.text.TextUtils;
 import android.view.inputmethod.EditorInfo;
 
@@ -25,10 +26,8 @@
 import java.util.Arrays;
 import java.util.Locale;
 
-// TODO: Move to com.android.inputmethod.keyboard.internal package.
 /**
- * Represents the parameters necessary to construct a new LatinKeyboard,
- * which also serve as a unique identifier for each keyboard type.
+ * Unique identifier for each keyboard type.
  */
 public class KeyboardId {
     public static final int MODE_TEXT = 0;
@@ -54,34 +53,37 @@
     private static final int F2KEY_MODE_SHORTCUT_IME = 2;
     private static final int F2KEY_MODE_SHORTCUT_IME_OR_SETTINGS = 3;
 
+    private static final int IME_ACTION_CUSTOM_LABEL = EditorInfo.IME_MASK_ACTION + 1;
+
     public final Locale mLocale;
     public final int mOrientation;
     public final int mWidth;
     public final int mMode;
     public final int mElementId;
-    private final int mInputType;
-    private final int mImeOptions;
+    private final EditorInfo mEditorInfo;
     private final boolean mSettingsKeyEnabled;
     public final boolean mClobberSettingsKey;
     public final boolean mShortcutKeyEnabled;
     public final boolean mHasShortcutKey;
+    public final String mCustomActionLabel;
 
     private final int mHashCode;
 
     public KeyboardId(int elementId, Locale locale, int orientation, int width, int mode,
-            int inputType, int imeOptions, boolean settingsKeyEnabled, boolean clobberSettingsKey,
+            EditorInfo editorInfo, boolean settingsKeyEnabled, boolean clobberSettingsKey,
             boolean shortcutKeyEnabled, boolean hasShortcutKey) {
         this.mLocale = locale;
         this.mOrientation = orientation;
         this.mWidth = width;
         this.mMode = mode;
         this.mElementId = elementId;
-        this.mInputType = inputType;
-        this.mImeOptions = imeOptions;
+        this.mEditorInfo = editorInfo;
         this.mSettingsKeyEnabled = settingsKeyEnabled;
         this.mClobberSettingsKey = clobberSettingsKey;
         this.mShortcutKeyEnabled = shortcutKeyEnabled;
         this.mHasShortcutKey = hasShortcutKey;
+        this.mCustomActionLabel = (editorInfo.actionLabel != null)
+                ? editorInfo.actionLabel.toString() : null;
 
         this.mHashCode = hashCode(this);
     }
@@ -98,7 +100,9 @@
                 id.mClobberSettingsKey,
                 id.mShortcutKeyEnabled,
                 id.mHasShortcutKey,
+                id.isMultiLine(),
                 id.imeAction(),
+                id.mCustomActionLabel,
                 id.mLocale
         });
     }
@@ -116,7 +120,9 @@
                 && other.mClobberSettingsKey == this.mClobberSettingsKey
                 && other.mShortcutKeyEnabled == this.mShortcutKeyEnabled
                 && other.mHasShortcutKey == this.mHasShortcutKey
+                && other.isMultiLine() == this.isMultiLine()
                 && other.imeAction() == this.imeAction()
+                && TextUtils.equals(other.mCustomActionLabel, this.mCustomActionLabel)
                 && other.mLocale.equals(this.mLocale);
     }
 
@@ -124,20 +130,17 @@
         return mElementId < ELEMENT_SYMBOLS;
     }
 
-    // This should be aligned with {@link KeyboardShiftState#isShiftLocked}.
     public boolean isAlphabetShiftLockedKeyboard() {
         return mElementId == ELEMENT_ALPHABET_SHIFT_LOCKED
                 || mElementId == ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED;
     }
 
-    // This should be aligned with {@link KeyboardShiftState#isShiftedOrShiftLocked}.
     public boolean isAlphabetShiftedOrShiftLockedKeyboard() {
         return isAlphabetKeyboard() && mElementId != ELEMENT_ALPHABET;
     }
 
-    // This should be aligned with {@link KeyboardShiftState#isManualShifted}.
     public boolean isAlphabetManualShiftedKeyboard() {
-        return mElementId != ELEMENT_ALPHABET_MANUAL_SHIFTED;
+        return mElementId == ELEMENT_ALPHABET_MANUAL_SHIFTED;
     }
 
     public boolean isSymbolsKeyboard() {
@@ -154,22 +157,30 @@
 
     public boolean navigateAction() {
         // Note: Turn off checking navigation flag to show TAB key for now.
-        boolean navigateAction = InputTypeCompatUtils.isWebInputType(mInputType);
+        boolean navigateAction = InputTypeCompatUtils.isWebInputType(mEditorInfo.inputType);
 //                || EditorInfoCompatUtils.hasFlagNavigateNext(mImeOptions)
 //                || EditorInfoCompatUtils.hasFlagNavigatePrevious(mImeOptions);
         return navigateAction;
     }
 
     public boolean passwordInput() {
-        return InputTypeCompatUtils.isPasswordInputType(mInputType)
-                || InputTypeCompatUtils.isVisiblePasswordInputType(mInputType);
+        final int inputType = mEditorInfo.inputType;
+        return InputTypeCompatUtils.isPasswordInputType(inputType)
+                || InputTypeCompatUtils.isVisiblePasswordInputType(inputType);
+    }
+
+    public boolean isMultiLine() {
+        return (mEditorInfo.inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) != 0;
     }
 
     public int imeAction() {
-        // We are interested only in {@link EditorInfo#IME_MASK_ACTION} enum value and
-        // {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION}.
-        return mImeOptions & (
-                EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
+        if ((mEditorInfo.imeOptions & EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) {
+            return EditorInfo.IME_ACTION_NONE;
+        } else if (mEditorInfo.actionLabel != null) {
+            return IME_ACTION_CUSTOM_LABEL;
+        } else {
+            return mEditorInfo.imeOptions & EditorInfo.IME_MASK_ACTION;
+        }
     }
 
     public boolean hasSettingsKey() {
@@ -208,7 +219,7 @@
                 mLocale,
                 (mOrientation == 1 ? "port" : "land"), mWidth,
                 modeName(mMode),
-                EditorInfoCompatUtils.imeOptionsName(imeAction()),
+                imeAction(),
                 f2KeyModeName(f2KeyMode()),
                 (mClobberSettingsKey ? " clobberSettingsKey" : ""),
                 (navigateAction() ? " navigateAction" : ""),
@@ -255,6 +266,11 @@
         }
     }
 
+    public static String actionName(int actionId) {
+        return (actionId == IME_ACTION_CUSTOM_LABEL) ? "actionCustomLabel"
+                : EditorInfoCompatUtils.imeActionName(actionId);
+    }
+
     public static String f2KeyModeName(int f2KeyMode) {
         switch (f2KeyMode) {
         case F2KEY_MODE_NONE: return "none";
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
index 82eaa1d..f27170a 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
@@ -62,6 +62,8 @@
             new HashMap<KeyboardId, SoftReference<Keyboard>>();
     private static final KeysCache sKeysCache = new KeysCache();
 
+    private static final EditorInfo EMPTY_EDITOR_INFO = new EditorInfo();
+
     public static class KeyboardSetException extends RuntimeException {
         public final KeyboardId mKeyboardId;
         public KeyboardSetException(Throwable cause, KeyboardId keyboardId) {
@@ -94,8 +96,7 @@
 
     static class Params {
         int mMode;
-        int mInputType;
-        int mImeOptions;
+        EditorInfo mEditorInfo;
         boolean mTouchPositionCorrectionEnabled;
         boolean mSettingsKeyEnabled;
         boolean mVoiceKeyEnabled;
@@ -192,9 +193,8 @@
         final boolean hasShortcutKey = params.mVoiceKeyEnabled
                 && (isSymbols != params.mVoiceKeyOnMain);
         return new KeyboardId(keyboardSetElementId, params.mLocale, params.mOrientation,
-                params.mWidth, params.mMode, params.mInputType, params.mImeOptions,
-                params.mSettingsKeyEnabled, params.mNoSettingsKey, params.mVoiceKeyEnabled,
-                hasShortcutKey);
+                params.mWidth, params.mMode, params.mEditorInfo, params.mSettingsKeyEnabled,
+                params.mNoSettingsKey, params.mVoiceKeyEnabled, hasShortcutKey);
     }
 
     public static class Builder {
@@ -213,10 +213,7 @@
             final Params params = mParams;
 
             params.mMode = Utils.getKeyboardMode(editorInfo);
-            if (editorInfo != null) {
-                params.mInputType = editorInfo.inputType;
-                params.mImeOptions = editorInfo.imeOptions;
-            }
+            params.mEditorInfo = (editorInfo != null) ? editorInfo : EMPTY_EDITOR_INFO;
             params.mNoSettingsKey = Utils.inPrivateImeOptions(
                     mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, mEditorInfo);
         }
@@ -232,7 +229,8 @@
                 boolean touchPositionCorrectionEnabled) {
             final boolean deprecatedForceAscii = Utils.inPrivateImeOptions(
                     mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo);
-            final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii(mParams.mImeOptions)
+            final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii(
+                    mParams.mEditorInfo.imeOptions)
                     || deprecatedForceAscii;
             mParams.mLocale = (forceAscii && !asciiCapable) ? Locale.US : inputLocale;
             mParams.mTouchPositionCorrectionEnabled = touchPositionCorrectionEnabled;
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 870c7cb..88a4157 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -92,13 +92,13 @@
     private final Drawable mAutoCorrectionSpacebarLedIcon;
     private static final int SPACE_LED_LENGTH_PERCENT = 80;
 
-    // Mini keyboard
+    // More keys keyboard
     private PopupWindow mMoreKeysWindow;
     private MoreKeysPanel mMoreKeysPanel;
     private int mMoreKeysPanelPointerTrackerId;
     private final WeakHashMap<Key, MoreKeysPanel> mMoreKeysPanelCache =
             new WeakHashMap<Key, MoreKeysPanel>();
-    private final boolean mConfigShowMiniKeyboardAtTouchedPoint;
+    private final boolean mConfigShowMoreKeysKeyboardAtTouchedPoint;
 
     private final PointerTrackerParams mPointerTrackerParams;
     private final boolean mIsSpacebarTriggeringPopupByLongPress;
@@ -137,7 +137,7 @@
                 break;
             case MSG_LONGPRESS_KEY:
                 if (tracker != null) {
-                    keyboardView.openMiniKeyboardIfRequired(tracker.getKey(), tracker);
+                    keyboardView.openMoreKeysKeyboardIfRequired(tracker.getKey(), tracker);
                 } else {
                     KeyboardSwitcher.getInstance().onLongPressTimeout(msg.arg1);
                 }
@@ -338,8 +338,8 @@
                 R.styleable.LatinKeyboardView_keyHysteresisDistance, 0);
         mKeyDetector = new KeyDetector(keyHysteresisDistance);
         mKeyTimerHandler = new KeyTimerHandler(this, keyTimerParams);
-        mConfigShowMiniKeyboardAtTouchedPoint = a.getBoolean(
-                R.styleable.LatinKeyboardView_showMiniKeyboardAtTouchedPoint, false);
+        mConfigShowMoreKeysKeyboardAtTouchedPoint = a.getBoolean(
+                R.styleable.LatinKeyboardView_showMoreKeysKeyboardAtTouchedPoint, false);
         a.recycle();
 
         PointerTracker.setParameters(mPointerTrackerParams);
@@ -435,7 +435,7 @@
         super.cancelAllMessages();
     }
 
-    private boolean openMiniKeyboardIfRequired(Key parentKey, PointerTracker tracker) {
+    private boolean openMoreKeysKeyboardIfRequired(Key parentKey, PointerTracker tracker) {
         // Check if we have a popup layout specified first.
         if (mMoreKeysLayout == 0) {
             return false;
@@ -458,19 +458,19 @@
         if (container == null)
             throw new NullPointerException();
 
-        final MiniKeyboardView miniKeyboardView =
-                (MiniKeyboardView)container.findViewById(R.id.mini_keyboard_view);
+        final MoreKeysKeyboardView moreKeysKeyboardView =
+                (MoreKeysKeyboardView)container.findViewById(R.id.more_keys_keyboard_view);
         final Keyboard parentKeyboard = getKeyboard();
-        final Keyboard miniKeyboard = new MiniKeyboard.Builder(
+        final Keyboard moreKeysKeyboard = new MoreKeysKeyboard.Builder(
                 this, parentKeyboard.mMoreKeysTemplate, parentKey, parentKeyboard).build();
-        miniKeyboardView.setKeyboard(miniKeyboard);
+        moreKeysKeyboardView.setKeyboard(moreKeysKeyboard);
         container.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
 
-        return miniKeyboardView;
+        return moreKeysKeyboardView;
     }
 
     /**
-     * Called when a key is long pressed. By default this will open mini keyboard associated
+     * Called when a key is long pressed. By default this will open more keys keyboard associated
      * with this key.
      * @param parentKey the key that was long pressed
      * @param tracker the pointer tracker which pressed the parent key
@@ -524,13 +524,13 @@
         if (mMoreKeysWindow == null) {
             mMoreKeysWindow = new PopupWindow(getContext());
             mMoreKeysWindow.setBackgroundDrawable(null);
-            mMoreKeysWindow.setAnimationStyle(R.style.MiniKeyboardAnimation);
+            mMoreKeysWindow.setAnimationStyle(R.style.MoreKeysKeyboardAnimation);
         }
         mMoreKeysPanel = moreKeysPanel;
         mMoreKeysPanelPointerTrackerId = tracker.mPointerId;
 
         final Keyboard keyboard = getKeyboard();
-        final int pointX = (mConfigShowMiniKeyboardAtTouchedPoint) ? tracker.getLastX()
+        final int pointX = (mConfigShowMoreKeysKeyboardAtTouchedPoint) ? tracker.getLastX()
                 : parentKey.mX + parentKey.mWidth / 2;
         final int pointY = parentKey.mY - keyboard.mVerticalGap;
         moreKeysPanel.showMoreKeysPanel(
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
similarity index 83%
rename from java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
rename to java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index 4648da1..83155f7 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -21,10 +21,10 @@
 import com.android.inputmethod.keyboard.internal.KeySpecParser;
 import com.android.inputmethod.latin.R;
 
-public class MiniKeyboard extends Keyboard {
+public class MoreKeysKeyboard extends Keyboard {
     private final int mDefaultKeyCoordX;
 
-    private MiniKeyboard(Builder.MiniKeyboardParams params) {
+    private MoreKeysKeyboard(Builder.MoreKeysKeyboardParams params) {
         super(params);
         mDefaultKeyCoordX = params.getDefaultKeyCoordX() + params.mDefaultKeyWidth / 2;
     }
@@ -33,21 +33,21 @@
         return mDefaultKeyCoordX;
     }
 
-    public static class Builder extends Keyboard.Builder<Builder.MiniKeyboardParams> {
+    public static class Builder extends Keyboard.Builder<Builder.MoreKeysKeyboardParams> {
         private final String[] mMoreKeys;
 
-        public static class MiniKeyboardParams extends Keyboard.Params {
+        public static class MoreKeysKeyboardParams extends Keyboard.Params {
             /* package */int mTopRowAdjustment;
             public int mNumRows;
             public int mNumColumns;
             public int mLeftKeys;
             public int mRightKeys; // includes default key.
 
-            public MiniKeyboardParams() {
+            public MoreKeysKeyboardParams() {
                 super();
             }
 
-            /* package for test */MiniKeyboardParams(int numKeys, int maxColumns, int keyWidth,
+            /* package for test */MoreKeysKeyboardParams(int numKeys, int maxColumns, int keyWidth,
                     int rowHeight, int coordXInParent, int parentKeyboardWidth) {
                 super();
                 setParameters(numKeys, maxColumns, keyWidth, rowHeight, coordXInParent,
@@ -55,21 +55,21 @@
             }
 
             /**
-             * Set keyboard parameters of mini keyboard.
+             * Set keyboard parameters of more keys keyboard.
              *
-             * @param numKeys number of keys in this mini keyboard.
-             * @param maxColumns number of maximum columns of this mini keyboard.
-             * @param keyWidth mini keyboard key width in pixel, including horizontal gap.
-             * @param rowHeight mini keyboard row height in pixel, including vertical gap.
-             * @param coordXInParent coordinate x of the popup key in parent keyboard.
+             * @param numKeys number of keys in this more keys keyboard.
+             * @param maxColumns number of maximum columns of this more keys keyboard.
+             * @param keyWidth more keys keyboard key width in pixel, including horizontal gap.
+             * @param rowHeight more keys keyboard row height in pixel, including vertical gap.
+             * @param coordXInParent coordinate x of the key preview in parent keyboard.
              * @param parentKeyboardWidth parent keyboard width in pixel.
              */
             public void setParameters(int numKeys, int maxColumns, int keyWidth, int rowHeight,
                     int coordXInParent, int parentKeyboardWidth) {
                 if (parentKeyboardWidth / keyWidth < maxColumns) {
                     throw new IllegalArgumentException(
-                            "Keyboard is too small to hold mini keyboard: " + parentKeyboardWidth
-                                    + " " + keyWidth + " " + maxColumns);
+                            "Keyboard is too small to hold more keys keyboard: "
+                                    + parentKeyboardWidth + " " + keyWidth + " " + maxColumns);
                 }
                 mDefaultKeyWidth = keyWidth;
                 mDefaultRowHeight = rowHeight;
@@ -95,14 +95,14 @@
                     leftKeys = numLeftKeys;
                     rightKeys = numRightKeys;
                 }
-                // Shift right if the left edge of mini keyboard is on the edge of parent keyboard
-                // unless the parent key is on the left edge.
+                // Shift right if the left edge of more keys keyboard is on the edge of parent
+                // keyboard unless the parent key is on the left edge.
                 if (leftKeys * keyWidth >= coordXInParent && leftKeys > 0) {
                     leftKeys--;
                     rightKeys++;
                 }
-                // Shift left if the right edge of mini keyboard is on the edge of parent keyboard
-                // unless the parent key is on the right edge.
+                // Shift left if the right edge of more keys keyboard is on the edge of parent
+                // keyboard unless the parent key is on the right edge.
                 if (rightKeys * keyWidth + coordXInParent >= parentKeyboardWidth && rightKeys > 1) {
                     leftKeys++;
                     rightKeys--;
@@ -204,10 +204,10 @@
         }
 
         public Builder(KeyboardView view, int xmlId, Key parentKey, Keyboard parentKeyboard) {
-            super(view.getContext(), new MiniKeyboardParams());
+            super(view.getContext(), new MoreKeysKeyboardParams());
             load(xmlId, parentKeyboard.mId);
 
-            // TODO: Mini keyboard's vertical gap is currently calculated heuristically.
+            // TODO: More keys keyboard's vertical gap is currently calculated heuristically.
             // Should revise the algorithm.
             mParams.mVerticalGap = parentKeyboard.mVerticalGap / 2;
             mMoreKeys = parentKey.mMoreKeys;
@@ -215,8 +215,9 @@
             final int previewWidth = view.mKeyPreviewDrawParams.mPreviewBackgroundWidth;
             final int previewHeight = view.mKeyPreviewDrawParams.mPreviewBackgroundHeight;
             final int width, height;
-            // Use pre-computed width and height if these values are available and mini keyboard
-            // has only one key to mitigate visual flicker between key preview and mini keyboard.
+            // Use pre-computed width and height if these values are available and more keys
+            // keyboard has only one key to mitigate visual flicker between key preview and more
+            // keys keyboard.
             if (view.isKeyPreviewPopupEnabled() && mMoreKeys.length == 1 && previewWidth > 0
                     && previewHeight > 0) {
                 width = previewWidth;
@@ -231,7 +232,7 @@
 
         private static int getMaxKeyWidth(KeyboardView view, String[] moreKeys, int minKeyWidth) {
             final int padding = (int) view.getContext().getResources()
-                    .getDimension(R.dimen.mini_keyboard_key_horizontal_padding);
+                    .getDimension(R.dimen.more_keys_keyboard_key_horizontal_padding);
             Paint paint = null;
             int maxWidth = minKeyWidth;
             for (String moreKeySpec : moreKeys) {
@@ -252,8 +253,8 @@
         }
 
         @Override
-        public MiniKeyboard build() {
-            final MiniKeyboardParams params = mParams;
+        public MoreKeysKeyboard build() {
+            final MoreKeysKeyboardParams params = mParams;
             for (int n = 0; n < mMoreKeys.length; n++) {
                 final String moreKeySpec = mMoreKeys[n];
                 final int row = n / params.mNumColumns;
@@ -262,7 +263,7 @@
                 params.markAsEdgeKey(key, row);
                 params.onAddKey(key);
             }
-            return new MiniKeyboard(params);
+            return new MoreKeysKeyboard(params);
         }
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
similarity index 83%
rename from java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java
rename to java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index 72d5b68..b030dd9 100644
--- a/java/src/com/android/inputmethod/keyboard/MiniKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -28,10 +28,10 @@
 import com.android.inputmethod.latin.R;
 
 /**
- * A view that renders a virtual {@link MiniKeyboard}. It handles rendering of keys and detecting
- * key presses and touch movements.
+ * A view that renders a virtual {@link MoreKeysKeyboard}. It handles rendering of keys and
+ * detecting key presses and touch movements.
  */
-public class MiniKeyboardView extends KeyboardView implements MoreKeysPanel {
+public class MoreKeysKeyboardView extends KeyboardView implements MoreKeysPanel {
     private final int[] mCoordinates = new int[2];
 
     private final KeyDetector mKeyDetector;
@@ -43,7 +43,7 @@
 
     private static final TimerProxy EMPTY_TIMER_PROXY = new TimerProxy.Adapter();
 
-    private final KeyboardActionListener mMiniKeyboardListener =
+    private final KeyboardActionListener mMoreKeysKeyboardListener =
             new KeyboardActionListener.Adapter() {
         @Override
         public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
@@ -71,16 +71,16 @@
         }
     };
 
-    public MiniKeyboardView(Context context, AttributeSet attrs) {
-        this(context, attrs, R.attr.miniKeyboardViewStyle);
+    public MoreKeysKeyboardView(Context context, AttributeSet attrs) {
+        this(context, attrs, R.attr.moreKeysKeyboardViewStyle);
     }
 
-    public MiniKeyboardView(Context context, AttributeSet attrs, int defStyle) {
+    public MoreKeysKeyboardView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
         final Resources res = context.getResources();
         mKeyDetector = new MoreKeysDetector(
-                res.getDimension(R.dimen.mini_keyboard_slide_allowance));
+                res.getDimension(R.dimen.more_keys_keyboard_slide_allowance));
         setKeyPreviewPopupEnabled(false, 0);
     }
 
@@ -110,7 +110,7 @@
 
     @Override
     public KeyboardActionListener getKeyboardActionListener() {
-        return mMiniKeyboardListener;
+        return mMoreKeysKeyboardListener;
     }
 
     @Override
@@ -125,7 +125,7 @@
 
     @Override
     public void setKeyPreviewPopupEnabled(boolean previewEnabled, int delay) {
-        // Mini keyboard needs no pop-up key preview displayed, so we pass always false with a
+        // More keys keyboard needs no pop-up key preview displayed, so we pass always false with a
         // delay of 0. The delay does not matter actually since the popup is not shown anyway.
         super.setKeyPreviewPopupEnabled(false, 0);
     }
@@ -136,13 +136,13 @@
         mController = controller;
         mListener = listener;
         final View container = (View)getParent();
-        final MiniKeyboard miniKeyboard = (MiniKeyboard)getKeyboard();
+        final MoreKeysKeyboard moreKeysKeyboard = (MoreKeysKeyboard)getKeyboard();
 
         parentView.getLocationInWindow(mCoordinates);
-        final int miniKeyboardLeft = pointX - miniKeyboard.getDefaultCoordX()
+        final int moreKeysKeyboardLeft = pointX - moreKeysKeyboard.getDefaultCoordX()
                 + parentView.getPaddingLeft();
-        final int x = wrapUp(Math.max(0, Math.min(miniKeyboardLeft,
-                parentView.getWidth() - miniKeyboard.mOccupiedWidth))
+        final int x = wrapUp(Math.max(0, Math.min(moreKeysKeyboardLeft,
+                parentView.getWidth() - moreKeysKeyboard.mOccupiedWidth))
                 - container.getPaddingLeft() + mCoordinates[0],
                 container.getMeasuredWidth(), 0, parentView.getWidth());
         final int y = pointY
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 2d1a008..41e7ef4 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -59,7 +59,7 @@
         mKeyHeight = keyHeight;
         mGridNeighbors = new Key[mGridSize][];
         if (minWidth == 0 || height == 0) {
-            // No proximity required. Keyboard might be mini keyboard.
+            // No proximity required. Keyboard might be more keys keyboard.
             return;
         }
         computeNearestNeighbors(keyWidth, keys, touchPositionCorrection, additionalProximityChars);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
index e3c5da4..1626a14 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
@@ -133,18 +133,28 @@
         return label;
     }
 
+    private static String getOutputTextInternal(String moreKeySpec) {
+        final int end = indexOfLabelEnd(moreKeySpec, 0);
+        if (end <= 0) {
+            return null;
+        }
+        if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) {
+            throw new KeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec);
+        }
+        return parseEscape(moreKeySpec.substring(end + /* LABEL_END */1));
+    }
+
     public static String getOutputText(String moreKeySpec) {
         if (hasCode(moreKeySpec)) {
             return null;
         }
-        final int end = indexOfLabelEnd(moreKeySpec, 0);
-        if (end > 0) {
-            if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) {
-                    throw new KeySpecParserError("Multiple " + LABEL_END + ": "
-                            + moreKeySpec);
+        final String outputText = getOutputTextInternal(moreKeySpec);
+        if (outputText != null) {
+            if (Utils.codePointCount(outputText) == 1) {
+                // If output text is one code point, it should be treated as a code.
+                // See {@link #getCode(Resources, String)}.
+                return null;
             }
-            final String outputText = parseEscape(
-                    moreKeySpec.substring(end + /* LABEL_END */1));
             if (!TextUtils.isEmpty(outputText)) {
                 return outputText;
             }
@@ -170,7 +180,13 @@
             final int code = res.getInteger(resId);
             return code;
         }
-        if (indexOfLabelEnd(moreKeySpec, 0) > 0) {
+        final String outputText = getOutputTextInternal(moreKeySpec);
+        if (outputText != null) {
+            // If output text is one code point, it should be treated as a code.
+            // See {@link #getOutputText(String)}.
+            if (Utils.codePointCount(outputText) == 1) {
+                return outputText.codePointAt(0);
+            }
             return Keyboard.CODE_OUTPUT_TEXT;
         }
         final String label = getLabel(moreKeySpec);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
index 6ec56ca..12a9c51 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java
@@ -40,17 +40,13 @@
         public String[] getStringArray(TypedArray a, int index);
         public String getString(TypedArray a, int index);
         public int getInt(TypedArray a, int index, int defaultValue);
-        public int getFlag(TypedArray a, int index, int defaultValue);
+        public int getFlag(TypedArray a, int index);
     }
 
-    private static class EmptyKeyStyle implements KeyStyle {
-        EmptyKeyStyle() {
-            // Nothing to do.
-        }
-
+    static class EmptyKeyStyle implements KeyStyle {
         @Override
         public String[] getStringArray(TypedArray a, int index) {
-            return parseStringArray(a, index);
+            return KeyStyles.parseStringArray(a, index);
         }
 
         @Override
@@ -64,50 +60,47 @@
         }
 
         @Override
-        public int getFlag(TypedArray a, int index, int defaultValue) {
-            return a.getInt(index, defaultValue);
-        }
-
-        protected static String[] parseStringArray(TypedArray a, int index) {
-            if (!a.hasValue(index))
-                return null;
-            return KeySpecParser.parseCsvString(
-                    a.getString(index), a.getResources(), R.string.english_ime_name);
+        public int getFlag(TypedArray a, int index) {
+            return a.getInt(index, 0);
         }
     }
 
-    private static class DeclaredKeyStyle extends EmptyKeyStyle {
-        private final HashMap<Integer, Object> mAttributes = new HashMap<Integer, Object>();
+    static class DeclaredKeyStyle implements KeyStyle {
+        private final HashMap<Integer, Object> mStyleAttributes = new HashMap<Integer, Object>();
 
         @Override
         public String[] getStringArray(TypedArray a, int index) {
-            return a.hasValue(index)
-                    ? super.getStringArray(a, index) : (String[])mAttributes.get(index);
+            if (a.hasValue(index)) {
+                return parseStringArray(a, index);
+            }
+            return (String[])mStyleAttributes.get(index);
         }
 
         @Override
         public String getString(TypedArray a, int index) {
-            return a.hasValue(index)
-                    ? super.getString(a, index) : (String)mAttributes.get(index);
+            if (a.hasValue(index)) {
+                return a.getString(index);
+            }
+            return (String)mStyleAttributes.get(index);
         }
 
         @Override
         public int getInt(TypedArray a, int index, int defaultValue) {
-            final Integer value = (Integer)mAttributes.get(index);
-            return super.getInt(a, index, (value != null) ? value : defaultValue);
+            if (a.hasValue(index)) {
+                return a.getInt(index, defaultValue);
+            }
+            final Integer styleValue = (Integer)mStyleAttributes.get(index);
+            return styleValue != null ? styleValue : defaultValue;
         }
 
         @Override
-        public int getFlag(TypedArray a, int index, int defaultValue) {
-            final Integer value = (Integer)mAttributes.get(index);
-            return super.getFlag(a, index, defaultValue) | (value != null ? value : 0);
+        public int getFlag(TypedArray a, int index) {
+            final int value = a.getInt(index, 0);
+            final Integer styleValue = (Integer)mStyleAttributes.get(index);
+            return (styleValue != null ? styleValue : 0) | value;
         }
 
-        DeclaredKeyStyle() {
-            super();
-        }
-
-        void parseKeyStyleAttributes(TypedArray keyAttr) {
+        void readKeyAttributes(TypedArray keyAttr) {
             // TODO: Currently not all Key attributes can be declared as style.
             readInt(keyAttr, R.styleable.Keyboard_Key_code);
             readInt(keyAttr, R.styleable.Keyboard_Key_altCode);
@@ -126,52 +119,68 @@
         }
 
         private void readString(TypedArray a, int index) {
-            if (a.hasValue(index))
-                mAttributes.put(index, a.getString(index));
+            if (a.hasValue(index)) {
+                mStyleAttributes.put(index, a.getString(index));
+            }
         }
 
         private void readInt(TypedArray a, int index) {
-            if (a.hasValue(index))
-                mAttributes.put(index, a.getInt(index, 0));
+            if (a.hasValue(index)) {
+                mStyleAttributes.put(index, a.getInt(index, 0));
+            }
         }
 
         private void readFlag(TypedArray a, int index) {
-            final Integer value = (Integer)mAttributes.get(index);
-            if (a.hasValue(index))
-                mAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0));
+            final Integer value = (Integer)mStyleAttributes.get(index);
+            if (a.hasValue(index)) {
+                mStyleAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0));
+            }
         }
 
         private void readStringArray(TypedArray a, int index) {
             final String[] value = parseStringArray(a, index);
-            if (value != null)
-                mAttributes.put(index, value);
+            if (value != null) {
+                mStyleAttributes.put(index, value);
+            }
         }
 
-        void addParent(DeclaredKeyStyle parentStyle) {
-            mAttributes.putAll(parentStyle.mAttributes);
+        void addParentStyleAttributes(DeclaredKeyStyle parentStyle) {
+            mStyleAttributes.putAll(parentStyle.mStyleAttributes);
         }
     }
 
+    static String[] parseStringArray(TypedArray a, int index) {
+        if (a.hasValue(index)) {
+            return KeySpecParser.parseCsvString(
+                    a.getString(index), a.getResources(), R.string.english_ime_name);
+        }
+        return null;
+    }
+
     public void parseKeyStyleAttributes(TypedArray keyStyleAttr, TypedArray keyAttrs,
             XmlPullParser parser) throws XmlPullParserException {
         final String styleName = keyStyleAttr.getString(R.styleable.Keyboard_KeyStyle_styleName);
-        if (DEBUG) Log.d(TAG, String.format("<%s styleName=%s />",
-                Keyboard.Builder.TAG_KEY_STYLE, styleName));
-        if (mStyles.containsKey(styleName))
+        if (DEBUG) {
+            Log.d(TAG, String.format("<%s styleName=%s />",
+                    Keyboard.Builder.TAG_KEY_STYLE, styleName));
+        }
+        if (mStyles.containsKey(styleName)) {
             throw new XmlParseUtils.ParseException(
                     "duplicate key style declared: " + styleName, parser);
+        }
 
         final DeclaredKeyStyle style = new DeclaredKeyStyle();
         if (keyStyleAttr.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) {
             final String parentStyle = keyStyleAttr.getString(
                     R.styleable.Keyboard_KeyStyle_parentStyle);
             final DeclaredKeyStyle parent = mStyles.get(parentStyle);
-            if (parent == null)
+            if (parent == null) {
                 throw new XmlParseUtils.ParseException(
                         "Unknown parentStyle " + parentStyle, parser);
-            style.addParent(parent);
+            }
+            style.addParentStyleAttributes(parent);
         }
-        style.parseKeyStyleAttributes(keyAttrs);
+        style.readKeyAttributes(keyAttrs);
         mStyles.put(styleName, style);
     }
 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 8aaa069..1cb79e7 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -187,7 +187,7 @@
     private View mKeyPreviewBackingView;
     private View mSuggestionsContainer;
     private SuggestionsView mSuggestionsView;
-    private Suggest mSuggest;
+    /* package for tests */ Suggest mSuggest;
     private CompletionInfo[] mApplicationSpecifiedCompletions;
 
     private InputMethodManagerCompatWrapper mImm;
@@ -1225,12 +1225,41 @@
         return mOptionsDialog != null && mOptionsDialog.isShowing();
     }
 
-    private void insertPunctuationFromSuggestionStrip(final InputConnection ic, final int code) {
+    private void insertPunctuationFromSuggestionStrip(final int code) {
         onCodeInput(code, new int[] { code },
                 KeyboardActionListener.SUGGESTION_STRIP_COORDINATE,
                 KeyboardActionListener.SUGGESTION_STRIP_COORDINATE);
     }
 
+    private static int getEditorActionId(EditorInfo editorInfo) {
+        if (editorInfo == null) return 0;
+        return (editorInfo.actionLabel != null)
+                ? editorInfo.actionId
+                : (editorInfo.imeOptions & EditorInfo.IME_MASK_ACTION);
+    }
+
+    private void performeEditorAction(int actionId) {
+        final InputConnection ic = getCurrentInputConnection();
+        if (ic != null) {
+            ic.performEditorAction(actionId);
+        }
+    }
+
+    private void sendKeyCodePoint(int code) {
+        // TODO: Remove this special handling of digit letters.
+        // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}.
+        if (code >= '0' && code <= '9') {
+            super.sendKeyChar((char)code);
+            return;
+        }
+
+        final InputConnection ic = getCurrentInputConnection();
+        if (ic != null) {
+            final String text = new String(new int[] { code }, 0, 1);
+            ic.commitText(text, text.length());
+        }
+    }
+
     // Implementation of {@link KeyboardActionListener}.
     @Override
     public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {
@@ -1271,6 +1300,9 @@
         case Keyboard.CODE_SHORTCUT:
             mSubtypeSwitcher.switchToShortcutIME();
             break;
+        case Keyboard.CODE_ACTION_ENTER:
+            performeEditorAction(getEditorActionId(getCurrentInputEditorInfo()));
+            break;
         case Keyboard.CODE_TAB:
             handleTab();
             // There are two cases for tab. Either we send a "next" event, that may change the
@@ -1308,7 +1340,7 @@
         commitTyped(ic);
         text = specificTldProcessingOnTextInput(ic, text);
         if (SPACE_STATE_PHANTOM == mSpaceState) {
-            sendKeyChar((char)Keyboard.CODE_SPACE);
+            sendKeyCodePoint(Keyboard.CODE_SPACE);
         }
         ic.commitText(text, 1);
         ic.endBatchEdit();
@@ -1327,10 +1359,12 @@
             // Not a tld: do nothing.
             return text;
         }
+        // We have a TLD (or something that looks like this): make sure we don't add
+        // a space even if currently in phantom mode.
+        mSpaceState = SPACE_STATE_NONE;
         final CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
         if (lastOne != null && lastOne.length() == 1
                 && lastOne.charAt(0) == Keyboard.CODE_PERIOD) {
-            mSpaceState = SPACE_STATE_NONE;
             return text.subSequence(1, text.length());
         } else {
             return text;
@@ -1399,7 +1433,7 @@
             }
 
             if (SPACE_STATE_DOUBLE == spaceState) {
-                if (revertDoubleSpace(ic)) {
+                if (revertDoubleSpaceWhileInBatchEdit(ic)) {
                     // No need to reset mSpaceState, it has already be done (that's why we
                     // receive it as a parameter)
                     return;
@@ -1453,10 +1487,12 @@
         }
     }
 
+    // TODO: Implement next and previous actions using other key code than tab's code.
     private void handleTab() {
         final int imeOptions = getCurrentInputEditorInfo().imeOptions;
         if (!EditorInfoCompatUtils.hasFlagNavigateNext(imeOptions)
                 && !EditorInfoCompatUtils.hasFlagNavigatePrevious(imeOptions)) {
+            // TODO: This should be {@link #sendKeyCodePoint(int)}.
             sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
             return;
         }
@@ -1475,6 +1511,28 @@
         }
     }
 
+    // ic may be null
+    private boolean maybeStripSpaceWhileInBatchEdit(final InputConnection ic, final int code,
+            final int spaceState, final boolean isFromSuggestionStrip) {
+        if (Keyboard.CODE_ENTER == code && SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
+            removeTrailingSpaceWhileInBatchEdit(ic);
+            return false;
+        } else if ((SPACE_STATE_WEAK == spaceState
+                || SPACE_STATE_SWAP_PUNCTUATION == spaceState)
+                && isFromSuggestionStrip) {
+            if (mSettingsValues.isMagicSpaceSwapper(code)) {
+                return true;
+            } else {
+                if (mSettingsValues.isMagicSpaceStripper(code)) {
+                    removeTrailingSpaceWhileInBatchEdit(ic);
+                }
+                return false;
+            }
+        } else {
+            return false;
+        }
+    }
+
     private void handleCharacter(final int primaryCode, final int[] keyCodes, final int x,
             final int y, final int spaceState) {
         mVoiceProxy.handleCharacter();
@@ -1489,7 +1547,6 @@
     private void handleCharacterWhileInBatchEdit(final int primaryCode, final int[] keyCodes,
             final int x, final int y, final int spaceState, final InputConnection ic) {
         boolean isComposingWord = mWordComposer.isComposingWord();
-        int code = primaryCode;
 
         if (SPACE_STATE_PHANTOM == spaceState &&
                 !mSettingsValues.isSymbolExcludedFromWordSeparators(primaryCode)) {
@@ -1497,17 +1554,18 @@
                 // Sanity check
                 throw new RuntimeException("Should not be composing here");
             }
-            sendKeyChar((char)Keyboard.CODE_SPACE);
+            sendKeyCodePoint(Keyboard.CODE_SPACE);
         }
 
-        if ((isAlphabet(code) || mSettingsValues.isSymbolExcludedFromWordSeparators(code))
+        if ((isAlphabet(primaryCode)
+                || mSettingsValues.isSymbolExcludedFromWordSeparators(primaryCode))
                 && isSuggestionsRequested() && !isCursorTouchingWord()) {
             if (!isComposingWord) {
                 // Reset entirely the composing state anyway, then start composing a new word unless
                 // the character is a single quote. The idea here is, single quote is not a
                 // separator and it should be treated as a normal character, except in the first
                 // position where it should not start composing a word.
-                isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != code);
+                isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != primaryCode);
                 // Here we don't need to reset the last composed word. It will be reset
                 // when we commit this one, if we ever do; if on the other hand we backspace
                 // it entirely and resume suggestions on the previous word, we'd like to still
@@ -1518,7 +1576,7 @@
             }
         }
         if (isComposingWord) {
-            mWordComposer.add(code, keyCodes, x, y);
+            mWordComposer.add(primaryCode, keyCodes, x, y);
             if (ic != null) {
                 // If it's the first letter, make note of auto-caps state
                 if (mWordComposer.size() == 1) {
@@ -1529,14 +1587,17 @@
             }
             mHandler.postUpdateSuggestions();
         } else {
-            sendKeyChar((char)code);
-        }
+            final boolean swapWeakSpace = maybeStripSpaceWhileInBatchEdit(ic, primaryCode,
+                    spaceState, KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x);
 
-        if (mSettingsValues.isWordSeparator(code)) {
-            Utils.Stats.onSeparator((char)code, x, y);
-        } else {
-            Utils.Stats.onNonSeparator((char)code, x, y);
+            sendKeyCodePoint(primaryCode);
+
+            if (swapWeakSpace) {
+                swapSwapperAndSpaceWhileInBatchEdit(ic);
+                mSpaceState = SPACE_STATE_WEAK;
+            }
         }
+        Utils.Stats.onNonSeparator((char)primaryCode, x, y);
     }
 
     // Returns true if we did an autocorrection, false otherwise.
@@ -1572,29 +1633,10 @@
             }
         }
 
-        final boolean swapWeakSpace;
-        if (Keyboard.CODE_ENTER == primaryCode && SPACE_STATE_SWAP_PUNCTUATION == spaceState) {
-            removeTrailingSpaceWhileInBatchEdit(ic);
-            swapWeakSpace = false;
-        } else if ((SPACE_STATE_WEAK == spaceState || SPACE_STATE_SWAP_PUNCTUATION == spaceState)
-                && KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x) {
-            if (mSettingsValues.isMagicSpaceSwapper(primaryCode)) {
-                swapWeakSpace = true;
-            } else {
-                swapWeakSpace = false;
-                if (mSettingsValues.isMagicSpaceStripper(primaryCode)) {
-                    removeTrailingSpaceWhileInBatchEdit(ic);
-                }
-            }
-        } else {
-            swapWeakSpace = false;
-        }
+        final boolean swapWeakSpace = maybeStripSpaceWhileInBatchEdit(ic, primaryCode, spaceState,
+                KeyboardActionListener.SUGGESTION_STRIP_COORDINATE == x);
 
-        // TODO: rethink interactions of sendKeyChar, commitText("\n") and actions. sendKeyChar
-        // with a CODE_ENTER parameter will have the default InputMethodService implementation
-        // possibly redirect on the keyboard action. That may be the right thing to do, but
-        // on Shift+Enter, it's generally not, so we may want to do the redirection right here.
-        sendKeyChar((char)primaryCode);
+        sendKeyCodePoint(primaryCode);
 
         if (Keyboard.CODE_SPACE == primaryCode) {
             if (isSuggestionsRequested()) {
@@ -1613,7 +1655,7 @@
         } else {
             if (swapWeakSpace) {
                 swapSwapperAndSpaceWhileInBatchEdit(ic);
-                mSpaceState = SPACE_STATE_WEAK;
+                mSpaceState = SPACE_STATE_SWAP_PUNCTUATION;
             } else if (SPACE_STATE_PHANTOM == spaceState) {
                 // If we are in phantom space state, and the user presses a separator, we want to
                 // stay in phantom space state so that the next keypress has a chance to add the
@@ -1869,52 +1911,40 @@
     }
 
     @Override
-    public void pickSuggestionManually(int index, CharSequence suggestion) {
+    public void pickSuggestionManually(final int index, final CharSequence suggestion) {
         mComposingStateManager.onFinishComposingText();
-        SuggestedWords suggestions = mSuggestionsView.getSuggestions();
+        final SuggestedWords suggestions = mSuggestionsView.getSuggestions();
         mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion,
                 mSettingsValues.mWordSeparators);
 
-        final InputConnection ic = getCurrentInputConnection();
-        if (ic != null) {
-            ic.beginBatchEdit();
-        }
         if (mInputAttributes.mApplicationSpecifiedCompletionOn
                 && mApplicationSpecifiedCompletions != null
                 && index >= 0 && index < mApplicationSpecifiedCompletions.length) {
-            if (ic != null) {
-                final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index];
-                ic.commitCompletion(completionInfo);
-            }
             if (mSuggestionsView != null) {
                 mSuggestionsView.clear();
             }
             mKeyboardSwitcher.updateShiftState();
+            final InputConnection ic = getCurrentInputConnection();
             if (ic != null) {
+                ic.beginBatchEdit();
+                final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index];
+                ic.commitCompletion(completionInfo);
                 ic.endBatchEdit();
             }
             return;
         }
 
-        // If this is a punctuation, apply it through the normal key press
-        if (suggestion.length() == 1 && (mSettingsValues.isWordSeparator(suggestion.charAt(0))
-                || mSettingsValues.isSuggestedPunctuation(suggestion.charAt(0)))) {
+        // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput
+        if (suggestion.length() == 1 && isShowingPunctuationList()) {
             // Word separators are suggested before the user inputs something.
             // So, LatinImeLogger logs "" as a user's input.
             LatinImeLogger.logOnManualSuggestion(
                     "", suggestion.toString(), index, suggestions.mWords);
-            final CharSequence outputText = mSettingsValues.mSuggestPuncOutputTextList
-                    .getWord(index);
-            final int primaryCode = outputText.charAt(0);
-            // Find out whether the previous character is a space. If it is, as a special case
-            // for punctuation entered through the suggestion strip, it should be swapped
-            // if it was a magic or a weak space. This is meant to help in case the user
-            // pressed space on purpose of displaying the suggestion strip punctuation.
-            insertPunctuationFromSuggestionStrip(ic, primaryCode);
-            // TODO: the following endBatchEdit seems useless, check
-            if (ic != null) {
-                ic.endBatchEdit();
-            }
+            // Rely on onCodeInput to do the complicated swapping/stripping logic consistently.
+            final int primaryCode = suggestion.charAt(0);
+            onCodeInput(primaryCode, new int[] { primaryCode },
+                    KeyboardActionListener.SUGGESTION_STRIP_COORDINATE,
+                    KeyboardActionListener.SUGGESTION_STRIP_COORDINATE);
             return;
         }
         // We need to log before we commit, because the word composer will store away the user
@@ -1967,9 +1997,6 @@
                 mHandler.postUpdateSuggestions();
             }
         }
-        if (ic != null) {
-            ic.endBatchEdit();
-        }
     }
 
     /**
@@ -2081,21 +2108,20 @@
         CharSequence toLeft = ic.getTextBeforeCursor(1, 0);
         CharSequence toRight = ic.getTextAfterCursor(1, 0);
         if (!TextUtils.isEmpty(toLeft)
-                && !mSettingsValues.isWordSeparator(toLeft.charAt(0))
-                && !mSettingsValues.isSuggestedPunctuation(toLeft.charAt(0))) {
+                && !mSettingsValues.isWordSeparator(toLeft.charAt(0))) {
             return true;
         }
         if (!TextUtils.isEmpty(toRight)
-                && !mSettingsValues.isWordSeparator(toRight.charAt(0))
-                && !mSettingsValues.isSuggestedPunctuation(toRight.charAt(0))) {
+                && !mSettingsValues.isWordSeparator(toRight.charAt(0))) {
             return true;
         }
         return false;
     }
 
     // "ic" must not be null
-    private static boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) {
-        CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
+    private static boolean sameAsTextBeforeCursor(final InputConnection ic,
+            final CharSequence text) {
+        final CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0);
         return TextUtils.equals(text, beforeText);
     }
 
@@ -2212,13 +2238,14 @@
             }
         }
         ic.deleteSurroundingText(restartLength, 0);
+        mComposingStateManager.onStartComposingText();
         ic.setComposingText(mWordComposer.getTypedWord(), 1);
         mHandler.cancelUpdateBigramPredictions();
         mHandler.postUpdateSuggestions();
     }
 
     // "ic" must not be null
-    private boolean revertDoubleSpace(final InputConnection ic) {
+    private boolean revertDoubleSpaceWhileInBatchEdit(final InputConnection ic) {
         mHandler.cancelDoubleSpacesTimer();
         // Here we test whether we indeed have a period and a space before us. This should not
         // be needed, but it's there just in case something went wrong.
@@ -2231,10 +2258,8 @@
                     + "\". \" just before the cursor.");
             return false;
         }
-        ic.beginBatchEdit();
         ic.deleteSurroundingText(2, 0);
         ic.commitText("  ", 1);
-        ic.endBatchEdit();
         return true;
     }
 
diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java
index 589cb6f..6b65231 100644
--- a/java/src/com/android/inputmethod/latin/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/SettingsValues.java
@@ -222,10 +222,6 @@
                 res.getBoolean(R.bool.config_default_vibration_enabled));
     }
 
-    public boolean isSuggestedPunctuation(int code) {
-        return mSuggestPuncs.contains(String.valueOf((char)code));
-    }
-
     public boolean isWordSeparator(int code) {
         return mWordSeparators.contains(String.valueOf((char)code));
     }
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index f418968..a1a329a 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -90,11 +90,11 @@
      * @return the number of keystrokes
      */
     public final int size() {
-        return mTypedWord.length();
+        return mCodes.size();
     }
 
     public final boolean isComposingWord() {
-        return size() > 0;
+        return mCodes.size() > 0;
     }
 
     /**
@@ -125,8 +125,8 @@
      * @param codes the array of unicode values
      */
     public void add(int primaryCode, int[] codes, int x, int y) {
-        final int newIndex = size();
-        mTypedWord.append((char) primaryCode);
+        final int newIndex = mCodes.size();
+        mTypedWord.appendCodePoint(primaryCode);
         correctPrimaryJuxtapos(primaryCode, codes);
         mCodes.add(codes);
         if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) {
@@ -171,8 +171,8 @@
             final KeyDetector keyDetector) {
         reset();
         final int length = word.length();
-        for (int i = 0; i < length; ++i) {
-            int codePoint = word.charAt(i);
+        for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) {
+            int codePoint = Character.codePointAt(word, i);
             addKeyInfo(codePoint, keyboard, keyDetector);
         }
     }
@@ -207,16 +207,25 @@
      * Delete the last keystroke as a result of hitting backspace.
      */
     public void deleteLast() {
-        final int size = size();
+        final int size = mCodes.size();
         if (size > 0) {
-            final int lastPos = size - 1;
-            char lastChar = mTypedWord.charAt(lastPos);
-            mCodes.remove(lastPos);
-            // TODO: This crashes and catches fire if the code point doesn't fit a char
-            mTypedWord.deleteCharAt(lastPos);
+            mCodes.remove(size - 1);
+            // Note: mTypedWord.length() and mCodes.length differ when there are surrogate pairs
+            final int stringBuilderLength = mTypedWord.length();
+            if (stringBuilderLength < size) {
+                throw new RuntimeException(
+                        "In WordComposer: mCodes and mTypedWords have non-matching lengths");
+            }
+            final int lastChar = mTypedWord.codePointBefore(stringBuilderLength);
+            if (Character.isSupplementaryCodePoint(lastChar)) {
+                mTypedWord.delete(stringBuilderLength - 2, stringBuilderLength);
+            } else {
+                mTypedWord.deleteCharAt(stringBuilderLength - 1);
+            }
             if (Character.isUpperCase(lastChar)) mCapsCount--;
         }
-        if (size() == 0) {
+        // We may have deleted the last one.
+        if (0 == mCodes.size()) {
             mIsFirstCharCapitalized = false;
         }
         if (mTrailingSingleQuotesCount > 0) {
diff --git a/native/src/correction.cpp b/native/src/correction.cpp
index 5f11452..087219e 100644
--- a/native/src/correction.cpp
+++ b/native/src/correction.cpp
@@ -159,10 +159,10 @@
     }
 }
 
-int Correction::getFreqForSplitTwoWords(const int *freqArray, const int *wordLengthArray,
-        const bool isSpaceProximity, const unsigned short *word) {
-    return Correction::RankingAlgorithm::calcFreqForSplitTwoWords(freqArray, wordLengthArray, this,
-            isSpaceProximity, word);
+int Correction::getFreqForSplitMultipleWords(const int *freqArray, const int *wordLengthArray,
+        const int wordCount, const bool isSpaceProximity, const unsigned short *word) {
+    return Correction::RankingAlgorithm::calcFreqForSplitMultipleWords(freqArray, wordLengthArray,
+            wordCount, this, isSpaceProximity, word);
 }
 
 int Correction::getFinalFreq(const int freq, unsigned short **word, int *wordLength) {
@@ -911,45 +911,85 @@
 }
 
 /* static */
-int Correction::RankingAlgorithm::calcFreqForSplitTwoWords(
-        const int *freqArray, const int *wordLengthArray, const Correction* correction,
-        const bool isSpaceProximity, const unsigned short *word) {
-    const int firstFreq = freqArray[0];
-    const int secondFreq = freqArray[1];
-    const int firstWordLength = wordLengthArray[0];
-    const int secondWordLength = wordLengthArray[1];
+int Correction::RankingAlgorithm::calcFreqForSplitMultipleWords(
+        const int *freqArray, const int *wordLengthArray, const int wordCount,
+        const Correction* correction, const bool isSpaceProximity, const unsigned short *word) {
     const int typedLetterMultiplier = correction->TYPED_LETTER_MULTIPLIER;
 
     bool firstCapitalizedWordDemotion = false;
-    if (firstWordLength >= 2) {
-        firstCapitalizedWordDemotion = isUpperCase(word[0]);
+    bool secondCapitalizedWordDemotion = false;
+
+    {
+        // TODO: Handle multiple capitalized word demotion properly
+        const int firstWordLength = wordLengthArray[0];
+        const int secondWordLength = wordLengthArray[1];
+        if (firstWordLength >= 2) {
+            firstCapitalizedWordDemotion = isUpperCase(word[0]);
+        }
+
+        if (secondWordLength >= 2) {
+            // FIXME: word[firstWordLength + 1] is incorrect.
+            secondCapitalizedWordDemotion = isUpperCase(word[firstWordLength + 1]);
+        }
     }
 
-    bool secondCapitalizedWordDemotion = false;
-    if (secondWordLength >= 2) {
-        secondCapitalizedWordDemotion = isUpperCase(word[firstWordLength + 1]);
-    }
 
     const bool capitalizedWordDemotion =
             firstCapitalizedWordDemotion ^ secondCapitalizedWordDemotion;
 
-    if (firstWordLength == 0 || secondWordLength == 0) {
+    int totalLength = 0;
+    int totalFreq = 0;
+    for (int i = 0; i < wordCount; ++i){
+        const int wordLength = wordLengthArray[i];
+        if (wordLength <= 0) {
+            return 0;
+        }
+        totalLength += wordLength;
+        const int demotionRate = 100 - TWO_WORDS_CORRECTION_DEMOTION_BASE / (wordLength + 1);
+        int tempFirstFreq = freqArray[i];
+        multiplyRate(demotionRate, &tempFirstFreq);
+        totalFreq += tempFirstFreq;
+    }
+
+    if (totalLength <= 0 || totalFreq <= 0) {
         return 0;
     }
-    const int firstDemotionRate = 100 - TWO_WORDS_CORRECTION_DEMOTION_BASE / (firstWordLength + 1);
-    int tempFirstFreq = firstFreq;
-    multiplyRate(firstDemotionRate, &tempFirstFreq);
 
-    const int secondDemotionRate = 100
-            - TWO_WORDS_CORRECTION_DEMOTION_BASE / (secondWordLength + 1);
-    int tempSecondFreq = secondFreq;
-    multiplyRate(secondDemotionRate, &tempSecondFreq);
-
-    const int totalLength = firstWordLength + secondWordLength;
-
+    // TODO: Currently totalFreq is adjusted to two word metrix.
     // Promote pairFreq with multiplying by 2, because the word length is the same as the typed
     // length.
-    int totalFreq = tempFirstFreq + tempSecondFreq;
+    totalFreq = totalFreq * 2 / wordCount;
+    if (wordCount > 2) {
+        // Safety net for 3+ words -- Caveats: many heuristics and workarounds here.
+        int oneLengthCounter = 0;
+        int twoLengthCounter = 0;
+        for (int i = 0; i < wordCount; ++i) {
+            const int wordLength = wordLengthArray[i];
+            // TODO: Use bigram instead of this safety net
+            if (i < wordCount - 1) {
+                const int nextWordLength = wordLengthArray[i + 1];
+                if (wordLength == 1 && nextWordLength == 2) {
+                    // Safety net to filter 1 length and 2 length sequential words
+                    return 0;
+                }
+            }
+            const int freq = freqArray[i];
+            // Demote too short weak words
+            if (wordLength <= 4 && freq <= MAX_FREQ * 2 / 3 /* heuristic... */) {
+                multiplyRate(100 * freq / MAX_FREQ, &totalFreq);
+            }
+            if (wordLength == 1) {
+                ++oneLengthCounter;
+            } else if (wordLength == 2) {
+                ++twoLengthCounter;
+            }
+            if (oneLengthCounter >= 2 || (oneLengthCounter + twoLengthCounter) >= 4) {
+                // Safety net to filter too many short words
+                return 0;
+            }
+        }
+        multiplyRate(MULTIPLE_WORDS_DEMOTION_RATE, &totalFreq);
+    }
 
     // This is a workaround to try offsetting the not-enough-demotion which will be done in
     // calcNormalizedScore in Utils.java.
@@ -993,9 +1033,9 @@
     }
 
     if (DEBUG_CORRECTION_FREQ) {
-        AKLOGI("Two words (%d, %d) (%d, %d) %d, %d", firstFreq, secondFreq, firstWordLength,
-                secondWordLength, capitalizedWordDemotion, totalFreq);
-        DUMP_WORD(word, firstWordLength);
+        AKLOGI("Multiple words (%d, %d) (%d, %d) %d, %d", freqArray[0], freqArray[1],
+                wordLengthArray[0], wordLengthArray[1], capitalizedWordDemotion, totalFreq);
+        DUMP_WORD(word, wordLengthArray[0]);
     }
 
     return totalFreq;
diff --git a/native/src/correction.h b/native/src/correction.h
index 9559bbf..2114eff 100644
--- a/native/src/correction.h
+++ b/native/src/correction.h
@@ -121,9 +121,9 @@
 
     bool needsToPrune() const;
 
-    int getFreqForSplitTwoWords(
-            const int *freqArray, const int *wordLengthArray, const bool isSpaceProximity,
-            const unsigned short *word);
+    int getFreqForSplitMultipleWords(
+            const int *freqArray, const int *wordLengthArray, const int wordCount,
+            const bool isSpaceProximity, const unsigned short *word);
     int getFinalFreq(const int freq, unsigned short **word, int* wordLength);
     int getFinalFreqForSubQueue(const int freq, unsigned short **word, int* wordLength,
             const int inputLength);
@@ -151,8 +151,8 @@
         static int calculateFinalFreq(const int inputIndex, const int depth,
                 const int freq, int *editDistanceTable, const Correction* correction,
                 const int inputLength);
-        static int calcFreqForSplitTwoWords(const int *freqArray, const int *wordLengthArray,
-                const Correction* correction, const bool isSpaceProximity,
+        static int calcFreqForSplitMultipleWords(const int *freqArray, const int *wordLengthArray,
+                const int wordCount, const Correction* correction, const bool isSpaceProximity,
                 const unsigned short *word);
         static double calcNormalizedScore(const unsigned short* before, const int beforeLength,
                 const unsigned short* after, const int afterLength, const int score);
diff --git a/native/src/defines.h b/native/src/defines.h
index 5b5c548..ffadb11 100644
--- a/native/src/defines.h
+++ b/native/src/defines.h
@@ -208,6 +208,7 @@
 #define ZERO_DISTANCE_PROMOTION_RATE 110
 #define NEUTRAL_SCORE_SQUARED_RADIUS 8.0f
 #define HALF_SCORE_SQUARED_RADIUS 32.0f
+#define MAX_FREQ 255
 
 // This must be greater than or equal to MAX_WORD_LENGTH defined in BinaryDictionary.java
 // This is only used for the size of array. Not to be used in c functions.
@@ -222,7 +223,9 @@
 #define SUB_QUEUE_MAX_WORDS 1
 #define SUB_QUEUE_MAX_COUNT 10
 #define SUB_QUEUE_MIN_WORD_LENGTH 4
-#define MULTIPLE_WORDS_SUGGESTION_MAX_WORDS 2
+#define MULTIPLE_WORDS_SUGGESTION_MAX_WORDS 10
+#define MULTIPLE_WORDS_DEMOTION_RATE 80
+#define MIN_INPUT_LENGTH_FOR_THREE_OR_MORE_WORDS_CORRECTION 6
 
 #define TWO_WORDS_CORRECTION_WITH_OTHER_ERROR_THRESHOLD 0.39
 #define START_TWO_WORDS_CORRECTION_THRESHOLD 0.22
@@ -230,7 +233,6 @@
 #define MAX_DEPTH_MULTIPLIER 3
 
 #define FIRST_WORD_INDEX 0
-#define SECOND_WORD_INDEX 1
 
 // TODO: Reduce this constant if possible; check the maximum number of umlauts in the same German
 // word in the dictionary
@@ -248,7 +250,7 @@
 #define NEUTRAL_AREA_RADIUS_RATIO 1.3f
 
 // DEBUG
-#define INPUTLENGTH_FOR_DEBUG 10
+#define INPUTLENGTH_FOR_DEBUG -1
 #define MIN_OUTPUT_INDEX_FOR_DEBUG -1
 
 #endif // LATINIME_DEFINES_H
diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp
index 597e5c8..155bdcb 100644
--- a/native/src/unigram_dictionary.cpp
+++ b/native/src/unigram_dictionary.cpp
@@ -224,7 +224,7 @@
     // Multiple word suggestions
     if (SUGGEST_MULTIPLE_WORDS
             && inputLength >= MIN_USER_TYPED_LENGTH_FOR_MULTIPLE_WORD_SUGGESTION) {
-        getSplitTwoWordsSuggestions(proximityInfo, xcoordinates, ycoordinates, codes,
+        getSplitMultipleWordsSuggestions(proximityInfo, xcoordinates, ycoordinates, codes,
                 useFullEditDistance, inputLength, correction, queuePool,
                 hasAutoCorrectionCandidate);
     }
@@ -445,17 +445,18 @@
         if (outputWordStartPos + nextWordLength >= MAX_WORD_LENGTH) {
             return false;
         }
-        outputWord[outputWordStartPos + tempOutputWordLength] = SPACE;
+        outputWord[tempOutputWordLength] = SPACE;
         if (outputWordLength) {
             ++*outputWordLength;
         }
     } else if (currentWordIndex >= 1) {
         // TODO: Handle 3 or more words
-        const int pairFreq = correction->getFreqForSplitTwoWords(
-                freqArray, wordLengthArray, isSpaceProximity, outputWord);
+        const int pairFreq = correction->getFreqForSplitMultipleWords(
+                freqArray, wordLengthArray, currentWordIndex + 1, isSpaceProximity, outputWord);
         if (DEBUG_DICT) {
-            AKLOGI("Split two words: %d, %d, %d, %d, (%d)", freqArray[0], freqArray[1], pairFreq,
-                    inputLength, wordLengthArray[0]);
+            DUMP_WORD(outputWord, tempOutputWordLength);
+            AKLOGI("Split two words: %d, %d, %d, %d, (%d) %d", freqArray[0], freqArray[1], pairFreq,
+                    inputLength, wordLengthArray[0], tempOutputWordLength);
         }
         addWord(outputWord, tempOutputWordLength, pairFreq, queuePool->getMasterQueue());
     }
@@ -473,30 +474,46 @@
         // Return if the last word index
         return;
     }
-    for (int i = 1; i < inputLength; ++i) {
-        int tempOutputWordLength = 0;
-        // First word
-        int inputWordStartPos = 0;
-        int inputWordLength = i;
+    if (startWordIndex >= 1
+            && (hasAutoCorrectionCandidate
+                    || inputLength < MIN_INPUT_LENGTH_FOR_THREE_OR_MORE_WORDS_CORRECTION)) {
+        // Do not suggest 3+ words if already has auto correction candidate
+        return;
+    }
+    for (int i = startInputPos + 1; i < inputLength; ++i) {
         if (DEBUG_CORRECTION_FREQ) {
-            AKLOGI("Two words, %d", inputWordLength);
+            AKLOGI("Multi words(%d), start in %d sep %d start out %d",
+                    startWordIndex, startInputPos, i, outputWordLength);
+            DUMP_WORD(outputWord, outputWordLength);
         }
+        int tempOutputWordLength = 0;
+        // Current word
+        int inputWordStartPos = startInputPos;
+        int inputWordLength = i - startInputPos;
         if (!getSubStringSuggestion(proximityInfo, xcoordinates, ycoordinates, codes,
                 useFullEditDistance, correction, queuePool, inputLength, hasAutoCorrectionCandidate,
-                FIRST_WORD_INDEX, inputWordStartPos, inputWordLength, 0, true /* not used */,
-                freqArray, wordLengthArray, outputWord, &tempOutputWordLength)) {
+                startWordIndex, inputWordStartPos, inputWordLength, outputWordLength,
+                true /* not used */, freqArray, wordLengthArray, outputWord,
+                &tempOutputWordLength)) {
             continue;
         }
 
-        // Second word
+        if (DEBUG_CORRECTION_FREQ) {
+            AKLOGI("Do missing space correction");
+        }
+        // Next word
         // Missing space
         inputWordStartPos = i;
         inputWordLength = inputLength - i;
-        getSubStringSuggestion(proximityInfo, xcoordinates, ycoordinates, codes,
+        if(!getSubStringSuggestion(proximityInfo, xcoordinates, ycoordinates, codes,
                 useFullEditDistance, correction, queuePool, inputLength, hasAutoCorrectionCandidate,
-                SECOND_WORD_INDEX, inputWordStartPos, inputWordLength, tempOutputWordLength,
-                false /* missing space */, freqArray, wordLengthArray, outputWord,
-                0);
+                startWordIndex + 1, inputWordStartPos, inputWordLength, tempOutputWordLength,
+                false /* missing space */, freqArray, wordLengthArray, outputWord, 0)) {
+            getMultiWordsSuggestionRec(proximityInfo, xcoordinates, ycoordinates, codes,
+                    useFullEditDistance, inputLength, correction, queuePool,
+                    hasAutoCorrectionCandidate, inputWordStartPos, startWordIndex + 1,
+                    tempOutputWordLength, freqArray, wordLengthArray, outputWord);
+        }
 
         // Mistyped space
         ++inputWordStartPos;
@@ -512,15 +529,17 @@
             continue;
         }
 
+        if (DEBUG_CORRECTION_FREQ) {
+            AKLOGI("Do mistyped space correction");
+        }
         getSubStringSuggestion(proximityInfo, xcoordinates, ycoordinates, codes,
                 useFullEditDistance, correction, queuePool, inputLength, hasAutoCorrectionCandidate,
-                SECOND_WORD_INDEX, inputWordStartPos, inputWordLength, tempOutputWordLength,
-                true /* mistyped space */, freqArray, wordLengthArray, outputWord,
-                0);
+                startWordIndex + 1, inputWordStartPos, inputWordLength, tempOutputWordLength,
+                true /* mistyped space */, freqArray, wordLengthArray, outputWord, 0);
     }
 }
 
-void UnigramDictionary::getSplitTwoWordsSuggestions(ProximityInfo *proximityInfo,
+void UnigramDictionary::getSplitMultipleWordsSuggestions(ProximityInfo *proximityInfo,
         const int *xcoordinates, const int *ycoordinates, const int *codes,
         const bool useFullEditDistance, const int inputLength,
         Correction *correction, WordsPriorityQueuePool* queuePool,
diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h
index 2d5d076..396a811 100644
--- a/native/src/unigram_dictionary.h
+++ b/native/src/unigram_dictionary.h
@@ -101,7 +101,7 @@
             const bool useFullEditDistance, const int inputLength, Correction *correction,
             WordsPriorityQueuePool* queuePool, const bool doAutoCompletion, const int maxErrors,
             const int currentWordIndex);
-    void getSplitTwoWordsSuggestions(ProximityInfo *proximityInfo,
+    void getSplitMultipleWordsSuggestions(ProximityInfo *proximityInfo,
             const int *xcoordinates, const int *ycoordinates, const int *codes,
             const bool useFullEditDistance, const int inputLength,
             Correction *correction, WordsPriorityQueuePool* queuePool,
diff --git a/tests/src/com/android/inputmethod/keyboard/MiniKeyboardBuilderTests.java b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java
similarity index 90%
rename from tests/src/com/android/inputmethod/keyboard/MiniKeyboardBuilderTests.java
rename to tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java
index a143bba..b1d6910 100644
--- a/tests/src/com/android/inputmethod/keyboard/MiniKeyboardBuilderTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java
@@ -16,11 +16,11 @@
 
 package com.android.inputmethod.keyboard;
 
-import com.android.inputmethod.keyboard.MiniKeyboard.Builder.MiniKeyboardParams;
-
 import android.test.AndroidTestCase;
 
-public class MiniKeyboardBuilderTests extends AndroidTestCase {
+import com.android.inputmethod.keyboard.MoreKeysKeyboard.Builder.MoreKeysKeyboardParams;
+
+public class MoreKeysKeyboardBuilderTests extends AndroidTestCase {
     private static final int MAX_COLUMNS = 5;
     private static final int WIDTH = 10;
     private static final int HEIGHT = 10;
@@ -41,24 +41,24 @@
     }
 
     public void testLayoutError() {
-        MiniKeyboardParams params = null;
+        MoreKeysKeyboardParams params = null;
         try {
-            params = new MiniKeyboardParams(10, MAX_COLUMNS + 1, WIDTH, HEIGHT, WIDTH * 2,
+            params = new MoreKeysKeyboardParams(10, MAX_COLUMNS + 1, WIDTH, HEIGHT, WIDTH * 2,
                     WIDTH * MAX_COLUMNS);
             fail("Should throw IllegalArgumentException");
         } catch (IllegalArgumentException e) {
-            // Too small keyboard to hold mini keyboard.
+            // Too small keyboard to hold more keys keyboard.
         }
-        assertNull("Too small keyboard to hold mini keyboard", params);
+        assertNull("Too small keyboard to hold more keys keyboard", params);
     }
 
-    // Mini keyboard layout test.
-    // "[n]" represents n-th key position in mini keyboard.
+    // More keys keyboard layout test.
+    // "[n]" represents n-th key position in more keys keyboard.
     // "[1]" is the default key.
 
     // [1]
     public void testLayout1KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(1, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("1 key M0 columns", 1, params.mNumColumns);
         assertEquals("1 key M0 rows", 1, params.mNumRows);
@@ -71,7 +71,7 @@
 
     // |[1]
     public void testLayout1KeyL0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(1, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L0, KEYBOARD_WIDTH);
         assertEquals("1 key L0 columns", 1, params.mNumColumns);
         assertEquals("1 key L0 rows", 1, params.mNumRows);
@@ -84,7 +84,7 @@
 
     // |___ [1]
     public void testLayout1KeyL1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(1, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L1, KEYBOARD_WIDTH);
         assertEquals("1 key L1 columns", 1, params.mNumColumns);
         assertEquals("1 key L1 rows", 1, params.mNumRows);
@@ -97,7 +97,7 @@
 
     // |___ ___ [1]
     public void testLayout1KeyL2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(1, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L2, KEYBOARD_WIDTH);
         assertEquals("1 key L2 columns", 1, params.mNumColumns);
         assertEquals("1 key L2 rows", 1, params.mNumRows);
@@ -110,7 +110,7 @@
 
     // [1]|
     public void testLayout1KeyR0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(1, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R0, KEYBOARD_WIDTH);
         assertEquals("1 key R0 columns", 1, params.mNumColumns);
         assertEquals("1 key R0 rows", 1, params.mNumRows);
@@ -123,7 +123,7 @@
 
     // [1] ___|
     public void testLayout1KeyR1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(1, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R1, KEYBOARD_WIDTH);
         assertEquals("1 key R1 columns", 1, params.mNumColumns);
         assertEquals("1 key R1 rows", 1, params.mNumRows);
@@ -136,7 +136,7 @@
 
     // [1] ___ ___|
     public void testLayout1KeyR2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(1, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(1, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R2, KEYBOARD_WIDTH);
         assertEquals("1 key R2 columns", 1, params.mNumColumns);
         assertEquals("1 key R2 rows", 1, params.mNumRows);
@@ -149,7 +149,7 @@
 
     // [1] [2]
     public void testLayout2KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(2, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("2 key M0 columns", 2, params.mNumColumns);
         assertEquals("2 key M0 rows", 1, params.mNumRows);
@@ -163,7 +163,7 @@
 
     // |[1] [2]
     public void testLayout2KeyL0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(2, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L0, KEYBOARD_WIDTH);
         assertEquals("2 key L0 columns", 2, params.mNumColumns);
         assertEquals("2 key L0 rows", 1, params.mNumRows);
@@ -177,7 +177,7 @@
 
     // |___ [1] [2]
     public void testLayout2KeyL1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(2, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L1, KEYBOARD_WIDTH);
         assertEquals("2 key L1 columns", 2, params.mNumColumns);
         assertEquals("2 key L1 rows", 1, params.mNumRows);
@@ -191,7 +191,7 @@
 
     // |___ ___ [1] [2]
     public void testLayout2KeyL2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(2, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L2, KEYBOARD_WIDTH);
         assertEquals("2 key L2 columns", 2, params.mNumColumns);
         assertEquals("2 key L2 rows", 1, params.mNumRows);
@@ -205,7 +205,7 @@
 
     // [2] [1]|
     public void testLayout2KeyR0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(2, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R0, KEYBOARD_WIDTH);
         assertEquals("2 key R0 columns", 2, params.mNumColumns);
         assertEquals("2 key R0 rows", 1, params.mNumRows);
@@ -219,7 +219,7 @@
 
     // [2] [1] ___|
     public void testLayout2KeyR1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(2, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R1, KEYBOARD_WIDTH);
         assertEquals("2 key R1 columns", 2, params.mNumColumns);
         assertEquals("2 key R1 rows", 1, params.mNumRows);
@@ -233,7 +233,7 @@
 
     // [1] [2] ___ ___|
     public void testLayout2KeyR2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(2, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(2, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R2, KEYBOARD_WIDTH);
         assertEquals("2 key R2 columns", 2, params.mNumColumns);
         assertEquals("2 key R2 rows", 1, params.mNumRows);
@@ -247,7 +247,7 @@
 
     // [3] [1] [2]
     public void testLayout3KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(3, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("3 key columns", 3, params.mNumColumns);
         assertEquals("3 key rows", 1, params.mNumRows);
@@ -262,7 +262,7 @@
 
     // |[1] [2] [3]
     public void testLayout3KeyL0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(3, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L0, KEYBOARD_WIDTH);
         assertEquals("3 key L0 columns", 3, params.mNumColumns);
         assertEquals("3 key L0 rows", 1, params.mNumRows);
@@ -277,7 +277,7 @@
 
     // |___ [1] [2] [3]
     public void testLayout3KeyL1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(3, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L1, KEYBOARD_WIDTH);
         assertEquals("3 key L1 columns", 3, params.mNumColumns);
         assertEquals("3 key L1 rows", 1, params.mNumRows);
@@ -292,7 +292,7 @@
 
     // |___ ___ [3] [1] [2]
     public void testLayout3KeyL2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(3, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L2, KEYBOARD_WIDTH);
         assertEquals("3 key L2 columns", 3, params.mNumColumns);
         assertEquals("3 key L2 rows", 1, params.mNumRows);
@@ -307,7 +307,7 @@
 
     // [3] [2] [1]|
     public void testLayout3KeyR0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(3, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R0, KEYBOARD_WIDTH);
         assertEquals("3 key R0 columns", 3, params.mNumColumns);
         assertEquals("3 key R0 rows", 1, params.mNumRows);
@@ -322,7 +322,7 @@
 
     // [3] [2] [1] ___|
     public void testLayout3KeyR1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(3, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R1, KEYBOARD_WIDTH);
         assertEquals("3 key R1 columns", 3, params.mNumColumns);
         assertEquals("3 key R1 rows", 1, params.mNumRows);
@@ -337,7 +337,7 @@
 
     // [3] [1] [2] ___ ___|
     public void testLayout3KeyR2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(3, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(3, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R2, KEYBOARD_WIDTH);
         assertEquals("3 key R2 columns", 3, params.mNumColumns);
         assertEquals("3 key R2 rows", 1, params.mNumRows);
@@ -352,7 +352,7 @@
 
     // [3] [1] [2] [4]
     public void testLayout4KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(4, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("4 key columns", 4, params.mNumColumns);
         assertEquals("4 key rows", 1, params.mNumRows);
@@ -368,7 +368,7 @@
 
     // |[1] [2] [3] [4]
     public void testLayout4KeyL0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(4, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L0, KEYBOARD_WIDTH);
         assertEquals("4 key L0 columns", 4, params.mNumColumns);
         assertEquals("4 key L0 rows", 1, params.mNumRows);
@@ -384,7 +384,7 @@
 
     // |___ [1] [2] [3] [4]
     public void testLayout4KeyL1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(4, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L1, KEYBOARD_WIDTH);
         assertEquals("4 key L1 columns", 4, params.mNumColumns);
         assertEquals("4 key L1 rows", 1, params.mNumRows);
@@ -400,7 +400,7 @@
 
     // |___ ___ [3] [1] [2] [4]
     public void testLayout4KeyL2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(4, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L2, KEYBOARD_WIDTH);
         assertEquals("4 key L2 columns", 4, params.mNumColumns);
         assertEquals("4 key L2 rows", 1, params.mNumRows);
@@ -416,7 +416,7 @@
 
     // [4] [3] [2] [1]|
     public void testLayout4KeyR0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(4, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R0, KEYBOARD_WIDTH);
         assertEquals("4 key R0 columns", 4, params.mNumColumns);
         assertEquals("4 key R0 rows", 1, params.mNumRows);
@@ -432,7 +432,7 @@
 
     // [4] [3] [2] [1] ___|
     public void testLayout4KeyR1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(4, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R1, KEYBOARD_WIDTH);
         assertEquals("4 key R1 columns", 4, params.mNumColumns);
         assertEquals("4 key R1 rows", 1, params.mNumRows);
@@ -448,7 +448,7 @@
 
     // [4] [3] [1] [2] ___ ___|
     public void testLayout4KeyR2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(4, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(4, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R2, KEYBOARD_WIDTH);
         assertEquals("4 key R2 columns", 4, params.mNumColumns);
         assertEquals("4 key R2 rows", 1, params.mNumRows);
@@ -464,7 +464,7 @@
 
     // [5] [3] [1] [2] [4]
     public void testLayout5KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(5, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("5 key columns", 5, params.mNumColumns);
         assertEquals("5 key rows", 1, params.mNumRows);
@@ -481,7 +481,7 @@
 
     // |[1] [2] [3] [4] [5]
     public void testLayout5KeyL0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(5, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L0, KEYBOARD_WIDTH);
         assertEquals("5 key L0 columns", 5, params.mNumColumns);
         assertEquals("5 key L0 rows", 1, params.mNumRows);
@@ -498,7 +498,7 @@
 
     // |___ [1] [2] [3] [4] [5]
     public void testLayout5KeyL1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(5, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L1, KEYBOARD_WIDTH);
         assertEquals("5 key L1 columns", 5, params.mNumColumns);
         assertEquals("5 key L1 rows", 1, params.mNumRows);
@@ -515,7 +515,7 @@
 
     // |___ ___ [3] [1] [2] [4] [5]
     public void testLayout5KeyL2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(5, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L2, KEYBOARD_WIDTH);
         assertEquals("5 key L2 columns", 5, params.mNumColumns);
         assertEquals("5 key L2 rows", 1, params.mNumRows);
@@ -532,7 +532,7 @@
 
     // [5] [4] [3] [2] [1]|
     public void testLayout5KeyR0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(5, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R0, KEYBOARD_WIDTH);
         assertEquals("5 key R0 columns", 5, params.mNumColumns);
         assertEquals("5 key R0 rows", 1, params.mNumRows);
@@ -549,7 +549,7 @@
 
     // [5] [4] [3] [2] [1] ___|
     public void testLayout5KeyR1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(5, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R1, KEYBOARD_WIDTH);
         assertEquals("5 key R1 columns", 5, params.mNumColumns);
         assertEquals("5 key R1 rows", 1, params.mNumRows);
@@ -566,7 +566,7 @@
 
     // [5] [4] [3] [1] [2] ___ ___|
     public void testLayout5KeyR2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(5, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(5, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R2, KEYBOARD_WIDTH);
         assertEquals("5 key R2 columns", 5, params.mNumColumns);
         assertEquals("5 key R2 rows", 1, params.mNumRows);
@@ -584,7 +584,7 @@
     // [6] [4] [5]
     // [3] [1] [2]
     public void testLayout6KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(6, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("6 key columns", 3, params.mNumColumns);
         assertEquals("6 key rows", 2, params.mNumRows);
@@ -603,7 +603,7 @@
     // |[4] [5] [6]
     // |[1] [2] [3]
     public void testLayout6KeyL0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(6, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L0, KEYBOARD_WIDTH);
         assertEquals("6 key L0 columns", 3, params.mNumColumns);
         assertEquals("6 key L0 rows", 2, params.mNumRows);
@@ -622,7 +622,7 @@
     // |___ [4] [5] [6]
     // |___ [1] [2] [3]
     public void testLayout6KeyL1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(6, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L1, KEYBOARD_WIDTH);
         assertEquals("6 key L1 columns", 3, params.mNumColumns);
         assertEquals("6 key L1 rows", 2, params.mNumRows);
@@ -641,7 +641,7 @@
     // |___ ___ [6] [4] [5]
     // |___ ___ [3] [1] [2]
     public void testLayout6KeyL2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(6, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L2, KEYBOARD_WIDTH);
         assertEquals("6 key L2 columns", 3, params.mNumColumns);
         assertEquals("6 key L2 rows", 2, params.mNumRows);
@@ -660,7 +660,7 @@
     // [6] [5] [4]|
     // [3] [2] [1]|
     public void testLayout6KeyR0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(6, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R0, KEYBOARD_WIDTH);
         assertEquals("6 key R0 columns", 3, params.mNumColumns);
         assertEquals("6 key R0 rows", 2, params.mNumRows);
@@ -679,7 +679,7 @@
     // [6] [5] [4] ___|
     // [3] [2] [1] ___|
     public void testLayout6KeyR1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(6, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R1, KEYBOARD_WIDTH);
         assertEquals("6 key R1 columns", 3, params.mNumColumns);
         assertEquals("6 key R1 rows", 2, params.mNumRows);
@@ -698,7 +698,7 @@
     // [6] [4] [5] ___ ___|
     // [3] [1] [2] ___ ___|
     public void testLayout6KeyR2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(6, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(6, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R2, KEYBOARD_WIDTH);
         assertEquals("6 key R2 columns", 3, params.mNumColumns);
         assertEquals("6 key R2 rows", 2, params.mNumRows);
@@ -717,7 +717,7 @@
     //   [7] [5] [6]
     // [3] [1] [2] [4]
     public void testLayout7KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(7, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("7 key columns", 4, params.mNumColumns);
         assertEquals("7 key rows", 2, params.mNumRows);
@@ -737,7 +737,7 @@
     // |[5] [6] [7]
     // |[1] [2] [3] [4]
     public void testLayout7KeyL0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(7, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L0, KEYBOARD_WIDTH);
         assertEquals("7 key L0 columns", 4, params.mNumColumns);
         assertEquals("7 key L0 rows", 2, params.mNumRows);
@@ -757,7 +757,7 @@
     // |___ [5] [6] [7]
     // |___ [1] [2] [3] [4]
     public void testLayout7KeyL1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(7, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L1, KEYBOARD_WIDTH);
         assertEquals("7 key L1 columns", 4, params.mNumColumns);
         assertEquals("7 key L1 rows", 2, params.mNumRows);
@@ -777,7 +777,7 @@
     // |___ ___   [7] [5] [6]
     // |___ ___ [3] [1] [2] [4]
     public void testLayout7KeyL2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(7, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L2, KEYBOARD_WIDTH);
         assertEquals("7 key L2 columns", 4, params.mNumColumns);
         assertEquals("7 key L2 rows", 2, params.mNumRows);
@@ -797,7 +797,7 @@
     //     [7] [6] [5]|
     // [4] [3] [2] [1]|
     public void testLayout7KeyR0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(7, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R0, KEYBOARD_WIDTH);
         assertEquals("7 key R0 columns", 4, params.mNumColumns);
         assertEquals("7 key R0 rows", 2, params.mNumRows);
@@ -817,7 +817,7 @@
     //     [7] [6] [5] ___|
     // [4] [3] [2] [1] ___|
     public void testLayout7KeyR1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(7, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R1, KEYBOARD_WIDTH);
         assertEquals("7 key R1 columns", 4, params.mNumColumns);
         assertEquals("7 key R1 rows", 2, params.mNumRows);
@@ -837,7 +837,7 @@
     //   [7] [5] [6]   ___ ___|
     // [4] [3] [1] [2] ___ ___|
     public void testLayout7KeyR2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(7, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(7, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R2, KEYBOARD_WIDTH);
         assertEquals("7 key R2 columns", 4, params.mNumColumns);
         assertEquals("7 key R2 rows", 2, params.mNumRows);
@@ -856,7 +856,7 @@
 
     // [7] [6] [5] [3] [1] [2] [4] ___|
     public void testLayout7KeyR3Max7() {
-        MiniKeyboardParams params = new MiniKeyboardParams(7, 7, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(7, 7, WIDTH,
                 HEIGHT, XPOS_R3, KEYBOARD_WIDTH);
         assertEquals("7 key R2 columns", 7, params.mNumColumns);
         assertEquals("7 key R2 rows", 1, params.mNumRows);
@@ -876,7 +876,7 @@
     // [7] [5] [6] [8]
     // [3] [1] [2] [4]
     public void testLayout8KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(8, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("8 key M0 columns", 4, params.mNumColumns);
         assertEquals("8 key M0 rows", 2, params.mNumRows);
@@ -897,7 +897,7 @@
     // |[5] [6] [7] [8]
     // |[1] [2] [3] [4]
     public void testLayout8KeyL0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(8, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L0, KEYBOARD_WIDTH);
         assertEquals("8 key L0 columns", 4, params.mNumColumns);
         assertEquals("8 key L0 rows", 2, params.mNumRows);
@@ -918,7 +918,7 @@
     // |___ [5] [6] [7] [8]
     // |___ [1] [2] [3] [4]
     public void testLayout8KeyL1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(8, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L1, KEYBOARD_WIDTH);
         assertEquals("8 key L1 columns", 4, params.mNumColumns);
         assertEquals("8 key L1 rows", 2, params.mNumRows);
@@ -939,7 +939,7 @@
     // |___ ___ [7] [5] [6] [8]
     // |___ ___ [3] [1] [2] [4]
     public void testLayout8KeyL2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(8, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L2, KEYBOARD_WIDTH);
         assertEquals("8 key L2 columns", 4, params.mNumColumns);
         assertEquals("8 key L2 rows", 2, params.mNumRows);
@@ -960,7 +960,7 @@
     // [8] [7] [6] [5]|
     // [4] [3] [2] [1]|
     public void testLayout8KeyR0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(8, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R0, KEYBOARD_WIDTH);
         assertEquals("8 key R0 columns", 4, params.mNumColumns);
         assertEquals("8 key R0 rows", 2, params.mNumRows);
@@ -981,7 +981,7 @@
     // [8] [7] [6] [5] ___|
     // [4] [3] [2] [1] ___|
     public void testLayout8KeyR1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(8, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R1, KEYBOARD_WIDTH);
         assertEquals("8 key R1 columns", 4, params.mNumColumns);
         assertEquals("8 key R1 rows", 2, params.mNumRows);
@@ -1002,7 +1002,7 @@
     // [8] [7] [5] [6] ___ ___|
     // [4] [3] [1] [2] ___ ___|
     public void testLayout8KeyR2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(8, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(8, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R2, KEYBOARD_WIDTH);
         assertEquals("8 key R2 columns", 4, params.mNumColumns);
         assertEquals("8 key R2 rows", 2, params.mNumRows);
@@ -1023,7 +1023,7 @@
     //   [8] [6] [7] [9]
     // [5] [3] [1] [2] [4]
     public void testLayout9KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(9, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("9 key M0 columns", 5, params.mNumColumns);
         assertEquals("9 key M0 rows", 2, params.mNumRows);
@@ -1045,7 +1045,7 @@
     // |[6] [7] [8] [9]
     // |[1] [2] [3] [4] [5]
     public void testLayout9KeyL0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(9, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L0, KEYBOARD_WIDTH);
         assertEquals("9 key L0 columns", 5, params.mNumColumns);
         assertEquals("9 key L0 rows", 2, params.mNumRows);
@@ -1067,7 +1067,7 @@
     // |___ [6] [7] [8] [9]
     // |___ [1] [2] [3] [4] [5]
     public void testLayout9KeyL1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(9, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L1, KEYBOARD_WIDTH);
         assertEquals("9 key L1 columns", 5, params.mNumColumns);
         assertEquals("9 key L1 rows", 2, params.mNumRows);
@@ -1089,7 +1089,7 @@
     // |___ ___   [8] [6] [7] [9]
     // |___ ___ [3] [1] [2] [4] [5]
     public void testLayout9KeyL2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(9, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L2, KEYBOARD_WIDTH);
         assertEquals("9 key L2 columns", 5, params.mNumColumns);
         assertEquals("9 key L2 rows", 2, params.mNumRows);
@@ -1111,7 +1111,7 @@
     //     [9] [8] [7] [6]|
     // [5] [4] [3] [2] [1]|
     public void testLayout9KeyR0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(9, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R0, KEYBOARD_WIDTH);
         assertEquals("9 key R0 columns", 5, params.mNumColumns);
         assertEquals("9 key R0 rows", 2, params.mNumRows);
@@ -1133,7 +1133,7 @@
     //     [9] [8] [7] [6] ___|
     // [5] [4] [3] [2] [1] ___|
     public void testLayout9KeyR1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(9, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R1, KEYBOARD_WIDTH);
         assertEquals("9 key R1 columns", 5, params.mNumColumns);
         assertEquals("9 key R1 rows", 2, params.mNumRows);
@@ -1155,7 +1155,7 @@
     //   [9] [8] [6] [7]   ___ ___|
     // [5] [4] [3] [1] [2] ___ ___|
     public void testLayout9KeyR2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(9, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(9, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R2, KEYBOARD_WIDTH);
         assertEquals("9 key R2 columns", 5, params.mNumColumns);
         assertEquals("9 key R2 rows", 2, params.mNumRows);
@@ -1177,7 +1177,7 @@
     // [A] [8] [6] [7] [9]
     // [5] [3] [1] [2] [4]
     public void testLayout10KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(10, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("10 key M0 columns", 5, params.mNumColumns);
         assertEquals("10 key M0 rows", 2, params.mNumRows);
@@ -1200,7 +1200,7 @@
     // |[6] [7] [8] [9] [A]
     // |[1] [2] [3] [4] [5]
     public void testLayout10KeyL0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(10, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L0, KEYBOARD_WIDTH);
         assertEquals("10 key L0 columns", 5, params.mNumColumns);
         assertEquals("10 key L0 rows", 2, params.mNumRows);
@@ -1223,7 +1223,7 @@
     // |___ [6] [7] [8] [9] [A]
     // |___ [1] [2] [3] [4] [5]
     public void testLayout10KeyL1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(10, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L1, KEYBOARD_WIDTH);
         assertEquals("10 key L1 columns", 5, params.mNumColumns);
         assertEquals("10 key L1 rows", 2, params.mNumRows);
@@ -1246,7 +1246,7 @@
     // |___ ___ [8] [6] [7] [9] [A]
     // |___ ___ [3] [1] [2] [4] [5]
     public void testLayout10KeyL2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(10, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_L2, KEYBOARD_WIDTH);
         assertEquals("10 key L2 columns", 5, params.mNumColumns);
         assertEquals("10 key L2 rows", 2, params.mNumRows);
@@ -1269,7 +1269,7 @@
     // [A] [9] [8] [7] [6]|
     // [5] [4] [3] [2] [1]|
     public void testLayout10KeyR0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(10, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R0, KEYBOARD_WIDTH);
         assertEquals("10 key R0 columns", 5, params.mNumColumns);
         assertEquals("10 key R0 rows", 2, params.mNumRows);
@@ -1292,7 +1292,7 @@
     // [A] [9] [8] [7] [6] ___|
     // [5] [4] [3] [2] [1] ___|
     public void testLayout10KeyR1() {
-        MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(10, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R1, KEYBOARD_WIDTH);
         assertEquals("10 key R1 columns", 5, params.mNumColumns);
         assertEquals("10 key R1 rows", 2, params.mNumRows);
@@ -1315,7 +1315,7 @@
     // [A] [9] [8] [6] [7] ___ ___|
     // [5] [4] [3] [1] [2] ___ ___|
     public void testLayout10KeyR2() {
-        MiniKeyboardParams params = new MiniKeyboardParams(10, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(10, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_R2, KEYBOARD_WIDTH);
         assertEquals("10 key R2 columns", 5, params.mNumColumns);
         assertEquals("10 key R2 rows", 2, params.mNumRows);
@@ -1339,7 +1339,7 @@
     // [7] [5] [6] [8]
     // [3] [1] [2] [4]
     public void testLayout11KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(11, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(11, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("11 key M0 columns", 4, params.mNumColumns);
         assertEquals("11 key M0 rows", 3, params.mNumRows);
@@ -1364,7 +1364,7 @@
     // [7] [5] [6] [8]
     // [3] [1] [2] [4]
     public void testLayout12KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(12, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(12, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("12 key M0 columns", 4, params.mNumColumns);
         assertEquals("12 key M0 rows", 3, params.mNumRows);
@@ -1391,7 +1391,7 @@
     // [A] [8] [6] [7] [9]
     // [5] [3] [1] [2] [4]
     public void testLayout13KeyM0() {
-        MiniKeyboardParams params = new MiniKeyboardParams(13, MAX_COLUMNS, WIDTH,
+        MoreKeysKeyboardParams params = new MoreKeysKeyboardParams(13, MAX_COLUMNS, WIDTH,
                 HEIGHT, XPOS_M0, KEYBOARD_WIDTH);
         assertEquals("13 key M0 columns", 5, params.mNumColumns);
         assertEquals("13 key M0 rows", 3, params.mNumRows);
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
index 429e16d..07f5848 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserTests.java
@@ -109,6 +109,10 @@
                 "@", null, ICON_UNDEFINED, '@');
         assertParser("Single escaped at", "\\@",
                 "@", null, ICON_UNDEFINED, '@');
+        assertParser("Single output text letter", "a|a",
+                "a", null, ICON_UNDEFINED, 'a');
+        assertParser("Single surrogate pair outputText", "G Clef|" + PAIR1,
+                "G Clef", null, ICON_UNDEFINED, CODE1);
         assertParser("Single letter with outputText", "a|abc",
                 "a", "abc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Single letter with surrogate outputText", "a|" + SURROGATE1,
@@ -132,10 +136,10 @@
                 "a", "a@c", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
         assertParser("Single letter with escaped at outputText", "a|\\@bc",
                 "a", "@bc", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Single escaped escape with outputText", "\\\\|\\\\",
-                "\\", "\\", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
-        assertParser("Single escaped bar with outputText", "\\||\\|",
-                "|", "|", ICON_UNDEFINED, Keyboard.CODE_OUTPUT_TEXT);
+        assertParser("Single escaped escape with single outputText", "\\\\|\\\\",
+                "\\", null, ICON_UNDEFINED, '\\');
+        assertParser("Single escaped bar with single outputText", "\\||\\|",
+                "|", null, ICON_UNDEFINED, '|');
         assertParser("Single letter with code", "a|" + CODE_SETTINGS,
                 "a", null, ICON_UNDEFINED, mCodeSettings);
     }
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
index 693352c..9d886da3b 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
@@ -111,6 +111,20 @@
         mLatinIME.onStartInputView(ei, false);
         mLatinIME.onCreateInputMethodInterface().startInput(ic, ei);
         mInputConnection = ic;
+        // Wait for the main dictionary to be loaded (we need it for auto-correction tests)
+        int remainingAttempts = 10;
+        while (remainingAttempts > 0 && !mLatinIME.mSuggest.hasMainDictionary()) {
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+                // Don't do much
+            } finally {
+                --remainingAttempts;
+            }
+        }
+        if (!mLatinIME.mSuggest.hasMainDictionary()) {
+            throw new RuntimeException("Can't initialize the main dictionary");
+        }
     }
 
     // type(int) and type(String): helper methods to send a code point resp. a string to LatinIME.
@@ -145,11 +159,26 @@
     }
 
     public void testPickSuggestionThenBackspace() {
-        final String WORD_TO_TYPE = "tgis";
+        final String WORD_TO_TYPE = "this";
+        final String EXPECTED_RESULT = "this";
         type(WORD_TO_TYPE);
         mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE);
+        mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1);
         type(Keyboard.CODE_DELETE);
-        assertEquals("press suggestion then backspace", WORD_TO_TYPE,
+        assertEquals("press suggestion then backspace", EXPECTED_RESULT,
+                mTextView.getText().toString());
+    }
+
+    public void testPickTypedWordOverAutoCorrectionThenBackspace() {
+        final String WORD_TO_TYPE = "tgis";
+        final String EXPECTED_RESULT = "tgis";
+        type(WORD_TO_TYPE);
+        // Choose the typed word, which should be in position 1 (because position 0 should
+        // be occupied by the "this" auto-correction, as checked by testAutoCorrect())
+        mLatinIME.pickSuggestionManually(1, WORD_TO_TYPE);
+        mLatinIME.onUpdateSelection(0, 0, WORD_TO_TYPE.length(), WORD_TO_TYPE.length(), -1, -1);
+        type(Keyboard.CODE_DELETE);
+        assertEquals("pick typed word over auto-correction then backspace", EXPECTED_RESULT,
                 mTextView.getText().toString());
     }
 
@@ -300,4 +329,71 @@
         }
         assertEquals("delete whole composing word", "", mTextView.getText().toString());
     }
+
+    public void testManuallyPickedWordThenColon() {
+        final String WORD_TO_TYPE = "this";
+        final String PUNCTUATION = ":";
+        final String EXPECTED_RESULT = "this:";
+        type(WORD_TO_TYPE);
+        mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE);
+        type(PUNCTUATION);
+        assertEquals("manually pick word then colon",
+                EXPECTED_RESULT, mTextView.getText().toString());
+    }
+
+    public void testManuallyPickedWordThenOpenParen() {
+        final String WORD_TO_TYPE = "this";
+        final String PUNCTUATION = "(";
+        final String EXPECTED_RESULT = "this (";
+        type(WORD_TO_TYPE);
+        mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE);
+        type(PUNCTUATION);
+        assertEquals("manually pick word then open paren",
+                EXPECTED_RESULT, mTextView.getText().toString());
+    }
+
+    public void testManuallyPickedWordThenCloseParen() {
+        final String WORD_TO_TYPE = "this";
+        final String PUNCTUATION = ")";
+        final String EXPECTED_RESULT = "this)";
+        type(WORD_TO_TYPE);
+        mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE);
+        type(PUNCTUATION);
+        assertEquals("manually pick word then close paren",
+                EXPECTED_RESULT, mTextView.getText().toString());
+    }
+
+    public void testManuallyPickedWordThenSmiley() {
+        final String WORD_TO_TYPE = "this";
+        final String SPECIAL_KEY = ":-)";
+        final String EXPECTED_RESULT = "this :-)";
+        type(WORD_TO_TYPE);
+        mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE);
+        mLatinIME.onTextInput(SPECIAL_KEY);
+        assertEquals("manually pick word then press the smiley key",
+                EXPECTED_RESULT, mTextView.getText().toString());
+    }
+
+    public void testManuallyPickedWordThenDotCom() {
+        final String WORD_TO_TYPE = "this";
+        final String SPECIAL_KEY = ".com";
+        final String EXPECTED_RESULT = "this.com";
+        type(WORD_TO_TYPE);
+        mLatinIME.pickSuggestionManually(0, WORD_TO_TYPE);
+        mLatinIME.onTextInput(SPECIAL_KEY);
+        assertEquals("manually pick word then press the .com key",
+                EXPECTED_RESULT, mTextView.getText().toString());
+    }
+
+    public void testTypeWordTypeDotThenPressDotCom() {
+        final String WORD_TO_TYPE = "this.";
+        final String SPECIAL_KEY = ".com";
+        final String EXPECTED_RESULT = "this.com";
+        type(WORD_TO_TYPE);
+        mLatinIME.onTextInput(SPECIAL_KEY);
+        assertEquals("type word type dot then press the .com key",
+                EXPECTED_RESULT, mTextView.getText().toString());
+    }
+
+    // TODO: Add some tests for non-BMP characters
 }