Merge "Move files under bigram/shortcut to under structure."
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_lmp.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_lmp.9.png
new file mode 100644
index 0000000..814e402
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_lmp.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_lmp.9.png
new file mode 100644
index 0000000..90abe39
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png
new file mode 100644
index 0000000..48eeb3f
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png
new file mode 100644
index 0000000..71e0683
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_lmp.9.png b/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_lmp.9.png
new file mode 100644
index 0000000..6768241
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_lmp.9.png b/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_lmp.9.png
new file mode 100644
index 0000000..10f8e97
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_background_lmp.9.png
new file mode 100644
index 0000000..be39415
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_left_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_left_background_lmp.9.png
new file mode 100644
index 0000000..9fa6d00
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_left_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_left_more_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_left_more_background_lmp.9.png
new file mode 100644
index 0000000..c73269b
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_left_more_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lmp.9.png
new file mode 100644
index 0000000..fffd402
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_more_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_right_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_right_background_lmp.9.png
new file mode 100644
index 0000000..61c23c1
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_right_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_right_more_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_right_more_background_lmp.9.png
new file mode 100644
index 0000000..827d743
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_right_more_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_popup_panel_background_lmp.9.png b/java/res/drawable-hdpi/keyboard_popup_panel_background_lmp.9.png
new file mode 100644
index 0000000..f9dd3b8
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_popup_panel_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_lmp.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_lmp.9.png
new file mode 100644
index 0000000..b7b2dca
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_lmp.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_lmp.9.png
new file mode 100644
index 0000000..4a92b80
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png
new file mode 100644
index 0000000..72125a0
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png
new file mode 100644
index 0000000..82413d4
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_lmp.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_lmp.9.png
new file mode 100644
index 0000000..0493859
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_lmp.9.png b/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_lmp.9.png
new file mode 100644
index 0000000..ee0aae2
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_background_lmp.9.png
new file mode 100644
index 0000000..625490b
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_left_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_left_background_lmp.9.png
new file mode 100644
index 0000000..427c870
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_left_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_left_more_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_left_more_background_lmp.9.png
new file mode 100644
index 0000000..ea75729
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_left_more_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lmp.9.png
new file mode 100644
index 0000000..1911c42
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_more_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_right_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_right_background_lmp.9.png
new file mode 100644
index 0000000..cdef116
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_right_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_right_more_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_right_more_background_lmp.9.png
new file mode 100644
index 0000000..dea5d07
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_right_more_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_popup_panel_background_lmp.9.png b/java/res/drawable-mdpi/keyboard_popup_panel_background_lmp.9.png
new file mode 100644
index 0000000..8965055
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_popup_panel_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_lmp.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_lmp.9.png
new file mode 100644
index 0000000..20251a0
--- /dev/null
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_normal_on_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_lmp.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_lmp.9.png
new file mode 100644
index 0000000..84d1739
--- /dev/null
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png
new file mode 100644
index 0000000..ee4490e
--- /dev/null
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png
new file mode 100644
index 0000000..e812477
--- /dev/null
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed_lmp.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed_lmp.9.png
new file mode 100644
index 0000000..f770962
--- /dev/null
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_light_pressed_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/btn_keyboard_key_popup_selected_lmp.9.png b/java/res/drawable-xhdpi/btn_keyboard_key_popup_selected_lmp.9.png
new file mode 100644
index 0000000..891d000
--- /dev/null
+++ b/java/res/drawable-xhdpi/btn_keyboard_key_popup_selected_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_background_lmp.9.png
new file mode 100644
index 0000000..c211d89
--- /dev/null
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_left_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_left_background_lmp.9.png
new file mode 100644
index 0000000..543bc76
--- /dev/null
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_left_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_left_more_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_left_more_background_lmp.9.png
new file mode 100644
index 0000000..ec42aad
--- /dev/null
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_left_more_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lmp.9.png
new file mode 100644
index 0000000..319e9d7
--- /dev/null
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_more_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_right_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_right_background_lmp.9.png
new file mode 100644
index 0000000..052032b
--- /dev/null
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_right_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_key_feedback_right_more_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_key_feedback_right_more_background_lmp.9.png
new file mode 100644
index 0000000..c7e9d1c
--- /dev/null
+++ b/java/res/drawable-xhdpi/keyboard_key_feedback_right_more_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_popup_panel_background_lmp.9.png b/java/res/drawable-xhdpi/keyboard_popup_panel_background_lmp.9.png
new file mode 100644
index 0000000..36df715
--- /dev/null
+++ b/java/res/drawable-xhdpi/keyboard_popup_panel_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_lmp.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_lmp.9.png
new file mode 100644
index 0000000..97f9625
--- /dev/null
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_normal_on_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_lmp.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_lmp.9.png
new file mode 100644
index 0000000..dfb16a7
--- /dev/null
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png
new file mode 100644
index 0000000..bf1d346
--- /dev/null
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_off_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png
new file mode 100644
index 0000000..9622771
--- /dev/null
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_dark_pressed_on_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_light_pressed_lmp.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_light_pressed_lmp.9.png
new file mode 100644
index 0000000..17144b6
--- /dev/null
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_light_pressed_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/btn_keyboard_key_popup_selected_lmp.9.png b/java/res/drawable-xxhdpi/btn_keyboard_key_popup_selected_lmp.9.png
new file mode 100644
index 0000000..0cbb2ec
--- /dev/null
+++ b/java/res/drawable-xxhdpi/btn_keyboard_key_popup_selected_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lmp.9.png
new file mode 100644
index 0000000..fd2f9e5
--- /dev/null
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_lmp.9.png
new file mode 100644
index 0000000..3ab7900
--- /dev/null
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_lmp.9.png
new file mode 100644
index 0000000..99543a1
--- /dev/null
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_left_more_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lmp.9.png
new file mode 100644
index 0000000..121411a
--- /dev/null
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_more_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_lmp.9.png
new file mode 100644
index 0000000..e9e3792
--- /dev/null
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_lmp.9.png
new file mode 100644
index 0000000..6c1143a
--- /dev/null
+++ b/java/res/drawable-xxhdpi/keyboard_key_feedback_right_more_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/keyboard_popup_panel_background_lmp.9.png b/java/res/drawable-xxhdpi/keyboard_popup_panel_background_lmp.9.png
new file mode 100644
index 0000000..91d5d7f
--- /dev/null
+++ b/java/res/drawable-xxhdpi/keyboard_popup_panel_background_lmp.9.png
Binary files differ
diff --git a/java/res/drawable/btn_keyboard_key_functional_lmp.xml b/java/res/drawable/btn_keyboard_key_functional_lmp.xml
new file mode 100644
index 0000000..427b8d5
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_key_functional_lmp.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- Functional keys. -->
+    <item android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_pressed_lmp" />
+    <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/java/res/drawable/btn_keyboard_key_ics.xml b/java/res/drawable/btn_keyboard_key_ics.xml
index 259bb9b..9db0eee 100644
--- a/java/res/drawable/btn_keyboard_key_ics.xml
+++ b/java/res/drawable/btn_keyboard_key_ics.xml
@@ -39,7 +39,7 @@
 
     <!-- Empty background keys. -->
     <item android:state_empty="true"
-          android:drawable="@drawable/transparent" />
+          android:drawable="@android:color/transparent" />
 
     <!-- Normal keys. -->
     <item android:state_pressed="true"
diff --git a/java/res/drawable/btn_keyboard_key_klp.xml b/java/res/drawable/btn_keyboard_key_klp.xml
index 16b5fa0..500e3ea 100644
--- a/java/res/drawable/btn_keyboard_key_klp.xml
+++ b/java/res/drawable/btn_keyboard_key_klp.xml
@@ -39,7 +39,7 @@
 
     <!-- Empty background keys. -->
     <item android:state_empty="true"
-          android:drawable="@drawable/transparent" />
+          android:drawable="@android:color/transparent" />
 
     <!-- Normal keys. -->
     <item android:state_pressed="true"
diff --git a/java/res/drawable/btn_keyboard_key_lmp.xml b/java/res/drawable/btn_keyboard_key_lmp.xml
new file mode 100644
index 0000000..fdd19df
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_key_lmp.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <!-- Functional keys. -->
+    <item android:state_single="true" android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_pressed_lmp" />
+    <item android:state_single="true"
+          android:drawable="@android:color/transparent" />
+
+    <!-- Action keys. -->
+    <item android:state_active="true" android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_pressed_lmp" />
+    <item android:state_active="true"
+          android:drawable="@android:color/transparent" />
+
+    <!-- Toggle keys. Use checkable/checked state. -->
+    <item android:state_checkable="true" android:state_checked="true" android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_pressed_on_lmp" />
+    <item android:state_checkable="true" android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_pressed_lmp" />
+    <item android:state_checkable="true" android:state_checked="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_normal_on_lmp" />
+    <item android:state_checkable="true"
+          android:drawable="@android:color/transparent" />
+
+    <!-- Empty background keys. -->
+    <item android:state_empty="true"
+          android:drawable="@android:color/transparent" />
+
+    <!-- Normal keys. -->
+    <item android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_light_pressed_lmp" />
+    <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/java/res/drawable/btn_keyboard_key_popup_ics.xml b/java/res/drawable/btn_keyboard_key_popup_ics.xml
index 31b6131..17d646b 100644
--- a/java/res/drawable/btn_keyboard_key_popup_ics.xml
+++ b/java/res/drawable/btn_keyboard_key_popup_ics.xml
@@ -17,5 +17,5 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true"
           android:drawable="@drawable/btn_keyboard_key_popup_selected_ics" />
-    <item android:drawable="@drawable/transparent" />
+    <item android:drawable="@android:color/transparent" />
 </selector>
diff --git a/java/res/drawable/btn_keyboard_key_popup_klp.xml b/java/res/drawable/btn_keyboard_key_popup_klp.xml
index 62cbca8..9dfc93a 100644
--- a/java/res/drawable/btn_keyboard_key_popup_klp.xml
+++ b/java/res/drawable/btn_keyboard_key_popup_klp.xml
@@ -17,5 +17,5 @@
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true"
           android:drawable="@drawable/btn_keyboard_key_popup_selected_klp" />
-    <item android:drawable="@drawable/transparent" />
+    <item android:drawable="@android:color/transparent" />
 </selector>
diff --git a/java/res/drawable/btn_keyboard_key_popup_lmp.xml b/java/res/drawable/btn_keyboard_key_popup_lmp.xml
new file mode 100644
index 0000000..ebedaea
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_key_popup_lmp.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_popup_selected_lmp" />
+    <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/java/res/drawable/btn_keyboard_spacebar_lmp.xml b/java/res/drawable/btn_keyboard_spacebar_lmp.xml
new file mode 100644
index 0000000..516cb07
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_spacebar_lmp.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_light_pressed_lmp" />
+    <item android:drawable="@android:color/transparent" />
+</selector>
diff --git a/java/res/drawable/transparent.xml b/java/res/drawable/btn_suggestion_lmp.xml
similarity index 74%
rename from java/res/drawable/transparent.xml
rename to java/res/drawable/btn_suggestion_lmp.xml
index 855cf2a..c778e23 100644
--- a/java/res/drawable/transparent.xml
+++ b/java/res/drawable/btn_suggestion_lmp.xml
@@ -2,7 +2,7 @@
 <!--
 /*
 **
-** Copyright 2011, The Android Open Source Project
+** Copyright 2014, 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.
@@ -18,13 +18,10 @@
 */
 -->
 
-<shape
+<selector
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle"
 >
-    <solid
-        android:color="@android:color/transparent" />
-    <size
-        android:width="50dp"
-        android:height="40dp" />
-</shape>
+    <item
+        android:state_pressed="true"
+        android:drawable="@drawable/btn_keyboard_key_popup_selected_lmp" />
+</selector>
diff --git a/java/res/drawable/keyboard_key_feedback_lmp.xml b/java/res/drawable/keyboard_key_feedback_lmp.xml
new file mode 100644
index 0000000..cdbe64c
--- /dev/null
+++ b/java/res/drawable/keyboard_key_feedback_lmp.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<selector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <!-- Left edge -->
+    <item latin:state_left_edge="true" latin:state_has_morekeys="true"
+          android:drawable="@drawable/keyboard_key_feedback_left_more_background_lmp" />
+    <item latin:state_left_edge="true"
+          android:drawable="@drawable/keyboard_key_feedback_left_background_lmp" />
+
+    <!-- Right edge -->
+    <item latin:state_right_edge="true" latin:state_has_morekeys="true"
+          android:drawable="@drawable/keyboard_key_feedback_right_more_background_lmp" />
+    <item latin:state_right_edge="true"
+          android:drawable="@drawable/keyboard_key_feedback_right_background_lmp" />
+
+    <item latin:state_has_morekeys="true"
+          android:drawable="@drawable/keyboard_key_feedback_more_background_lmp" />
+    <item android:drawable="@drawable/keyboard_key_feedback_background_lmp" />
+</selector>
diff --git a/java/res/layout/suggestions_strip.xml b/java/res/layout/suggestions_strip.xml
index bff9a1e..36898c8 100644
--- a/java/res/layout/suggestions_strip.xml
+++ b/java/res/layout/suggestions_strip.xml
@@ -64,4 +64,12 @@
             android:textSize="16sp"
             style="?attr/suggestionWordStyle" />
     </LinearLayout>
+    <ImageButton
+        android:id="@+id/suggestions_strip_voice_key"
+        android:layout_width="@dimen/config_suggestions_strip_edge_key_width"
+        android:layout_height="fill_parent"
+        android:layout_alignParentEnd="true"
+        android:layout_alignParentRight="true"
+        android:layout_centerVertical="true"
+        style="?attr/suggestionWordStyle" />
 </merge>
diff --git a/java/res/values-land/config.xml b/java/res/values-land/config.xml
index f72d64f..37bf22f 100644
--- a/java/res/values-land/config.xml
+++ b/java/res/values-land/config.xml
@@ -59,6 +59,7 @@
 
     <dimen name="config_suggestions_strip_height">36dp</dimen>
     <dimen name="config_suggestions_strip_horizontal_margin">54dp</dimen>
+    <dimen name="config_suggestions_strip_edge_key_width">54dp</dimen>
     <dimen name="config_more_suggestions_row_height">36dp</dimen>
     <integer name="config_max_more_suggestions_row">2</integer>
     <fraction name="config_min_more_suggestions_width">60%</fraction>
diff --git a/java/res/values-sw600dp-land/config.xml b/java/res/values-sw600dp-land/config.xml
index 8789e72..ba8b52f 100644
--- a/java/res/values-sw600dp-land/config.xml
+++ b/java/res/values-sw600dp-land/config.xml
@@ -50,6 +50,7 @@
 
     <dimen name="config_suggestions_strip_height">44dp</dimen>
     <dimen name="config_suggestions_strip_horizontal_margin">180.0dp</dimen>
+    <dimen name="config_suggestions_strip_edge_key_width">54dp</dimen>
     <integer name="config_max_more_suggestions_row">5</integer>
     <fraction name="config_min_more_suggestions_width">50%</fraction>
 
diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw600dp/config.xml
index 12e9832..d97538d 100644
--- a/java/res/values-sw600dp/config.xml
+++ b/java/res/values-sw600dp/config.xml
@@ -63,7 +63,8 @@
     <fraction name="config_key_shifted_letter_hint_ratio_5row">27%</fraction>
 
     <dimen name="config_suggestions_strip_height">44dp</dimen>
-    <dimen name="config_suggestions_strip_horizontal_margin">0dp</dimen>
+    <dimen name="config_suggestions_strip_horizontal_margin">54dp</dimen>
+    <dimen name="config_suggestions_strip_edge_key_width">54dp</dimen>
     <dimen name="config_more_suggestions_row_height">44dp</dimen>
     <integer name="config_max_more_suggestions_row">6</integer>
     <fraction name="config_min_more_suggestions_width">90%</fraction>
diff --git a/java/res/values-sw768dp-land/config.xml b/java/res/values-sw768dp-land/config.xml
index 17733f0..63f86ba 100644
--- a/java/res/values-sw768dp-land/config.xml
+++ b/java/res/values-sw768dp-land/config.xml
@@ -51,6 +51,7 @@
 
     <dimen name="config_suggestions_strip_height">44dp</dimen>
     <dimen name="config_suggestions_strip_horizontal_margin">340dp</dimen>
+    <dimen name="config_suggestions_strip_edge_key_width">54dp</dimen>
     <fraction name="config_min_more_suggestions_width">50%</fraction>
 
     <!-- Gesture floating preview text parameters -->
diff --git a/java/res/values-sw768dp/config.xml b/java/res/values-sw768dp/config.xml
index 647cca9..94b38d8 100644
--- a/java/res/values-sw768dp/config.xml
+++ b/java/res/values-sw768dp/config.xml
@@ -62,6 +62,7 @@
 
     <dimen name="config_suggestions_strip_height">44dp</dimen>
     <dimen name="config_suggestions_strip_horizontal_margin">100dp</dimen>
+    <dimen name="config_suggestions_strip_edge_key_width">54dp</dimen>
     <dimen name="config_more_suggestions_row_height">44dp</dimen>
     <integer name="config_max_more_suggestions_row">6</integer>
     <fraction name="config_min_more_suggestions_width">90%</fraction>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 475e92f..290ab50 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -74,6 +74,7 @@
         <!-- Size of the text for spacebar language label, in the proportion of key height. -->
         <attr name="languageOnSpacebarTextRatio" format="fraction" />
         <attr name="languageOnSpacebarTextColor" format="color" />
+        <attr name="languageOnSpacebarTextShadowRadius" format="float" />
         <attr name="languageOnSpacebarTextShadowColor" format="color" />
         <!-- Background image for the spacebar. -->
         <attr name="spacebarBackground" format="reference" />
@@ -431,6 +432,7 @@
             <!--  This should be aligned with KeyboardId.IME_ACTION_* -->
             <enum name="actionCustomLabel" value="0x100" />
         </attr>
+        <attr name="isIconDefined" format="string" />
         <attr name="localeCode" format="string" />
         <attr name="languageCode" format="string" />
         <attr name="countryCode" format="string" />
diff --git a/java/res/values/colors.xml b/java/res/values/colors.xml
index 824928c..baa0887 100644
--- a/java/res/values/colors.xml
+++ b/java/res/values/colors.xml
@@ -26,7 +26,6 @@
     <color name="suggested_word_color_ics">#B233B5E5</color>
     <color name="highlight_translucent_color_ics">#9933B5E5</color>
     <color name="key_text_color_holo">@android:color/white</color>
-    <color name="key_text_shadow_color_holo">@android:color/transparent</color>
     <color name="key_text_inactivated_color_holo">#66E0E4E5</color>
     <color name="key_hint_letter_color_holo">#80000000</color>
     <color name="key_hint_label_color_holo">#A0FFFFFF</color>
@@ -40,6 +39,12 @@
     <color name="typed_word_color_klp">#D8F0F0F0</color>
     <color name="suggested_word_color_klp">#B2F0F0F0</color>
     <color name="highlight_translucent_color_klp">#99E0E0E0</color>
+    <!-- Color resources for LMP theme. Base color = F0F0F0 -->
+    <color name="key_hint_letter_color_lmp">@android:color/white</color>
+    <color name="highlight_color_lmp">#FFF0F0F0</color>
+    <color name="typed_word_color_lmp">#D8F0F0F0</color>
+    <color name="suggested_word_color_lmp">#B2F0F0F0</color>
+    <color name="highlight_translucent_color_lmp">#99E0E0E0</color>
     <!-- Color resources for setup wizard and tutorial -->
     <color name="setup_background">#FFEBEBEB</color>
     <color name="setup_text_dark">#FF707070</color>
diff --git a/java/res/values/config-common.xml b/java/res/values/config-common.xml
index 3fe4b94..1962c0d 100644
--- a/java/res/values/config-common.xml
+++ b/java/res/values/config-common.xml
@@ -24,9 +24,6 @@
          at input history to suggest a hopefully helpful suggestions for the next word? -->
     <bool name="config_default_next_word_prediction">true</bool>
 
-    <!-- This configuration must be aligned with {@link KeyboardTheme#DEFAULT_THEME_ID}. -->
-    <string name="config_default_keyboard_theme_id" translatable="false">2</string>
-
     <integer name="config_delay_update_shift_state">100</integer>
     <integer name="config_double_space_period_timeout">1100</integer>
 
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index 1ab4927..9f556a6 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -64,7 +64,8 @@
     <fraction name="config_key_shifted_letter_hint_ratio_5row">41%</fraction>
 
     <dimen name="config_suggestions_strip_height">40dp</dimen>
-    <dimen name="config_suggestions_strip_horizontal_margin">0dp</dimen>
+    <dimen name="config_suggestions_strip_horizontal_margin">36dp</dimen>
+    <dimen name="config_suggestions_strip_edge_key_width">36dp</dimen>
     <dimen name="config_more_suggestions_row_height">40dp</dimen>
     <integer name="config_max_more_suggestions_row">6</integer>
     <fraction name="config_min_more_suggestions_width">90%</fraction>
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index 9a610a0..415dd0b 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -47,17 +47,6 @@
     <string name="prefs_debug_mode">Debug Mode</string>
     <string name="prefs_force_non_distinct_multitouch">Force non-distinct multitouch</string>
 
-    <!-- For keyboard color scheme option dialog. -->
-    <string-array name="keyboard_theme_names">
-        <item>@string/keyboard_color_scheme_white</item>
-        <item>@string/keyboard_color_scheme_blue</item>
-    </string-array>
-    <!-- An element must be a keyboard theme id of {@link KeyboardTheme#THEME_ID_*}. -->
-    <string-array name="keyboard_theme_ids">
-        <item>2</item>
-        <item>0</item>
-    </string-array>
-
     <!-- Subtype locale display name exceptions.
          For each exception, there should be related string resources for display name that may have
          explicit keyboard layout. The string resource name must be "subtype_<locale>" or
diff --git a/java/res/values/keyboard-icons-holo.xml b/java/res/values/keyboard-icons-holo.xml
index 4c888d5..669d2c0 100644
--- a/java/res/values/keyboard-icons-holo.xml
+++ b/java/res/values/keyboard-icons-holo.xml
@@ -21,9 +21,6 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
     <style name="KeyboardIcons.Holo">
         <!-- Keyboard icons -->
-        <!-- TODO: The following holo icon for phone (drawable-hdpi and drawable-xhdpi) are missing.
-             sym_keyboard_123_mic_holo
-             -->
         <item name="iconShiftKey">@drawable/sym_keyboard_shift_holo_dark</item>
         <item name="iconDeleteKey">@drawable/sym_keyboard_delete_holo_dark</item>
         <item name="iconSettingsKey">@drawable/sym_keyboard_settings_holo_dark</item>
diff --git a/java/res/values/keyboard-icons-lmp.xml b/java/res/values/keyboard-icons-lmp.xml
new file mode 100644
index 0000000..a9cbabc
--- /dev/null
+++ b/java/res/values/keyboard-icons-lmp.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, 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.
+*/
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="KeyboardIcons.LMP">
+        <!-- Keyboard icons -->
+        <item name="iconShiftKey">@drawable/sym_keyboard_shift_holo_dark</item>
+        <item name="iconDeleteKey">@drawable/sym_keyboard_delete_holo_dark</item>
+        <item name="iconSettingsKey">@drawable/sym_keyboard_settings_holo_dark</item>
+        <item name="iconSpaceKey">@drawable/sym_keyboard_space_holo_dark</item>
+        <item name="iconEnterKey">@drawable/sym_keyboard_return_holo_dark</item>
+        <item name="iconSearchKey">@drawable/sym_keyboard_search_holo_dark</item>
+        <item name="iconTabKey">@drawable/sym_keyboard_tab_holo_dark</item>
+        <item name="iconShortcutKey">@drawable/sym_keyboard_voice_holo_dark</item>
+        <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_holo_dark</item>
+        <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_holo_dark</item>
+        <item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_holo_dark</item>
+        <item name="iconTabKeyPreview">@drawable/sym_keyboard_feedback_tab</item>
+        <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch_dark</item>
+        <item name="iconZwnjKey">@drawable/sym_keyboard_zwnj_holo_dark</item>
+        <item name="iconZwjKey">@drawable/sym_keyboard_zwj_holo_dark</item>
+        <item name="iconEmojiKey">@drawable/sym_keyboard_smiley_holo_dark</item>
+    </style>
+</resources>
diff --git a/java/res/values/keyboard-themes.xml b/java/res/values/keyboard-themes.xml
new file mode 100644
index 0000000..0325f5b
--- /dev/null
+++ b/java/res/values/keyboard-themes.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- For keyboard color scheme option dialog. -->
+    <string-array name="keyboard_theme_names" translatable="false">
+        <item>@string/keyboard_color_scheme_white</item>
+        <item>@string/keyboard_color_scheme_blue</item>
+        <!-- TODO: Make this item as translatable string resource. -->
+        <item>Quantum</item>
+    </string-array>
+    <!-- An element must be a keyboard theme id of {@link KeyboardTheme#THEME_ID_*}. -->
+    <string-array name="keyboard_theme_ids" translatable="false">
+        <item>2</item>
+        <item>0</item>
+        <item>3</item>
+    </string-array>
+</resources>
diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml
index 616dbd8..d7943ee 100644
--- a/java/res/values/themes-ics.xml
+++ b/java/res/values/themes-ics.xml
@@ -56,8 +56,8 @@
         <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_holo</item>
         <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_holo</item>
         <item name="keyPreviewTextColor">@color/key_text_color_holo</item>
-        <item name="keyTextShadowColor">@color/key_text_shadow_color_holo</item>
-        <item name="keyTextShadowRadius">0.0</item>
+        <!-- A negative value to disable key text shadow layer. -->
+        <item name="keyTextShadowRadius">-1.0</item>
     </style>
     <style
         name="MainKeyboardView.ICS"
@@ -71,6 +71,7 @@
         <item name="autoCorrectionSpacebarLedEnabled">false</item>
         <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item>
         <item name="languageOnSpacebarTextColor">@color/spacebar_text_color_holo</item>
+        <item name="languageOnSpacebarTextShadowRadius">1.0</item>
         <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item>
         <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_ics</item>
     </style>
diff --git a/java/res/values/themes-klp.xml b/java/res/values/themes-klp.xml
index 9bb3d79..13500fe 100644
--- a/java/res/values/themes-klp.xml
+++ b/java/res/values/themes-klp.xml
@@ -56,8 +56,8 @@
         <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_holo</item>
         <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_holo</item>
         <item name="keyPreviewTextColor">@color/key_text_color_holo</item>
-        <item name="keyTextShadowColor">@color/key_text_shadow_color_holo</item>
-        <item name="keyTextShadowRadius">0.0</item>
+        <!-- A negative value to disable key text shadow layer. -->
+        <item name="keyTextShadowRadius">-1.0</item>
     </style>
     <style
         name="MainKeyboardView.KLP"
@@ -71,6 +71,7 @@
         <item name="autoCorrectionSpacebarLedEnabled">false</item>
         <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item>
         <item name="languageOnSpacebarTextColor">@color/spacebar_text_color_holo</item>
+        <item name="languageOnSpacebarTextShadowRadius">1.0</item>
         <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item>
         <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_klp</item>
     </style>
diff --git a/java/res/values/themes-lmp.xml b/java/res/values/themes-lmp.xml
new file mode 100644
index 0000000..41c4d09
--- /dev/null
+++ b/java/res/values/themes-lmp.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, 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.
+*/
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+    <style name="KeyboardTheme.LMP" parent="KeyboardIcons.LMP">
+        <item name="keyboardStyle">@style/Keyboard.LMP</item>
+        <item name="keyboardViewStyle">@style/KeyboardView.LMP</item>
+        <item name="mainKeyboardViewStyle">@style/MainKeyboardView.LMP</item>
+        <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.LMP</item>
+        <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LMP</item>
+        <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.LMP</item>
+        <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LMP</item>
+        <item name="suggestionStripViewStyle">@style/SuggestionStripView.LMP</item>
+        <item name="suggestionWordStyle">@style/SuggestionWord.LMP</item>
+    </style>
+    <style
+        name="Keyboard.LMP"
+        parent="Keyboard"
+    >
+        <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
+        <item name="themeId">0</item>
+        <item name="keyboardTopPadding">@fraction/config_keyboard_top_padding_holo</item>
+        <item name="keyboardBottomPadding">@fraction/config_keyboard_bottom_padding_holo</item>
+        <item name="horizontalGap">@fraction/config_key_horizontal_gap_holo</item>
+        <item name="verticalGap">@fraction/config_key_vertical_gap_holo</item>
+        <item name="touchPositionCorrectionData">@array/touch_position_correction_data_holo</item>
+    </style>
+    <style
+        name="KeyboardView.LMP"
+        parent="KeyboardView"
+    >
+        <item name="android:background">@drawable/keyboard_background_holo</item>
+        <item name="keyBackground">@drawable/btn_keyboard_key_lmp</item>
+        <item name="keyTypeface">bold</item>
+        <item name="keyTextColor">@color/key_text_color_holo</item>
+        <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_holo</item>
+        <item name="keyHintLetterColor">@color/key_hint_letter_color_lmp</item>
+        <item name="keyHintLabelColor">@color/key_hint_label_color_holo</item>
+        <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_holo</item>
+        <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_holo</item>
+        <item name="keyPreviewTextColor">@color/key_text_color_holo</item>
+        <!-- A negative value to disable key text shadow layer. -->
+        <item name="keyTextShadowRadius">-1.0</item>
+    </style>
+    <style
+        name="MainKeyboardView.LMP"
+        parent="KeyboardView.LMP"
+    >
+        <item name="keyPreviewOffset">@dimen/config_key_preview_offset_holo</item>
+        <item name="gestureFloatingPreviewTextColor">@color/highlight_color_lmp</item>
+        <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_holo</item>
+        <item name="gestureTrailColor">@color/highlight_color_lmp</item>
+        <item name="slidingKeyInputPreviewColor">@color/highlight_translucent_color_lmp</item>
+        <item name="autoCorrectionSpacebarLedEnabled">false</item>
+        <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_holo</item>
+        <item name="languageOnSpacebarTextColor">@color/spacebar_text_color_holo</item>
+        <item name="languageOnSpacebarTextShadowRadius">1.0</item>
+        <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_holo</item>
+        <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_lmp</item>
+    </style>
+    <style
+        name="KeyPreviewTextView.LMP"
+        parent="KeyPreviewTextView"
+    >
+        <item name="android:background">@drawable/keyboard_key_feedback_lmp</item>
+    </style>
+    <!-- Though {@link EmojiPalettesView} doesn't extend {@link KeyboardView}, some views inside it,
+         for instance delete button, need themed {@link KeyboardView} attributes. -->
+    <style
+        name="EmojiPalettesView.LMP"
+        parent="KeyboardView.LMP"
+    >
+        <item name="keyBackgroundEmojiFunctional">@drawable/btn_keyboard_key_functional_lmp</item>
+        <item name="emojiTabLabelColor">@color/emoji_tab_label_color_holo</item>
+    </style>
+    <style
+        name="MoreKeysKeyboard.LMP"
+        parent="Keyboard.LMP"
+    >
+        <item name="keyboardTopPadding">0%p</item>
+        <item name="keyboardBottomPadding">0%p</item>
+        <item name="horizontalGap">0%p</item>
+        <item name="touchPositionCorrectionData">@null</item>
+    </style>
+    <style
+        name="MoreKeysKeyboardView.LMP"
+        parent="KeyboardView.LMP"
+    >
+        <item name="android:background">@drawable/keyboard_popup_panel_background_lmp</item>
+        <item name="keyBackground">@drawable/btn_keyboard_key_popup_lmp</item>
+        <item name="keyTypeface">normal</item>
+        <item name="verticalCorrection">@dimen/config_more_keys_keyboard_vertical_correction_holo</item>
+    </style>
+    <style
+        name="SuggestionStripView.LMP"
+        parent="KeyboardView.LMP"
+    >
+        <item name="suggestionsCountInStrip">@integer/config_suggestions_count_in_strip</item>
+        <item name="centerSuggestionPercentile">@fraction/config_center_suggestion_percentile</item>
+        <item name="maxMoreSuggestionsRow">@integer/config_max_more_suggestions_row</item>
+        <item name="minMoreSuggestionsWidth">@fraction/config_min_more_suggestions_width</item>
+        <item name="android:background">@drawable/keyboard_suggest_strip_holo</item>
+        <item name="suggestionStripOptions">autoCorrectBold|validTypedWordBold</item>
+        <item name="colorValidTypedWord">@color/typed_word_color_lmp</item>
+        <item name="colorTypedWord">@color/typed_word_color_lmp</item>
+        <item name="colorAutoCorrect">@color/highlight_color_lmp</item>
+        <item name="colorSuggested">@color/suggested_word_color_lmp</item>
+        <item name="alphaObsoleted">70%</item>
+    </style>
+    <style
+        name="SuggestionWord.LMP"
+        parent="SuggestionWord"
+    >
+        <item name="android:background">@drawable/btn_suggestion_lmp</item>
+        <item name="android:textColor">@color/highlight_color_lmp</item>
+    </style>
+</resources>
diff --git a/java/res/xml-sw600dp/key_settings.xml b/java/res/xml-sw600dp/key_settings.xml
new file mode 100644
index 0000000..45915e9
--- /dev/null
+++ b/java/res/xml-sw600dp/key_settings.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, 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"
+>
+    <switch>
+        <case
+            latin:clobberSettingsKey="false"
+        >
+            <Key
+                latin:keyStyle="settingsKeyStyle" />
+        </case>
+        <!-- clobberSettingsKey="true" -->
+        <default>
+            <Spacer />
+        </default>
+    </switch>
+</merge>
diff --git a/java/res/xml-sw600dp/key_shortcut.xml b/java/res/xml-sw600dp/key_shortcut.xml
deleted file mode 100644
index d24e81f..0000000
--- a/java/res/xml-sw600dp/key_shortcut.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-<?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"
->
-    <switch>
-        <case
-            latin:supportsSwitchingToShortcutIme="true"
-            latin:clobberSettingsKey="false"
-        >
-            <Key
-                latin:keyStyle="shortcutKeyStyle"
-                latin:keyLabelFlags="hasPopupHint|preserveCase"
-                latin:moreKeys="!text/keyspec_settings" />
-        </case>
-        <case
-            latin:supportsSwitchingToShortcutIme="true"
-            latin:clobberSettingsKey="true"
-        >
-            <Key
-                latin:keyStyle="shortcutKeyStyle" />
-        </case>
-        <case
-            latin:supportsSwitchingToShortcutIme="false"
-            latin:clobberSettingsKey="false"
-        >
-            <Key
-                latin:keyStyle="settingsKeyStyle" />
-        </case>
-        <!-- supportsSwitchingToShortcutIme="false" clobberSettingsKey="true" -->
-        <default>
-            <Spacer />
-        </default>
-    </switch>
-</merge>
diff --git a/java/res/xml-sw600dp/key_styles_common.xml b/java/res/xml-sw600dp/key_styles_common.xml
index 3d5556f..f9b959b 100644
--- a/java/res/xml-sw600dp/key_styles_common.xml
+++ b/java/res/xml-sw600dp/key_styles_common.xml
@@ -78,7 +78,7 @@
         latin:keyboardLayout="@xml/key_styles_enter" />
     <key-style
         latin:styleName="spaceKeyStyle"
-        latin:keySpec=" |!code/key_space"
+        latin:keySpec="!icon/space_key|!code/key_space"
         latin:keyActionFlags="noKeyPreview|enableLongPress" />
     <!-- U+200C: ZERO WIDTH NON-JOINER
          U+200D: ZERO WIDTH JOINER -->
diff --git a/java/res/xml-sw600dp/row_dvorak4.xml b/java/res/xml-sw600dp/row_dvorak4.xml
index 2ba6a49..d3709ef 100644
--- a/java/res/xml-sw600dp/row_dvorak4.xml
+++ b/java/res/xml-sw600dp/row_dvorak4.xml
@@ -29,7 +29,7 @@
             latin:keyStyle="toSymbolKeyStyle"
             latin:keyWidth="10.0%p" />
         <include
-            latin:keyboardLayout="@xml/key_shortcut" />
+            latin:keyboardLayout="@xml/key_settings" />
         <include
             latin:keyboardLayout="@xml/key_f1" />
         <include
diff --git a/java/res/xml-sw600dp/row_pcqwerty5.xml b/java/res/xml-sw600dp/row_pcqwerty5.xml
index 52b581a..ac07f11 100644
--- a/java/res/xml-sw600dp/row_pcqwerty5.xml
+++ b/java/res/xml-sw600dp/row_pcqwerty5.xml
@@ -26,7 +26,7 @@
     >
         <include
             latin:keyWidth="9.0%p"
-            latin:keyboardLayout="@xml/key_shortcut" />
+            latin:keyboardLayout="@xml/key_settings" />
         <switch>
             <case
                 latin:languageSwitchKeyEnabled="true"
diff --git a/java/res/xml-sw600dp/row_qwerty4.xml b/java/res/xml-sw600dp/row_qwerty4.xml
index 7969dd8..d931437 100644
--- a/java/res/xml-sw600dp/row_qwerty4.xml
+++ b/java/res/xml-sw600dp/row_qwerty4.xml
@@ -29,7 +29,7 @@
             latin:keyStyle="toSymbolKeyStyle"
             latin:keyWidth="10.0%p" />
         <include
-            latin:keyboardLayout="@xml/key_shortcut" />
+            latin:keyboardLayout="@xml/key_settings" />
         <include
             latin:keyboardLayout="@xml/key_f1" />
         <include
diff --git a/java/res/xml/key_f1.xml b/java/res/xml/key_f1.xml
index c96ddca..3471c85 100644
--- a/java/res/xml/key_f1.xml
+++ b/java/res/xml/key_f1.xml
@@ -36,27 +36,10 @@
                 latin:keySpec="\@"
                 latin:keyStyle="f1MoreKeysStyle" />
         </case>
-        <case
-            latin:supportsSwitchingToShortcutIme="false"
-        >
-            <Key
-                latin:keySpec="!text/keyspec_comma"
-                latin:keyLabelFlags="hasPopupHint"
-                latin:keyStyle="f1MoreKeysStyle" />
-        </case>
-        <!-- latin:supportsSwitchingToShortcutIme="true" -->
-        <case
-            latin:hasShortcutKey="true"
-        >
-            <Key
-                latin:keyStyle="shortcutKeyStyle" />
-        </case>
-        <!-- latin:hasShortcutKey="false" -->
         <default>
             <Key
                 latin:keySpec="!text/keyspec_comma"
                 latin:keyLabelFlags="hasPopupHint"
-                latin:additionalMoreKeys="!text/keyspec_shortcut"
                 latin:keyStyle="f1MoreKeysStyle" />
         </default>
     </switch>
diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml
index 78e0301..773995f 100644
--- a/java/res/xml/key_styles_common.xml
+++ b/java/res/xml/key_styles_common.xml
@@ -87,7 +87,7 @@
         latin:keyboardLayout="@xml/key_styles_enter" />
     <key-style
         latin:styleName="spaceKeyStyle"
-        latin:keySpec=" |!code/key_space"
+        latin:keySpec="!icon/space_key|!code/key_space"
         latin:keyActionFlags="noKeyPreview|enableLongPress" />
     <!-- U+200C: ZERO WIDTH NON-JOINER
          U+200D: ZERO WIDTH JOINER -->
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index 0156996..2adc957 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -503,7 +503,7 @@
             android:subtypeId="0xea266ea4"
             android:imeSubtypeLocale="my_MM"
             android:imeSubtypeMode="keyboard"
-            android:imeSubtypeExtraValue="KeyboardLayoutSet=myanmar,EmojiCapable"
+            android:imeSubtypeExtraValue="KeyboardLayoutSet=myanmar,EmojiCapable,CombiningRules=MyanmarReordering"
             android:isAsciiCapable="false"
     />
     <subtype android:icon="@drawable/ic_ime_switcher_dark"
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index 7d86dbd..61ebb69 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -158,12 +158,11 @@
                 android:persistent="true"
                 android:defaultValue="false" />
             <ListPreference
-                android:key="pref_keyboard_layout_20110916"
+                android:key="pref_keyboard_theme"
                 android:title="@string/keyboard_color_scheme"
                 android:persistent="true"
                 android:entryValues="@array/keyboard_theme_ids"
-                android:entries="@array/keyboard_theme_names"
-                android:defaultValue="@string/config_default_keyboard_theme_id" />
+                android:entries="@array/keyboard_theme_names" />
             <PreferenceScreen
                 android:fragment="com.android.inputmethod.latin.settings.AdditionalSubtypeSettings"
                 android:key="custom_input_styles"
diff --git a/java/res/xml/row_dvorak4.xml b/java/res/xml/row_dvorak4.xml
index 91462cb..279f646 100644
--- a/java/res/xml/row_dvorak4.xml
+++ b/java/res/xml/row_dvorak4.xml
@@ -30,7 +30,6 @@
         <Key
             latin:keySpec="q"
             latin:backgroundType="normal"
-            latin:additionalMoreKeys="!text/keyspec_shortcut"
             latin:keyStyle="f1MoreKeysStyle" />
         <include
             latin:keyXPos="25%p"
diff --git a/java/res/xml/row_pcqwerty5.xml b/java/res/xml/row_pcqwerty5.xml
index 3782763..32c5389 100644
--- a/java/res/xml/row_pcqwerty5.xml
+++ b/java/res/xml/row_pcqwerty5.xml
@@ -26,13 +26,6 @@
     >
         <switch>
             <case
-                latin:hasShortcutKey="true"
-            >
-                <Key
-                    latin:keyStyle="shortcutKeyStyle"
-                    latin:keyWidth="11.538%p" />
-            </case>
-            <case
                 latin:clobberSettingsKey="false"
             >
                 <Key
diff --git a/java/src/com/android/inputmethod/event/CombinerChain.java b/java/src/com/android/inputmethod/event/CombinerChain.java
index 8b59dc5..990f7de 100644
--- a/java/src/com/android/inputmethod/event/CombinerChain.java
+++ b/java/src/com/android/inputmethod/event/CombinerChain.java
@@ -23,6 +23,7 @@
 import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 
 /**
  * This class implements the logic chain between receiving events and generating code points.
@@ -43,6 +44,13 @@
     private SpannableStringBuilder mStateFeedback;
     private final ArrayList<Combiner> mCombiners;
 
+    private static final HashMap<String, Class> IMPLEMENTED_COMBINERS
+            = new HashMap<String, Class>();
+    static {
+        IMPLEMENTED_COMBINERS.put("MyanmarReordering", MyanmarReordering.class);
+    }
+    private static final String COMBINER_SPEC_SEPARATOR = ";";
+
     /**
      * Create an combiner chain.
      *
@@ -56,6 +64,9 @@
         mCombiners = CollectionUtils.newArrayList();
         // The dead key combiner is always active, and always first
         mCombiners.add(new DeadKeyCombiner());
+        for (final Combiner combiner : combinerList) {
+            mCombiners.add(combiner);
+        }
         mCombinedText = new StringBuilder();
         mStateFeedback = new SpannableStringBuilder();
     }
@@ -114,4 +125,29 @@
         final SpannableStringBuilder s = new SpannableStringBuilder(mCombinedText);
         return s.append(mStateFeedback);
     }
+
+    public static Combiner[] createCombiners(final String spec) {
+        if (TextUtils.isEmpty(spec)) {
+            return new Combiner[0];
+        }
+        final String[] combinerDescriptors = spec.split(COMBINER_SPEC_SEPARATOR);
+        final Combiner[] combiners = new Combiner[combinerDescriptors.length];
+        int i = 0;
+        for (final String combinerDescriptor : combinerDescriptors) {
+            final Class combinerClass = IMPLEMENTED_COMBINERS.get(combinerDescriptor);
+            if (null == combinerClass) {
+                throw new RuntimeException("Unknown combiner descriptor: " + combinerDescriptor);
+            }
+            try {
+                combiners[i++] = (Combiner)combinerClass.newInstance();
+            } catch (InstantiationException e) {
+                throw new RuntimeException("Unable to instantiate combiner: " + combinerDescriptor,
+                        e);
+            } catch (IllegalAccessException e) {
+                throw new RuntimeException("Unable to instantiate combiner: " + combinerDescriptor,
+                        e);
+            }
+        }
+        return combiners;
+    }
 }
diff --git a/java/src/com/android/inputmethod/event/MyanmarReordering.java b/java/src/com/android/inputmethod/event/MyanmarReordering.java
new file mode 100644
index 0000000..27b8c14
--- /dev/null
+++ b/java/src/com/android/inputmethod/event/MyanmarReordering.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.event;
+
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * A combiner that reorders input for Myanmar.
+ */
+public class MyanmarReordering implements Combiner {
+    // U+1031 MYANMAR VOWEL SIGN E
+    private final static int VOWEL_E = 0x1031; // Code point for vowel E that we need to reorder
+    // U+200C ZERO WIDTH NON-JOINER
+    // U+200B ZERO WIDTH SPACE
+    private final static int ZERO_WIDTH_NON_JOINER = 0x200B; // should be 0x200C
+
+    private final ArrayList<Event> mCurrentEvents = CollectionUtils.newArrayList();
+
+    // List of consonants :
+    // U+1000 MYANMAR LETTER KA
+    // U+1001 MYANMAR LETTER KHA
+    // U+1002 MYANMAR LETTER GA
+    // U+1003 MYANMAR LETTER GHA
+    // U+1004 MYANMAR LETTER NGA
+    // U+1005 MYANMAR LETTER CA
+    // U+1006 MYANMAR LETTER CHA
+    // U+1007 MYANMAR LETTER JA
+    // U+1008 MYANMAR LETTER JHA
+    // U+1009 MYANMAR LETTER NYA
+    // U+100A MYANMAR LETTER NNYA
+    // U+100B MYANMAR LETTER TTA
+    // U+100C MYANMAR LETTER TTHA
+    // U+100D MYANMAR LETTER DDA
+    // U+100E MYANMAR LETTER DDHA
+    // U+100F MYANMAR LETTER NNA
+    // U+1010 MYANMAR LETTER TA
+    // U+1011 MYANMAR LETTER THA
+    // U+1012 MYANMAR LETTER DA
+    // U+1013 MYANMAR LETTER DHA
+    // U+1014 MYANMAR LETTER NA
+    // U+1015 MYANMAR LETTER PA
+    // U+1016 MYANMAR LETTER PHA
+    // U+1017 MYANMAR LETTER BA
+    // U+1018 MYANMAR LETTER BHA
+    // U+1019 MYANMAR LETTER MA
+    // U+101A MYANMAR LETTER YA
+    // U+101B MYANMAR LETTER RA
+    // U+101C MYANMAR LETTER LA
+    // U+101D MYANMAR LETTER WA
+    // U+101E MYANMAR LETTER SA
+    // U+101F MYANMAR LETTER HA
+    // U+1020 MYANMAR LETTER LLA
+    // U+103F MYANMAR LETTER GREAT SA
+    private static boolean isConsonant(final int codePoint) {
+        return (codePoint >= 0x1000 && codePoint <= 0x1020) || 0x103F == codePoint;
+    }
+
+    // List of medials :
+    // U+103B MYANMAR CONSONANT SIGN MEDIAL YA
+    // U+103C MYANMAR CONSONANT SIGN MEDIAL RA
+    // U+103D MYANMAR CONSONANT SIGN MEDIAL WA
+    // U+103E MYANMAR CONSONANT SIGN MEDIAL HA
+    // U+105E MYANMAR CONSONANT SIGN MON MEDIAL NA
+    // U+105F MYANMAR CONSONANT SIGN MON MEDIAL MA
+    // U+1060 MYANMAR CONSONANT SIGN MON MEDIAL LA
+    // U+1082 MYANMAR CONSONANT SIGN SHAN MEDIAL WA
+    private static int[] MEDIAL_LIST = { 0x103B, 0x103C, 0x103D, 0x103E,
+            0x105E, 0x105F, 0x1060, 0x1082};
+    private static boolean isMedial(final int codePoint) {
+        return Arrays.binarySearch(MEDIAL_LIST, codePoint) >= 0;
+    }
+
+    private static boolean isConsonantOrMedial(final int codePoint) {
+        return isConsonant(codePoint) || isMedial(codePoint);
+    }
+
+    private Event getLastEvent() {
+        final int size = mCurrentEvents.size();
+        if (size <= 0) {
+            return null;
+        }
+        return mCurrentEvents.get(size - 1);
+    }
+
+    private CharSequence getCharSequence() {
+        final StringBuilder s = new StringBuilder();
+        for (final Event e : mCurrentEvents) {
+            s.appendCodePoint(e.mCodePoint);
+        }
+        return s;
+    }
+
+    /**
+     * Clears the currently combining stream of events and returns the resulting software text
+     * event corresponding to the stream. Optionally adds a new event to the cleared stream.
+     * @param newEvent the new event to add to the stream. null if none.
+     * @return the resulting software text event. Null if none.
+     */
+    private Event clearAndGetResultingEvent(final Event newEvent) {
+        final CharSequence combinedText;
+        if (mCurrentEvents.size() > 0) {
+            combinedText = getCharSequence();
+            mCurrentEvents.clear();
+        } else {
+            combinedText = null;
+        }
+        if (null != newEvent) {
+            mCurrentEvents.add(newEvent);
+        }
+        return null == combinedText ? null
+                : Event.createSoftwareTextEvent(combinedText, Event.NOT_A_KEY_CODE);
+    }
+
+    @Override
+    public Event processEvent(ArrayList<Event> previousEvents, Event newEvent) {
+        final int codePoint = newEvent.mCodePoint;
+        if (VOWEL_E == codePoint) {
+            final Event lastEvent = getLastEvent();
+            if (null == lastEvent) {
+                mCurrentEvents.add(newEvent);
+                return null;
+            } else if (isConsonantOrMedial(lastEvent.mCodePoint)) {
+                final Event resultingEvent = clearAndGetResultingEvent(null);
+                mCurrentEvents.add(Event.createSoftwareKeypressEvent(ZERO_WIDTH_NON_JOINER,
+                        Event.NOT_A_KEY_CODE,
+                        Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
+                        false /* isKeyRepeat */));
+                mCurrentEvents.add(newEvent);
+                return resultingEvent;
+            } else { // VOWEL_E == lastCodePoint. But if that was anything else this is correct too.
+                return clearAndGetResultingEvent(newEvent);
+            }
+        } if (isConsonant(codePoint)) {
+            final Event lastEvent = getLastEvent();
+            if (null == lastEvent) {
+                mCurrentEvents.add(newEvent);
+                return null;
+            } else if (VOWEL_E == lastEvent.mCodePoint) {
+                final int eventSize = mCurrentEvents.size();
+                if (eventSize >= 2
+                        && mCurrentEvents.get(eventSize - 2).mCodePoint == ZERO_WIDTH_NON_JOINER) {
+                    // We have a ZWJN before a vowel E. We need to remove the ZWNJ and then
+                    // reorder the vowel with respect to the consonant.
+                    mCurrentEvents.remove(eventSize - 1);
+                    mCurrentEvents.remove(eventSize - 2);
+                    mCurrentEvents.add(newEvent);
+                    mCurrentEvents.add(lastEvent);
+                    return null;
+                }
+                // If there is already a consonant, then we are starting a new syllable.
+                for (int i = eventSize - 2; i >= 0; --i) {
+                    if (isConsonant(mCurrentEvents.get(i).mCodePoint)) {
+                        return clearAndGetResultingEvent(newEvent);
+                    }
+                }
+                // If we come here, we didn't have a consonant so we reorder
+                mCurrentEvents.remove(eventSize - 1);
+                mCurrentEvents.add(newEvent);
+                mCurrentEvents.add(lastEvent);
+                return null;
+            } else { // lastCodePoint is a consonant/medial. But if it's something else it's fine
+                return clearAndGetResultingEvent(newEvent);
+            }
+        } else if (isMedial(codePoint)) {
+            final Event lastEvent = getLastEvent();
+            if (null == lastEvent) {
+                mCurrentEvents.add(newEvent);
+                return null;
+            } else if (VOWEL_E == lastEvent.mCodePoint) {
+                final int eventSize = mCurrentEvents.size();
+                // If there is already a consonant, then we are in the middle of a syllable, and we
+                // need to reorder.
+                boolean hasConsonant = false;
+                for (int i = eventSize - 2; i >= 0; --i) {
+                    if (isConsonant(mCurrentEvents.get(i).mCodePoint)) {
+                        hasConsonant = true;
+                        break;
+                    }
+                }
+                if (hasConsonant) {
+                    mCurrentEvents.remove(eventSize - 1);
+                    mCurrentEvents.add(newEvent);
+                    mCurrentEvents.add(lastEvent);
+                    return null;
+                }
+                // Otherwise, we just commit everything.
+                return clearAndGetResultingEvent(null);
+            } else { // lastCodePoint is a consonant/medial. But if it's something else it's fine
+                return clearAndGetResultingEvent(newEvent);
+            }
+        } else if (Constants.CODE_DELETE == newEvent.mKeyCode) {
+            if (mCurrentEvents.size() > 0) {
+                mCurrentEvents.remove(mCurrentEvents.size() - 1);
+                return null;
+            }
+        }
+        // This character is not part of the combining scheme, so we should reset everything.
+        if (mCurrentEvents.size() > 0) {
+            // If we have events in flight, then add the new event and return the resulting event.
+            mCurrentEvents.add(newEvent);
+            return clearAndGetResultingEvent(null);
+        } else {
+            // If we don't have any events in flight, then just pass this one through.
+            return newEvent;
+        }
+    }
+
+    @Override
+    public CharSequence getCombiningStateFeedback() {
+        return getCharSequence();
+    }
+
+    @Override
+    public void reset() {
+        mCurrentEvents.clear();
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 1cd6ef2..4a46a4a 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -64,7 +64,7 @@
      * what user actually typed. */
     private boolean mIsAutoCorrectionActive;
 
-    private KeyboardTheme mKeyboardTheme = KeyboardTheme.getDefaultKeyboardTheme();
+    private KeyboardTheme mKeyboardTheme;
     private Context mThemeContext;
 
     private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
@@ -101,7 +101,7 @@
 
     private boolean updateKeyboardThemeAndContextThemeWrapper(final Context context,
             final KeyboardTheme keyboardTheme) {
-        if (mThemeContext == null || mKeyboardTheme.mThemeId != keyboardTheme.mThemeId) {
+        if (mThemeContext == null || !keyboardTheme.equals(mKeyboardTheme)) {
             mKeyboardTheme = keyboardTheme;
             mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId);
             KeyboardLayoutSet.clearKeyboardCache();
@@ -342,7 +342,8 @@
             mKeyboardView.closing();
         }
 
-        updateKeyboardThemeAndContextThemeWrapper(mLatinIME, mKeyboardTheme);
+        updateKeyboardThemeAndContextThemeWrapper(
+                mLatinIME, KeyboardTheme.getKeyboardTheme(mPrefs));
         mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
                 R.layout.input_view, null);
         mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
index 4db72ad..429c7dd 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
@@ -17,34 +17,85 @@
 package com.android.inputmethod.keyboard;
 
 import android.content.SharedPreferences;
+import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.util.Log;
 
 import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.settings.Settings;
+
+import java.util.Arrays;
+import java.util.Comparator;
 
 public final class KeyboardTheme {
     private static final String TAG = KeyboardTheme.class.getSimpleName();
 
-    public static final int THEME_ID_ICS = 0;
-    public static final int THEME_ID_KLP = 2;
-    private static final int DEFAULT_THEME_ID = THEME_ID_KLP;
+    static final String KITKAT_KEYBOARD_THEME_KEY = "pref_keyboard_layout_20110916";
+    static final String KEYBOARD_THEME_KEY = "pref_keyboard_theme_20140509";
+
+    static final int THEME_ID_ICS = 0;
+    static final int THEME_ID_KLP = 2;
+    static final int THEME_ID_LMP = 3;
+    static final int DEFAULT_THEME_ID = THEME_ID_KLP;
 
     private static final KeyboardTheme[] KEYBOARD_THEMES = {
-        new KeyboardTheme(THEME_ID_ICS, R.style.KeyboardTheme_ICS),
-        new KeyboardTheme(THEME_ID_KLP, R.style.KeyboardTheme_KLP),
+        new KeyboardTheme(THEME_ID_ICS, R.style.KeyboardTheme_ICS,
+                VERSION_CODES.ICE_CREAM_SANDWICH),
+        new KeyboardTheme(THEME_ID_KLP, R.style.KeyboardTheme_KLP,
+                VERSION_CODES.KITKAT),
+        new KeyboardTheme(THEME_ID_LMP, R.style.KeyboardTheme_LMP,
+                // TODO: Update this constant once the *next* version becomes available.
+                VERSION_CODES.CUR_DEVELOPMENT),
     };
+    static {
+        // Sort {@link #KEYBOARD_THEME} by descending order of {@link #mMinApiVersion}.
+        Arrays.sort(KEYBOARD_THEMES, new Comparator<KeyboardTheme>() {
+            @Override
+            public int compare(final KeyboardTheme lhs, final KeyboardTheme rhs) {
+                if (lhs.mMinApiVersion > rhs.mMinApiVersion) return -1;
+                if (lhs.mMinApiVersion < rhs.mMinApiVersion) return 1;
+                return 0;
+            }
+        });
+    }
 
     public final int mThemeId;
     public final int mStyleId;
+    final int mMinApiVersion;
 
     // Note: The themeId should be aligned with "themeId" attribute of Keyboard style
-    // in values/style.xml.
-    public KeyboardTheme(final int themeId, final int styleId) {
+    // in values/themes-<style>.xml.
+    private KeyboardTheme(final int themeId, final int styleId, final int minApiVersion) {
         mThemeId = themeId;
         mStyleId = styleId;
+        mMinApiVersion = minApiVersion;
     }
 
-    private static KeyboardTheme searchKeyboardTheme(final int themeId) {
+    @Override
+    public boolean equals(final Object o) {
+        if (o == this) return true;
+        return (o instanceof KeyboardTheme) && ((KeyboardTheme)o).mThemeId == mThemeId;
+    }
+
+    @Override
+    public int hashCode() {
+        return mThemeId;
+    }
+
+    // TODO: This method should be removed when {@link LatinImeLogger} is removed.
+    public int getCompatibleThemeIdForLogging() {
+        switch (mThemeId) {
+        case THEME_ID_ICS:
+            return 5;
+        case THEME_ID_KLP:
+            return 9;
+        case THEME_ID_LMP:
+            return 10;
+        default: // Invalid theme
+            return -1;
+        }
+    }
+
+    private static KeyboardTheme searchKeyboardThemeById(final int themeId) {
         // TODO: This search algorithm isn't optimal if there are many themes.
         for (final KeyboardTheme theme : KEYBOARD_THEMES) {
             if (theme.mThemeId == themeId) {
@@ -54,18 +105,57 @@
         return null;
     }
 
-    public static KeyboardTheme getDefaultKeyboardTheme() {
-        return searchKeyboardTheme(DEFAULT_THEME_ID);
+    private static int getSdkVersion() {
+        final int sdkVersion = Build.VERSION.SDK_INT;
+        // TODO: Consider to remove this check once the *next* version becomes available.
+        if (sdkVersion == VERSION_CODES.KITKAT && Build.VERSION.CODENAME.startsWith("L")) {
+            return VERSION_CODES.CUR_DEVELOPMENT;
+        }
+        return sdkVersion;
+    }
+
+    static KeyboardTheme getDefaultKeyboardTheme(final SharedPreferences prefs,
+            final int sdkVersion) {
+        final String obsoleteIdString = prefs.getString(KITKAT_KEYBOARD_THEME_KEY, null);
+        if (obsoleteIdString != null) {
+            // Remove old preference.
+            prefs.edit().remove(KITKAT_KEYBOARD_THEME_KEY).apply();
+            if (sdkVersion <= VERSION_CODES.KITKAT) {
+                try {
+                    final int themeId = Integer.parseInt(obsoleteIdString);
+                    final KeyboardTheme theme = searchKeyboardThemeById(themeId);
+                    if (theme != null) {
+                        return theme;
+                    }
+                    Log.w(TAG, "Unknown keyboard theme in preference: " + obsoleteIdString);
+                } catch (final NumberFormatException e) {
+                    Log.w(TAG, "Illegal keyboard theme in preference: " + obsoleteIdString);
+                }
+            }
+        }
+        // TODO: This search algorithm isn't optimal if there are many themes.
+        for (final KeyboardTheme theme : KEYBOARD_THEMES) {
+            if (sdkVersion >= theme.mMinApiVersion) {
+                return theme;
+            }
+        }
+        return searchKeyboardThemeById(DEFAULT_THEME_ID);
+    }
+
+    public static void saveKeyboardThemeId(final String themeIdString,
+            final SharedPreferences prefs) {
+        prefs.edit().putString(KEYBOARD_THEME_KEY, themeIdString).apply();
     }
 
     public static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs) {
-        final String themeIdString = prefs.getString(Settings.PREF_KEYBOARD_LAYOUT, null);
+        final int sdkVersion = getSdkVersion();
+        final String themeIdString = prefs.getString(KEYBOARD_THEME_KEY, null);
         if (themeIdString == null) {
-            return getDefaultKeyboardTheme();
+            return getDefaultKeyboardTheme(prefs, sdkVersion);
         }
         try {
             final int themeId = Integer.parseInt(themeIdString);
-            final KeyboardTheme theme = searchKeyboardTheme(themeId);
+            final KeyboardTheme theme = searchKeyboardThemeById(themeId);
             if (theme != null) {
                 return theme;
             }
@@ -73,9 +163,8 @@
         } catch (final NumberFormatException e) {
             Log.w(TAG, "Illegal keyboard theme in preference: " + themeIdString);
         }
-        // Reset preference to default value.
-        final String defaultThemeIdString = Integer.toString(DEFAULT_THEME_ID);
-        prefs.edit().putString(Settings.PREF_KEYBOARD_LAYOUT, defaultThemeIdString).apply();
-        return getDefaultKeyboardTheme();
+        // Remove preference.
+        prefs.edit().remove(KEYBOARD_THEME_KEY).apply();
+        return getDefaultKeyboardTheme(prefs, sdkVersion);
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 8ca00b0..4450a44 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -82,6 +82,7 @@
     private final float mVerticalCorrection;
     private final Drawable mKeyBackground;
     private final Rect mKeyBackgroundPadding = new Rect();
+    private static final float KET_TEXT_SHADOW_RADIUS_DISABLED = -1.0f;
 
     // HORIZONTAL ELLIPSIS "...", character for popup hint.
     private static final String POPUP_HINT_CHAR = "\u2026";
@@ -133,7 +134,7 @@
         mKeyShiftedLetterHintPadding = keyboardViewAttr.getDimension(
                 R.styleable.KeyboardView_keyShiftedLetterHintPadding, 0.0f);
         mKeyTextShadowRadius = keyboardViewAttr.getFloat(
-                R.styleable.KeyboardView_keyTextShadowRadius, 0.0f);
+                R.styleable.KeyboardView_keyTextShadowRadius, KET_TEXT_SHADOW_RADIUS_DISABLED);
         mVerticalCorrection = keyboardViewAttr.getDimension(
                 R.styleable.KeyboardView_verticalCorrection, 0.0f);
         keyboardViewAttr.recycle();
@@ -414,18 +415,23 @@
                 }
             }
 
-            paint.setColor(key.selectTextColor(params));
             if (key.isEnabled()) {
-                // Set a drop shadow for the text
-                paint.setShadowLayer(mKeyTextShadowRadius, 0.0f, 0.0f, params.mTextShadowColor);
+                paint.setColor(key.selectTextColor(params));
+                // Set a drop shadow for the text if the shadow radius is positive value.
+                if (mKeyTextShadowRadius > 0.0f) {
+                    paint.setShadowLayer(mKeyTextShadowRadius, 0.0f, 0.0f, params.mTextShadowColor);
+                } else {
+                    paint.clearShadowLayer();
+                }
             } else {
                 // Make label invisible
                 paint.setColor(Color.TRANSPARENT);
+                paint.clearShadowLayer();
             }
             blendAlpha(paint, params.mAnimAlpha);
             canvas.drawText(label, 0, label.length(), positionX, baseline, paint);
             // Turn off drop shadow and reset x-scale.
-            paint.setShadowLayer(0.0f, 0.0f, 0.0f, Color.TRANSPARENT);
+            paint.clearShadowLayer();
             paint.setTextScaleX(1.0f);
 
             if (icon != null) {
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 8f79a91..1a8e4b7 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -74,6 +74,7 @@
  * @attr ref R.styleable#MainKeyboardView_autoCorrectionSpacebarLedIcon
  * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextRatio
  * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextColor
+ * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextShadowRadius
  * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarTextShadowColor
  * @attr ref R.styleable#MainKeyboardView_spacebarBackground
  * @attr ref R.styleable#MainKeyboardView_languageOnSpacebarFinalAlpha
@@ -129,7 +130,9 @@
     private final float mLanguageOnSpacebarTextRatio;
     private float mLanguageOnSpacebarTextSize;
     private final int mLanguageOnSpacebarTextColor;
+    private final float mLanguageOnSpacebarTextShadowRadius;
     private final int mLanguageOnSpacebarTextShadowColor;
+    private static final float LANGUAGE_ON_SPACEBAR_TEXT_SHADOW_RADIUS_DISABLED = -1.0f;
     // The minimum x-scale to fit the language name on spacebar.
     private static final float MINIMUM_XSCALE_OF_LANGUAGE_NAME = 0.8f;
     // Stuff to draw auto correction LED on spacebar.
@@ -231,6 +234,9 @@
                 R.styleable.MainKeyboardView_languageOnSpacebarTextRatio, 1, 1, 1.0f);
         mLanguageOnSpacebarTextColor = mainKeyboardViewAttr.getColor(
                 R.styleable.MainKeyboardView_languageOnSpacebarTextColor, 0);
+        mLanguageOnSpacebarTextShadowRadius = mainKeyboardViewAttr.getFloat(
+                R.styleable.MainKeyboardView_languageOnSpacebarTextShadowRadius,
+                LANGUAGE_ON_SPACEBAR_TEXT_SHADOW_RADIUS_DISABLED);
         mLanguageOnSpacebarTextShadowColor = mainKeyboardViewAttr.getColor(
                 R.styleable.MainKeyboardView_languageOnSpacebarTextShadowColor, 0);
         mLanguageOnSpacebarFinalAlpha = mainKeyboardViewAttr.getInt(
@@ -948,12 +954,17 @@
             final float descent = paint.descent();
             final float textHeight = -paint.ascent() + descent;
             final float baseline = height / 2 + textHeight / 2;
-            paint.setColor(mLanguageOnSpacebarTextShadowColor);
-            paint.setAlpha(mLanguageOnSpacebarAnimAlpha);
-            canvas.drawText(language, width / 2, baseline - descent - 1, paint);
+            if (mLanguageOnSpacebarTextShadowRadius > 0.0f) {
+                paint.setShadowLayer(mLanguageOnSpacebarTextShadowRadius, 0, 0,
+                        mLanguageOnSpacebarTextShadowColor);
+            } else {
+                paint.clearShadowLayer();
+            }
             paint.setColor(mLanguageOnSpacebarTextColor);
             paint.setAlpha(mLanguageOnSpacebarAnimAlpha);
             canvas.drawText(language, width / 2, baseline - descent, paint);
+            paint.clearShadowLayer();
+            paint.setTextScaleX(1.0f);
         }
 
         // Draw the spacebar icon at the bottom
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index dfe0df0..2aeeed8 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -664,6 +664,8 @@
                     R.styleable.Keyboard_Case_isMultiLine, id.isMultiLine());
             final boolean imeActionMatched = matchInteger(caseAttr,
                     R.styleable.Keyboard_Case_imeAction, id.imeAction());
+            final boolean isIconDefinedMatched = isIconDefined(caseAttr,
+                    R.styleable.Keyboard_Case_isIconDefined, mParams.mIconsSet);
             final boolean localeCodeMatched = matchString(caseAttr,
                     R.styleable.Keyboard_Case_localeCode, id.mLocale.toString());
             final boolean languageCodeMatched = matchString(caseAttr,
@@ -675,10 +677,11 @@
                     && passwordInputMatched && clobberSettingsKeyMatched
                     && supportsSwitchingToShortcutImeMatched && hasShortcutKeyMatched
                     && languageSwitchKeyEnabledMatched && isMultiLineMatched && imeActionMatched
-                    && localeCodeMatched && languageCodeMatched && countryCodeMatched;
+                    && isIconDefinedMatched && localeCodeMatched && languageCodeMatched
+                    && countryCodeMatched;
 
             if (DEBUG) {
-                startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE,
+                startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE,
                         textAttr(caseAttr.getString(
                                 R.styleable.Keyboard_Case_keyboardLayoutSet), "keyboardLayoutSet"),
                         textAttr(caseAttr.getString(
@@ -704,6 +707,8 @@
                                 "languageSwitchKeyEnabled"),
                         booleanAttr(caseAttr, R.styleable.Keyboard_Case_isMultiLine,
                                 "isMultiLine"),
+                        textAttr(caseAttr.getString(R.styleable.Keyboard_Case_isIconDefined),
+                                "isIconDefined"),
                         textAttr(caseAttr.getString(R.styleable.Keyboard_Case_localeCode),
                                 "localeCode"),
                         textAttr(caseAttr.getString(R.styleable.Keyboard_Case_languageCode),
@@ -755,6 +760,16 @@
         return false;
     }
 
+    private static boolean isIconDefined(final TypedArray a, final int index,
+            final KeyboardIconsSet iconsSet) {
+        if (!a.hasValue(index)) {
+            return true;
+        }
+        final String iconName = a.getString(index);
+        final int iconId = KeyboardIconsSet.getIconId(iconName);
+        return iconsSet.getIconDrawable(iconId) != null;
+    }
+
     private boolean parseDefault(final XmlPullParser parser, final KeyboardRow row,
             final boolean skip) throws XmlPullParserException, IOException {
         if (DEBUG) startTag("<%s>", TAG_DEFAULT);
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index e71723a..67ca595 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -115,6 +115,11 @@
              */
             public static final String IS_ADDITIONAL_SUBTYPE = "isAdditionalSubtype";
 
+            /**
+             * The subtype extra value used to specify the combining rules.
+             */
+            public static final String COMBINING_RULES = "CombiningRules";
+
             private ExtraValue() {
                 // This utility class is not publicly instantiable.
             }
@@ -164,6 +169,8 @@
     // How many continuous deletes at which to start deleting at a higher speed.
     public static final int DELETE_ACCELERATE_AT = 20;
 
+    public static final String WORD_SEPARATOR = " ";
+
     public static boolean isValidCoordinate(final int coordinate) {
         // Detect {@link NOT_A_COORDINATE}, {@link SUGGESTION_STRIP_COORDINATE},
         // and {@link SPELL_CHECKER_COORDINATE}.
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 0742fbd..cd380db 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -57,6 +57,8 @@
     public static final String TYPE_USER_HISTORY = "history";
     // Personalization dictionary.
     public static final String TYPE_PERSONALIZATION = "personalization";
+    // Contextual dictionary.
+    public static final String TYPE_CONTEXTUAL = "contextual";
     public final String mDictType;
 
     public Dictionary(final String dictType) {
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
index 9735645..e0220e1 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorForSuggest.java
@@ -23,6 +23,7 @@
 import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.keyboard.ProximityInfo;
 import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.personalization.ContextualDictionary;
 import com.android.inputmethod.latin.personalization.PersonalizationDictionary;
 import com.android.inputmethod.latin.personalization.UserHistoryDictionary;
 import com.android.inputmethod.latin.utils.CollectionUtils;
@@ -55,7 +56,7 @@
     private boolean mIsUserDictEnabled = false;
     private volatile CountDownLatch mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0);
     // To synchronize assigning mDictionaries to ensure closing dictionaries.
-    private Object mLock = new Object();
+    private final Object mLock = new Object();
 
     private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTION =
             new String[] {
@@ -63,7 +64,8 @@
                 Dictionary.TYPE_USER_HISTORY,
                 Dictionary.TYPE_PERSONALIZATION,
                 Dictionary.TYPE_USER,
-                Dictionary.TYPE_CONTACTS
+                Dictionary.TYPE_CONTACTS,
+                Dictionary.TYPE_CONTEXTUAL
             };
 
     private static final Map<String, Class<? extends ExpandableBinaryDictionary>>
@@ -74,6 +76,7 @@
         DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_PERSONALIZATION, PersonalizationDictionary.class);
         DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_USER, UserBinaryDictionary.class);
         DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_CONTACTS, ContactsBinaryDictionary.class);
+        DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_CONTEXTUAL, ContextualDictionary.class);
     }
 
     private static final String DICT_FACTORY_METHOD_NAME = "getDictionary";
@@ -201,6 +204,7 @@
         if (usePersonalizedDicts) {
             subDictTypesToUse.add(Dictionary.TYPE_USER_HISTORY);
             subDictTypesToUse.add(Dictionary.TYPE_PERSONALIZATION);
+            subDictTypesToUse.add(Dictionary.TYPE_CONTEXTUAL);
         }
 
         final Dictionary newMainDict;
@@ -366,32 +370,46 @@
     }
 
     public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized,
-            final String previousWord, final int timeStampInSeconds) {
+            final String previousWord, final int timeStampInSeconds,
+            final boolean blockPotentiallyOffensive) {
         final Dictionaries dictionaries = mDictionaries;
+        final String[] words = suggestion.split(Constants.WORD_SEPARATOR);
+        for (int i = 0; i < words.length; i++) {
+            final String currentWord = words[i];
+            final String prevWord = (i == 0) ? previousWord : words[i - 1];
+            final boolean wasCurrentWordAutoCapitalized = (i == 0) ? wasAutoCapitalized : false;
+            addWordToUserHistory(dictionaries, prevWord, currentWord,
+                    wasCurrentWordAutoCapitalized, timeStampInSeconds, blockPotentiallyOffensive);
+        }
+    }
+
+    private void addWordToUserHistory(final Dictionaries dictionaries, final String prevWord,
+            final String word, final boolean wasAutoCapitalized, final int timeStampInSeconds,
+            final boolean blockPotentiallyOffensive) {
         final ExpandableBinaryDictionary userHistoryDictionary =
                 dictionaries.getSubDict(Dictionary.TYPE_USER_HISTORY);
         if (userHistoryDictionary == null) {
             return;
         }
-        final int maxFreq = getMaxFrequency(suggestion);
-        if (maxFreq == 0) {
+        final int maxFreq = getMaxFrequency(word);
+        if (maxFreq == 0 && blockPotentiallyOffensive) {
             return;
         }
-        final String suggestionLowerCase = suggestion.toLowerCase(dictionaries.mLocale);
+        final String lowerCasedWord = word.toLowerCase(dictionaries.mLocale);
         final String secondWord;
         if (wasAutoCapitalized) {
-            if (isValidWord(suggestion, false /* ignoreCase */)
-                    && !isValidWord(suggestionLowerCase, false /* ignoreCase */)) {
+            if (isValidWord(word, false /* ignoreCase */)
+                    && !isValidWord(lowerCasedWord, false /* ignoreCase */)) {
                 // If the word was auto-capitalized and exists only as a capitalized word in the
                 // dictionary, then we must not downcase it before registering it. For example,
                 // the name of the contacts in start-of-sentence position would come here with the
                 // wasAutoCapitalized flag: if we downcase it, we'd register a lower-case version
                 // of that contact's name which would end up popping in suggestions.
-                secondWord = suggestion;
+                secondWord = word;
             } else {
                 // If however the word is not in the dictionary, or exists as a lower-case word
                 // only, then we consider that was a lower-case word that had been auto-capitalized.
-                secondWord = suggestionLowerCase;
+                secondWord = lowerCasedWord;
             }
         } else {
             // HACK: We'd like to avoid adding the capitalized form of common words to the User
@@ -399,20 +417,20 @@
             // consolidation is done.
             // TODO: Remove this hack when ready.
             final int lowerCaseFreqInMainDict = dictionaries.hasDict(Dictionary.TYPE_MAIN) ?
-                    dictionaries.getDict(Dictionary.TYPE_MAIN).getFrequency(suggestionLowerCase) :
+                    dictionaries.getDict(Dictionary.TYPE_MAIN).getFrequency(lowerCasedWord) :
                             Dictionary.NOT_A_PROBABILITY;
             if (maxFreq < lowerCaseFreqInMainDict
                     && lowerCaseFreqInMainDict >= CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT) {
                 // Use lower cased word as the word can be a distracter of the popular word.
-                secondWord = suggestionLowerCase;
+                secondWord = lowerCasedWord;
             } else {
-                secondWord = suggestion;
+                secondWord = word;
             }
         }
         // We demote unrecognized words (frequency < 0, below) by specifying them as "invalid".
         // We don't add words with 0-frequency (assuming they would be profanity etc.).
         final boolean isValid = maxFreq > 0;
-        UserHistoryDictionary.addToDictionary(userHistoryDictionary, previousWord, secondWord,
+        UserHistoryDictionary.addToDictionary(userHistoryDictionary, prevWord, secondWord,
                 isValid, timeStampInSeconds);
     }
 
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index d64a1a6..7dc566a 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -733,6 +733,7 @@
         // Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
         // is not guaranteed. It may even be called at the same time on a different thread.
         mSubtypeSwitcher.onSubtypeChanged(subtype);
+        mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype));
         loadKeyboard();
     }
 
@@ -808,7 +809,10 @@
 
         // The app calling setText() has the effect of clearing the composing
         // span, so we should reset our state unconditionally, even if restarting is true.
-        mInputLogic.startInput(restarting, editorInfo);
+        // We also tell the input logic about the combining rules for the current subtype, so
+        // it can adjust its combiners if needed.
+        mInputLogic.startInput(restarting, editorInfo,
+                mSubtypeSwitcher.getCombiningRulesExtraValueOfCurrentSubtype());
 
         // Note: the following does a round-trip IPC on the main thread: be careful
         final Locale currentLocale = mSubtypeSwitcher.getCurrentSubtypeLocale();
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index 0211339..c8a2fb2 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -52,7 +52,6 @@
 
     private /* final */ RichInputMethodManager mRichImm;
     private /* final */ Resources mResources;
-    private /* final */ ConnectivityManager mConnectivityManager;
 
     private final LanguageOnSpacebarHelper mLanguageOnSpacebarHelper =
             new LanguageOnSpacebarHelper();
@@ -111,10 +110,10 @@
         }
         mResources = context.getResources();
         mRichImm = RichInputMethodManager.getInstance();
-        mConnectivityManager = (ConnectivityManager) context.getSystemService(
+        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
 
-        final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo();
+        final NetworkInfo info = connectivityManager.getActiveNetworkInfo();
         mIsNetworkConnected = (info != null && info.isConnected());
 
         onSubtypeChanged(getCurrentSubtype());
@@ -327,4 +326,8 @@
                 + DUMMY_EMOJI_SUBTYPE);
         return DUMMY_EMOJI_SUBTYPE;
     }
+
+    public String getCombiningRulesExtraValueOfCurrentSubtype() {
+        return SubtypeLocaleUtils.getCombiningRulesExtraValue(getCurrentSubtype());
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index d755195..cdee496 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -41,6 +41,7 @@
     public static final int CAPS_MODE_AUTO_SHIFT_LOCKED = 0x7;
 
     private CombinerChain mCombinerChain;
+    private String mCombiningSpec; // Memory so that we don't uselessly recreate the combiner chain
 
     // The list of events that served to compose this string.
     private final ArrayList<Event> mEvents;
@@ -91,6 +92,21 @@
     }
 
     /**
+     * Restart input with a new combining spec.
+     * @param combiningSpec The spec string for combining. This is found in the extra value.
+     */
+    public void restart(final String combiningSpec) {
+        final String nonNullCombiningSpec = null == combiningSpec ? "" : combiningSpec;
+        if (nonNullCombiningSpec.equals(mCombiningSpec)) {
+            mCombinerChain.reset();
+        } else {
+            mCombinerChain = new CombinerChain(CombinerChain.createCombiners(nonNullCombiningSpec));
+            mCombiningSpec = nonNullCombiningSpec;
+        }
+        reset();
+    }
+
+    /**
      * Clear out the keys registered so far.
      */
     public void reset() {
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 75432fb..8b795b8 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -97,6 +97,11 @@
     private boolean mIsAutoCorrectionIndicatorOn;
     private long mDoubleSpacePeriodCountdownStart;
 
+    /**
+     * Create a new instance of the input logic.
+     * @param latinIME the instance of the parent LatinIME. We should remove this when we can.
+     * @param suggestionStripViewAccessor an object to access the suggestion strip view.
+     */
     public InputLogic(final LatinIME latinIME,
             final SuggestionStripViewAccessor suggestionStripViewAccessor) {
         mLatinIME = latinIME;
@@ -117,9 +122,12 @@
      *
      * @param restarting whether input is starting in the same field as before. Unused for now.
      * @param editorInfo the editorInfo associated with the editor.
+     * @param combiningSpec the combining spec string for this subtype
      */
-    public void startInput(final boolean restarting, final EditorInfo editorInfo) {
+    public void startInput(final boolean restarting, final EditorInfo editorInfo,
+            final String combiningSpec) {
         mEnteredText = null;
+        mWordComposer.restart(combiningSpec);
         resetComposingState(true /* alsoResetLastComposedWord */);
         mDeleteCount = 0;
         mSpaceState = SpaceState.NONE;
@@ -138,6 +146,14 @@
     }
 
     /**
+     * Call this when the subtype changes.
+     * @param combiningSpec the spec string for the combining rules
+     */
+    public void onSubtypeChanged(final String combiningSpec) {
+        mWordComposer.restart(combiningSpec);
+    }
+
+    /**
      * Clean up the input logic after input is finished.
      */
     public void finishInput() {
@@ -588,7 +604,7 @@
             if (null != candidate
                     && mSuggestedWords.mSequenceNumber >= mAutoCommitSequenceNumber) {
                 if (candidate.mSourceDict.shouldAutoCommit(candidate)) {
-                    final String[] commitParts = candidate.mWord.split(" ", 2);
+                    final String[] commitParts = candidate.mWord.split(Constants.WORD_SEPARATOR, 2);
                     batchPointers.shift(candidate.mIndexOfTouchPointOfSecondWord);
                     promotePhantomSpace(settingsValues);
                     mConnection.commitText(commitParts[0], 0);
@@ -1225,7 +1241,7 @@
         final int timeStampInSeconds = (int)TimeUnit.MILLISECONDS.toSeconds(
                 System.currentTimeMillis());
         mSuggest.mDictionaryFacilitator.addToUserHistory(suggestion, wasAutoCapitalized, prevWord,
-                timeStampInSeconds);
+                timeStampInSeconds, settingsValues.mBlockPotentiallyOffensive);
     }
 
     public void performUpdateSuggestionStripSync(final SettingsValues settingsValues) {
@@ -1946,10 +1962,11 @@
         final CharSequence chosenWordWithSuggestions =
                 SuggestionSpanUtils.getTextWithSuggestionSpan(mLatinIME, chosenWord,
                         suggestedWords);
-        mConnection.commitText(chosenWordWithSuggestions, 1);
-        // TODO: we pass 2 here, but would it be better to move this above and pass 1 instead?
+        // Use the 2nd previous word as the previous word because the 1st previous word is the word
+        // to be committed.
         final String prevWord = mConnection.getNthPreviousWord(
                 settingsValues.mSpacingAndPunctuations, 2);
+        mConnection.commitText(chosenWordWithSuggestions, 1);
         // Add the word to the user history dictionary
         performAdditionToUserHistoryDictionary(settingsValues, chosenWord, prevWord);
         // TODO: figure out here if this is an auto-correct or if the best word is actually
diff --git a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java
new file mode 100644
index 0000000..96f03f9
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.personalization;
+
+import android.content.Context;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.Dictionary;
+import com.android.inputmethod.latin.ExpandableBinaryDictionary;
+
+import java.io.File;
+import java.util.Locale;
+
+public class ContextualDictionary extends ExpandableBinaryDictionary {
+    /* package */ static final String NAME = PersonalizationDictionary.class.getSimpleName();
+
+    private ContextualDictionary(final Context context, final Locale locale,
+            final File dictFile) {
+        super(context, getDictName(NAME, locale, dictFile), locale, Dictionary.TYPE_CONTEXTUAL,
+                dictFile);
+        // Always reset the contents.
+        clear();
+    }
+    @UsedForTesting
+    public static ContextualDictionary getDictionary(final Context context, final Locale locale,
+            final File dictFile) {
+        return new ContextualDictionary(context, locale, dictFile);
+    }
+
+    @Override
+    public boolean isValidWord(final String word) {
+        // Strings out of this dictionary should not be considered existing words.
+        return false;
+    }
+
+    @Override
+    protected void loadInitialContentsLocked() {
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index a3aae8c..4e4c888 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -64,7 +64,7 @@
             "pref_show_language_switch_key";
     public static final String PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST =
             "pref_include_other_imes_in_language_switch_list";
-    public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20110916";
+    public static final String PREF_KEYBOARD_THEME = "pref_keyboard_theme";
     public static final String PREF_CUSTOM_INPUT_STYLES = "custom_input_styles";
     // TODO: consolidate key preview dismiss delay with the key preview animation parameters.
     public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY =
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
index 22cbd20..e1d38e7 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
@@ -37,6 +37,7 @@
 import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.inputmethod.dictionarypack.DictionarySettingsActivity;
+import com.android.inputmethod.keyboard.KeyboardTheme;
 import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.SubtypeSwitcher;
@@ -253,11 +254,31 @@
         }
         updateListPreferenceSummaryToCurrentValue(Settings.PREF_SHOW_SUGGESTIONS_SETTING);
         updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
-        updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEYBOARD_LAYOUT);
+        final ListPreference keyboardThemePref = (ListPreference)findPreference(
+                Settings.PREF_KEYBOARD_THEME);
+        if (keyboardThemePref != null) {
+            final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(prefs);
+            final String value = Integer.toString(keyboardTheme.mThemeId);
+            final CharSequence entries[] = keyboardThemePref.getEntries();
+            final int entryIndex = keyboardThemePref.findIndexOfValue(value);
+            keyboardThemePref.setSummary(entryIndex < 0 ? null : entries[entryIndex]);
+            keyboardThemePref.setValue(value);
+        }
         updateCustomInputStylesSummary(prefs, res);
     }
 
     @Override
+    public void onPause() {
+        super.onPause();
+        final SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
+        final ListPreference keyboardThemePref = (ListPreference)findPreference(
+                Settings.PREF_KEYBOARD_THEME);
+        if (keyboardThemePref != null) {
+            KeyboardTheme.saveKeyboardThemeId(keyboardThemePref.getValue(), prefs);
+        }
+    }
+
+    @Override
     public void onDestroy() {
         getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(
                 this);
@@ -287,7 +308,7 @@
         ensureConsistencyOfAutoCorrectionSettings();
         updateListPreferenceSummaryToCurrentValue(Settings.PREF_SHOW_SUGGESTIONS_SETTING);
         updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY);
-        updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEYBOARD_LAYOUT);
+        updateListPreferenceSummaryToCurrentValue(Settings.PREF_KEYBOARD_THEME);
         refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources());
     }
 
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index dde50cc..de2eb95 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -205,7 +205,8 @@
     }
 
     public boolean isWordCodePoint(final int code) {
-        return Character.isLetter(code) || isWordConnector(code);
+        return Character.isLetter(code) || isWordConnector(code)
+                || Character.COMBINING_SPACING_MARK == Character.getType(code);
     }
 
     public boolean isUsuallyPrecededBySpace(final int code) {
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index a578fa4..d4f7f36 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -18,7 +18,9 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Color;
+import android.graphics.drawable.Drawable;
 import android.support.v4.view.ViewCompat;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -31,6 +33,7 @@
 import android.view.View.OnLongClickListener;
 import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.widget.ImageButton;
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
@@ -59,12 +62,14 @@
         public void addWordToUserDictionary(String word);
         public void showImportantNoticeContents();
         public void pickSuggestionManually(int index, SuggestedWordInfo word);
+        public void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat);
     }
 
     static final boolean DBG = LatinImeLogger.sDBG;
     private static final float DEBUG_INFO_TEXT_SIZE_IN_DIP = 6.0f;
 
     private final ViewGroup mSuggestionsStrip;
+    private final ImageButton mVoiceKey;
     private final ViewGroup mAddToDictionaryStrip;
     private final View mImportantNoticeStrip;
     MainKeyboardView mMainKeyboardView;
@@ -86,39 +91,42 @@
 
     private static class StripVisibilityGroup {
         private final View mSuggestionsStrip;
+        private final View mVoiceKey;
         private final View mAddToDictionaryStrip;
         private final View mImportantNoticeStrip;
 
-        public StripVisibilityGroup(final View suggestionsStrip, final View addToDictionaryStrip,
-                final View importantNoticeStrip) {
+        public StripVisibilityGroup(final View suggestionsStrip, final View voiceKey,
+                final View addToDictionaryStrip, final View importantNoticeStrip) {
             mSuggestionsStrip = suggestionsStrip;
+            mVoiceKey = voiceKey;
             mAddToDictionaryStrip = addToDictionaryStrip;
             mImportantNoticeStrip = importantNoticeStrip;
-            showSuggestionsStrip();
+            showSuggestionsStrip(false /* voiceKeyEnabled */);
         }
 
-        public void setLayoutDirection(final boolean isRtlLanguage) {
-            final int layoutDirection = isRtlLanguage ? ViewCompat.LAYOUT_DIRECTION_RTL
-                    : ViewCompat.LAYOUT_DIRECTION_LTR;
+        public void setLayoutDirection(final int layoutDirection) {
             ViewCompat.setLayoutDirection(mSuggestionsStrip, layoutDirection);
             ViewCompat.setLayoutDirection(mAddToDictionaryStrip, layoutDirection);
             ViewCompat.setLayoutDirection(mImportantNoticeStrip, layoutDirection);
         }
 
-        public void showSuggestionsStrip() {
+        public void showSuggestionsStrip(final boolean enableVoiceKey) {
             mSuggestionsStrip.setVisibility(VISIBLE);
+            mVoiceKey.setVisibility(enableVoiceKey ? VISIBLE : INVISIBLE);
             mAddToDictionaryStrip.setVisibility(INVISIBLE);
             mImportantNoticeStrip.setVisibility(INVISIBLE);
         }
 
         public void showAddToDictionaryStrip() {
             mSuggestionsStrip.setVisibility(INVISIBLE);
+            mVoiceKey.setVisibility(INVISIBLE);
             mAddToDictionaryStrip.setVisibility(VISIBLE);
             mImportantNoticeStrip.setVisibility(INVISIBLE);
         }
 
         public void showImportantNoticeStrip() {
             mSuggestionsStrip.setVisibility(INVISIBLE);
+            mVoiceKey.setVisibility(INVISIBLE);
             mAddToDictionaryStrip.setVisibility(INVISIBLE);
             mImportantNoticeStrip.setVisibility(VISIBLE);
         }
@@ -145,10 +153,11 @@
         inflater.inflate(R.layout.suggestions_strip, this);
 
         mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip);
+        mVoiceKey = (ImageButton)findViewById(R.id.suggestions_strip_voice_key);
         mAddToDictionaryStrip = (ViewGroup)findViewById(R.id.add_to_dictionary_strip);
         mImportantNoticeStrip = findViewById(R.id.important_notice_strip);
-        mStripVisibilityGroup = new StripVisibilityGroup(mSuggestionsStrip, mAddToDictionaryStrip,
-                mImportantNoticeStrip);
+        mStripVisibilityGroup = new StripVisibilityGroup(mSuggestionsStrip, mVoiceKey,
+                mAddToDictionaryStrip, mImportantNoticeStrip);
 
         for (int pos = 0; pos < SuggestedWords.MAX_SUGGESTIONS; pos++) {
             final TextView word = new TextView(context, null, R.attr.suggestionWordStyle);
@@ -177,6 +186,13 @@
                 R.dimen.config_more_suggestions_modal_tolerance);
         mMoreSuggestionsSlidingDetector = new GestureDetector(
                 context, mMoreSuggestionsSlidingListener);
+
+        final TypedArray keyboardAttr = context.obtainStyledAttributes(attrs,
+                R.styleable.Keyboard, defStyle, R.style.SuggestionStripView);
+        final Drawable iconVoice = keyboardAttr.getDrawable(R.styleable.Keyboard_iconShortcutKey);
+        keyboardAttr.recycle();
+        mVoiceKey.setImageDrawable(iconVoice);
+        mVoiceKey.setOnClickListener(this);
     }
 
     /**
@@ -188,16 +204,30 @@
         mMainKeyboardView = (MainKeyboardView)inputView.findViewById(R.id.keyboard_view);
     }
 
+    private boolean isVoiceKeyEnabled() {
+        if (mMainKeyboardView == null) {
+            return false;
+        }
+        final Keyboard keyboard = mMainKeyboardView.getKeyboard();
+        if (keyboard == null) {
+            return false;
+        }
+        return keyboard.mId.mHasShortcutKey;
+    }
+
     public void setSuggestions(final SuggestedWords suggestedWords, final boolean isRtlLanguage) {
         clear();
-        mStripVisibilityGroup.setLayoutDirection(isRtlLanguage);
+        final int layoutDirection = isRtlLanguage ? ViewCompat.LAYOUT_DIRECTION_RTL
+                : ViewCompat.LAYOUT_DIRECTION_LTR;
+        setLayoutDirection(layoutDirection);
+        mStripVisibilityGroup.setLayoutDirection(layoutDirection);
         mSuggestedWords = suggestedWords;
         mSuggestionsCountInStrip = mLayoutHelper.layoutAndReturnSuggestionCountInStrip(
                 mSuggestedWords, mSuggestionsStrip, this);
         if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
             ResearchLogger.suggestionStripView_setSuggestions(mSuggestedWords);
         }
-        mStripVisibilityGroup.showSuggestionsStrip();
+        mStripVisibilityGroup.showSuggestionsStrip(isVoiceKeyEnabled());
     }
 
     public int setMoreSuggestionsHeight(final int remainingHeight) {
@@ -252,7 +282,7 @@
     public void clear() {
         mSuggestionsStrip.removeAllViews();
         removeAllDebugInfoViews();
-        mStripVisibilityGroup.showSuggestionsStrip();
+        mStripVisibilityGroup.showSuggestionsStrip(false /* enableVoiceKey */);
         dismissMoreSuggestionsPanel();
     }
 
@@ -415,6 +445,12 @@
             mListener.showImportantNoticeContents();
             return;
         }
+        if (view == mVoiceKey) {
+            mListener.onCodeInput(Constants.CODE_SHORTCUT,
+                    Constants.SUGGESTION_STRIP_COORDINATE, Constants.SUGGESTION_STRIP_COORDINATE,
+                    false /* isKeyRepeat */);
+            return;
+        }
         final Object tag = view.getTag();
         // {@link String} tag is set at {@link #showAddToDictionaryHint(String,CharSequence)}.
         if (tag instanceof String) {
diff --git a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
index b37779b..938d271 100644
--- a/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/SubtypeLocaleUtils.java
@@ -324,4 +324,8 @@
     public static boolean isRtlLanguage(final InputMethodSubtype subtype) {
         return isRtlLanguage(getSubtypeLocale(subtype));
     }
+
+    public static String getCombiningRulesExtraValue(final InputMethodSubtype subtype) {
+        return subtype.getExtraValueOf(Constants.Subtype.ExtraValue.COMBINING_RULES);
+    }
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
index 0fb6ff2..75bd609 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.preference.PreferenceManager;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.ContextThemeWrapper;
@@ -40,9 +41,6 @@
 
 @SmallTest
 public class KeyboardLayoutSetTestsBase extends AndroidTestCase {
-    private static final KeyboardTheme DEFAULT_KEYBOARD_THEME =
-            KeyboardTheme.getDefaultKeyboardTheme();
-
     // All input method subtypes of LatinIME.
     private final ArrayList<InputMethodSubtype> mAllSubtypesList = CollectionUtils.newArrayList();
     private final ArrayList<InputMethodSubtype> mAsciiCapableSubtypesList =
@@ -58,7 +56,9 @@
         super.setUp();
         mScreenMetrics = mContext.getResources().getInteger(R.integer.config_screen_metrics);
 
-        mThemeContext = new ContextThemeWrapper(mContext, DEFAULT_KEYBOARD_THEME.mStyleId);
+        final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(
+                PreferenceManager.getDefaultSharedPreferences(mContext));
+        mThemeContext = new ContextThemeWrapper(mContext, keyboardTheme.mStyleId);
         RichInputMethodManager.init(mThemeContext);
         final RichInputMethodManager richImm = RichInputMethodManager.getInstance();
 
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
new file mode 100644
index 0000000..9b532fe
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard;
+
+import android.content.SharedPreferences;
+import android.os.Build.VERSION_CODES;
+import android.preference.PreferenceManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+@SmallTest
+public class KeyboardThemeTests extends AndroidTestCase {
+    private SharedPreferences mPrefs;
+
+    private static final int THEME_ID_NULL = -1;
+    private static final int THEME_ID_ICS = KeyboardTheme.THEME_ID_ICS;
+    private static final int THEME_ID_KLP = KeyboardTheme.THEME_ID_KLP;
+    private static final int THEME_ID_LMP = KeyboardTheme.THEME_ID_LMP;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
+    }
+
+    private void assertDefaultKeyboardTheme(final int sdkVersion, final int oldThemeId,
+            final int expectedThemeId) {
+        if (oldThemeId == THEME_ID_NULL) {
+            mPrefs.edit().remove(KeyboardTheme.KITKAT_KEYBOARD_THEME_KEY).apply();
+        } else {
+            final String themeIdString = Integer.toString(oldThemeId);
+            mPrefs.edit().putString(KeyboardTheme.KITKAT_KEYBOARD_THEME_KEY, themeIdString).apply();
+        }
+        final KeyboardTheme defaultTheme =
+                KeyboardTheme.getDefaultKeyboardTheme(mPrefs, sdkVersion);
+        assertNotNull(defaultTheme);
+        assertEquals(expectedThemeId, defaultTheme.mThemeId);
+        assertFalse(mPrefs.contains(KeyboardTheme.KITKAT_KEYBOARD_THEME_KEY));
+    }
+
+    private void assertDefaultKeyboardThemeICS(final int sdkVersion) {
+        assertDefaultKeyboardTheme(sdkVersion, THEME_ID_NULL, THEME_ID_ICS);
+        assertDefaultKeyboardTheme(sdkVersion, THEME_ID_ICS, THEME_ID_ICS);
+        assertDefaultKeyboardTheme(sdkVersion, THEME_ID_KLP, THEME_ID_KLP);
+    }
+
+    private void assertDefaultKeyboardThemeKLP(final int sdkVersion) {
+        assertDefaultKeyboardTheme(sdkVersion, THEME_ID_NULL, THEME_ID_KLP);
+        assertDefaultKeyboardTheme(sdkVersion, THEME_ID_ICS, THEME_ID_ICS);
+        assertDefaultKeyboardTheme(sdkVersion, THEME_ID_KLP, THEME_ID_KLP);
+    }
+
+    private void assertDefaultKeyboardThemeLMP(final int sdkVersion) {
+        // Forced to switch to LMP theme.
+        assertDefaultKeyboardTheme(sdkVersion, THEME_ID_NULL, THEME_ID_LMP);
+        assertDefaultKeyboardTheme(sdkVersion, THEME_ID_ICS, THEME_ID_LMP);
+        assertDefaultKeyboardTheme(sdkVersion, THEME_ID_KLP, THEME_ID_LMP);
+    }
+
+    public void testDefaultKeyboardThemeICS() {
+        assertDefaultKeyboardThemeICS(VERSION_CODES.ICE_CREAM_SANDWICH);
+        assertDefaultKeyboardThemeICS(VERSION_CODES.ICE_CREAM_SANDWICH_MR1);
+    }
+
+    public void testDefaultKeyboardThemeJB() {
+        assertDefaultKeyboardThemeICS(VERSION_CODES.JELLY_BEAN);
+        assertDefaultKeyboardThemeICS(VERSION_CODES.JELLY_BEAN_MR1);
+        assertDefaultKeyboardThemeICS(VERSION_CODES.JELLY_BEAN_MR2);
+    }
+
+    public void testDefaultKeyboardThemeKLP() {
+        assertDefaultKeyboardThemeKLP(VERSION_CODES.KITKAT);
+    }
+
+    public void testDefaultKeyboardThemeLMP() {
+        // TODO: Update this constant once the *next* version becomes available.
+        assertDefaultKeyboardThemeLMP(VERSION_CODES.CUR_DEVELOPMENT);
+    }
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java b/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java
index 99cf6e5..7ba1d78 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Dvorak.java
@@ -51,7 +51,7 @@
 
         @Override
         public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
-            return isPhone ? joinKeys(key("q", SHORTCUT_KEY, SETTINGS_KEY)) : joinKeys(key("/"));
+            return isPhone ? joinKeys(key("q", SETTINGS_KEY)) : joinKeys(key("/"));
         }
 
         @Override
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java b/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java
index a007089..16d2f86 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Farsi.java
@@ -91,7 +91,7 @@
 
         @Override
         public ExpectedKey[] getSpaceKeys(final boolean isPhone) {
-            return joinKeys(SPACE_KEY, key(ZWNJ_KEY, ZWJ_KEY));
+            return joinKeys(LANGUAGE_SWITCH_KEY, SPACE_KEY, key(ZWNJ_KEY, ZWJ_KEY));
         }
 
         @Override
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java b/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java
index afd26e4..cf20149 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/HindiCompact.java
@@ -16,29 +16,12 @@
 
 package com.android.inputmethod.keyboard.layout;
 
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.SIGN_ANUSVARA;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.SIGN_CANDRABINDU;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.SIGN_NUKTA;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.SIGN_VIRAMA;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.SIGN_VISARGA;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_AA;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_AI;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_AU;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_CANDRA_E;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_CANDRA_O;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_E;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_I;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_II;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_O;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_U;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_UU;
-import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.VOWEL_SIGN_VOCALIC_R;
+import static com.android.inputmethod.keyboard.layout.DevanagariLetterConstants.*;
 
 import com.android.inputmethod.keyboard.layout.Hindi.HindiCustomizer;
 import com.android.inputmethod.keyboard.layout.Hindi.HindiSymbols;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
-import com.android.inputmethod.latin.Constants;
 
 import java.util.Locale;
 
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java b/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
index 4123a22..e4e9554 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/LayoutBase.java
@@ -29,7 +29,6 @@
  * The base class of keyboard layout.
  */
 public abstract class LayoutBase extends AbstractLayoutBase {
-
     /**
      * This class is used to customize common keyboard layout to language specific layout.
      */
@@ -152,7 +151,7 @@
          *         keyboard.
          */
         public ExpectedKey[] getSpaceKeys(final boolean isPhone) {
-            return joinKeys(SPACE_KEY);
+            return joinKeys(LANGUAGE_SWITCH_KEY, SPACE_KEY);
         }
 
         /**
@@ -161,7 +160,8 @@
          * @return the array of {@link ExpectedKey} that should be placed at left of the spacebar.
          */
         public ExpectedKey[] getKeysLeftToSpacebar(final boolean isPhone) {
-            return isPhone ? joinKeys(key(",", SETTINGS_KEY)) : joinKeys("/");
+            // U+002C: "," COMMA
+            return isPhone ? joinKeys(key("\u002C", SETTINGS_KEY)) : joinKeys("/");
         }
 
         /**
@@ -306,6 +306,10 @@
 
     /**
      * Get common alphabet layout. This layout doesn't contain any special keys.
+     *
+     * A keyboard layout is an array of rows, and a row consists of an array of
+     * {@link ExpectedKey}s. Each row may have different number of {@link ExpectedKey}s.
+     *
      * @param isPhone true if requesting phone's layout.
      * @return the common alphabet keyboard layout.
      */
@@ -313,6 +317,10 @@
 
     /**
      * Get common alphabet shifted layout. This layout doesn't contain any special keys.
+     *
+     * A keyboard layout is an array of rows, and a row consists of an array of
+     * {@link ExpectedKey}s. Each row may have different number of {@link ExpectedKey}s.
+     *
      * @param isPhone true if requesting phone's layout.
      * @param elementId the element id of the requesting shifted mode.
      * @return the common alphabet shifted keyboard layout.
@@ -327,9 +335,13 @@
 
     /**
      * Get the complete expected keyboard layout.
+     *
+     * A keyboard layout is an array of rows, and a row consists of an array of
+     * {@link ExpectedKey}s. Each row may have different number of {@link ExpectedKey}s.
+     *
      * @param isPhone true if requesting phone's layout.
      * @param elementId the element id of the requesting keyboard mode.
-     * @return
+     * @return the keyboard layout of the <code>elementId</code>.
      */
     public ExpectedKey[][] getLayout(final boolean isPhone, final int elementId) {
         if (elementId == KeyboardId.ELEMENT_SYMBOLS) {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/NepaliRomanized.java b/tests/src/com/android/inputmethod/keyboard/layout/NepaliRomanized.java
index 7048dbb..7933d07 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/NepaliRomanized.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/NepaliRomanized.java
@@ -47,7 +47,7 @@
 
         @Override
         public ExpectedKey[] getSpaceKeys(final boolean isPhone) {
-            return joinKeys(SPACE_KEY, key(ZWNJ_KEY, ZWJ_KEY));
+            return joinKeys(LANGUAGE_SWITCH_KEY, SPACE_KEY, key(ZWNJ_KEY, ZWJ_KEY));
         }
 
         // U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractKeyboardBuilder.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractKeyboardBuilder.java
index 3365b92..6e72104 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractKeyboardBuilder.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractKeyboardBuilder.java
@@ -21,9 +21,9 @@
 /**
  * This class builds a keyboard that is a two dimensional array of elements <code>E</code>.
  *
- * A keyboard consists of array of rows, and a row consists of array of elements. Each row may have
- * different number of elements. A element of a keyboard can be specified by a row number and a
- * column number, both numbers starts from 1.
+ * A keyboard consists of an array of rows, and a row consists of an array of elements. Each row
+ * may have different number of elements. A element of a keyboard can be specified by a row number
+ * and a column number, both numbers starts from 1.
  *
  * @param <E> the type of a keyboard element. A keyboard element must be an immutable object.
  */
@@ -39,8 +39,7 @@
     abstract E[][] newArrayOfArray(final int size);
 
     /**
-     * Construct a builder filled with the default element.
-     * @param dimensions the integer array of each row's size.
+     * Construct an empty builder.
      */
     AbstractKeyboardBuilder() {
         mRows = newArrayOfArray(0);
@@ -80,7 +79,7 @@
      * Get the current contents of the specified row.
      * @param row the row number to get the contents.
      * @return the array of elements at row number <code>row</code>.
-     * @throws {@link RuntimeException} if <code>row</code> is illegal.
+     * @throws RuntimeException if <code>row</code> is illegal.
      */
     E[] getRowAt(final int row) {
         final int rowIndex = row - 1;
@@ -94,7 +93,7 @@
      * Set an array of elements to the specified row.
      * @param row the row number to set <code>elements</code>.
      * @param elements the array of elements to set at row number <code>row</code>.
-     * @throws {@link RuntimeException} if <code>row</code> is illegal.
+     * @throws RuntimeException if <code>row</code> is illegal.
      */
     void setRowAt(final int row, final E[] elements) {
         final int rowIndex = row - 1;
@@ -114,7 +113,7 @@
      * @param element the element to set or insert at <code>row,column</code>.
      * @param insert if true, the <code>element</code> is inserted at <code>row,column</code>.
      *        Otherwise the <code>element</code> replace the element at <code>row,column</code>.
-     * @throws {@link RuntimeException} if <code>row</code> or <code>column</code> is illegal.
+     * @throws RuntimeException if <code>row</code> or <code>column</code> is illegal.
      */
     void setElementAt(final int row, final int column, final E element, final boolean insert) {
         final E[] elements = getRowAt(row);
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
index 6176f6a..9e0039d 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/AbstractLayoutBase.java
@@ -19,7 +19,6 @@
 import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
 import com.android.inputmethod.keyboard.layout.expected.ExpectedKey.ExpectedAdditionalMoreKey;
 import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.utils.StringUtils;
 
 /**
  * Base class to create an expected keyboard for unit test.
@@ -109,6 +108,8 @@
     // Icon ids.
     private static final int ICON_DELETE = KeyboardIconsSet.getIconId(
             KeyboardIconsSet.NAME_DELETE_KEY);
+    private static final int ICON_SPACE = KeyboardIconsSet.getIconId(
+            KeyboardIconsSet.NAME_SPACE_KEY);
     private static final int ICON_TAB = KeyboardIconsSet.getIconId(
             KeyboardIconsSet.NAME_TAB_KEY);
     private static final int ICON_SHORTCUT = KeyboardIconsSet.getIconId(
@@ -131,6 +132,5 @@
             ICON_LANGUAGE_SWITCH, Constants.CODE_LANGUAGE_SWITCH);
     public static final ExpectedKey ENTER_KEY = key(ICON_ENTER, Constants.CODE_ENTER);
     public static final ExpectedKey EMOJI_KEY = key(ICON_EMOJI, Constants.CODE_EMOJI);
-    public static final ExpectedKey SPACE_KEY = key(
-            StringUtils.newSingleCodePointString(Constants.CODE_SPACE));
+    public static final ExpectedKey SPACE_KEY = key(ICON_SPACE, Constants.CODE_SPACE);
 }
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java
index 26d2e2a..d0fea58 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java
@@ -28,6 +28,9 @@
 
 /**
  * This class builds an actual keyboard for unit test.
+ *
+ * An actual keyboard is an array of rows, and a row consists of an array of {@link Key}s.
+ * Each row may have different number of {@link Key}s.
  */
 public final class ActualKeyboardBuilder extends AbstractKeyboardBuilder<Key> {
     private static ArrayList<Key> filterOutSpacer(final List<Key> keys) {
@@ -43,7 +46,8 @@
 
     /**
      * Create the keyboard that consists of the array of rows of the actual keyboard's keys.
-     * @param sortedKeys the sorted list of keys of the actual keyboard.
+     * @param sortedKeys keys list of the actual keyboard that is sorted from top-left to
+     * bottom-right.
      * @return the actual keyboard grouped with rows.
      */
     public static Key[][] buildKeyboard(final List<Key> sortedKeys) {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyboardBuilder.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyboardBuilder.java
index f068ad1..e06d34d 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyboardBuilder.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ExpectedKeyboardBuilder.java
@@ -24,6 +24,11 @@
 
 /**
  * This class builds an expected keyboard for unit test.
+ *
+ * An expected keyboard is an array of rows, and a row consists of an array of {@link ExpectedKey}s.
+ * Each row may have different number of {@link ExpectedKey}s. While building an expected keyboard,
+ * an {@link ExpectedKey} can be specified by a row number and a column number, both numbers starts
+ * from 1.
  */
 public final class ExpectedKeyboardBuilder extends AbstractKeyboardBuilder<ExpectedKey> {
     public ExpectedKeyboardBuilder() {
@@ -212,7 +217,7 @@
      * @param keys the array of keys to insert at <code>row,column</code>. Each key can be
      *        {@link ExpectedKey}, {@link ExpectedKey} array, and {@link String}.
      * @return this builder.
-     * @throws {@link RuntimeException} if <code>row</code> or <code>column</code> is illegal.
+     * @throws RuntimeException if <code>row</code> or <code>column</code> is illegal.
      */
     public ExpectedKeyboardBuilder insertKeysAtRow(final int row, final int column,
             final Object ... keys) {
@@ -229,7 +234,7 @@
      * @param keys the array of keys to add on the left most of the row. Each key can be
      *        {@link ExpectedKey}, {@link ExpectedKey} array, and {@link String}.
      * @return this builder.
-     * @throws {@link RuntimeException} if <code>row</code> is illegal.
+     * @throws RuntimeException if <code>row</code> is illegal.
      */
     public ExpectedKeyboardBuilder addKeysOnTheLeftOfRow(final int row,
             final Object ... keys) {
@@ -247,7 +252,7 @@
      * @param keys the array of keys to add on the right most of the row. Each key can be
      *        {@link ExpectedKey}, {@link ExpectedKey} array, and {@link String}.
      * @return this builder.
-     * @throws {@link RuntimeException} if <code>row</code> is illegal.
+     * @throws RuntimeException if <code>row</code> is illegal.
      */
     public ExpectedKeyboardBuilder addKeysOnTheRightOfRow(final int row,
             final Object ... keys) {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java
index 4002c49..d4e8fb6 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/LayoutTestsBase.java
@@ -51,7 +51,10 @@
         mSubtype = getSubtype(mLayout.getLocale(), mLayout.getName());
         mLogTag = SubtypeLocaleUtils.getSubtypeNameForLogging(mSubtype) + "/"
                 + (isPhone() ? "phone" : "tablet");
-        mKeyboardLayoutSet = createKeyboardLayoutSet(mSubtype, null /* editorInfo */);
+        // TODO: Test with language switch key enabled and disabled.
+        mKeyboardLayoutSet = createKeyboardLayoutSet(mSubtype, null /* editorInfo */,
+                true /* isShortcutImeEnabled */, true /* showsVoiceInputKey */,
+                true /* isLanguageSwitchKeyEnabled */);
     }
 
     // Those helper methods have a lower case name to be readable when defining expected keyboard
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTestsReorderingMyanmar.java b/tests/src/com/android/inputmethod/latin/InputLogicTestsReorderingMyanmar.java
new file mode 100644
index 0000000..b3f2819
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTestsReorderingMyanmar.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Pair;
+
+/*
+ * Relevant characters for this test :
+ * Spurs the need to reorder :
+ * U+1031 MYANMAR VOWEL SIGN E : ေ
+ * U+1004 U+103A U+1039 Kinzi. It's a compound character.
+ *
+ * List of consonants :
+ * U+1000 MYANMAR LETTER KA က
+ * U+1001 MYANMAR LETTER KHA ခ
+ * U+1002 MYANMAR LETTER GA ဂ
+ * U+1003 MYANMAR LETTER GHA ဃ
+ * U+1004 MYANMAR LETTER NGA င
+ * U+1005 MYANMAR LETTER CA စ
+ * U+1006 MYANMAR LETTER CHA ဆ
+ * U+1007 MYANMAR LETTER JA ဇ
+ * U+1008 MYANMAR LETTER JHA ဈ
+ * U+1009 MYANMAR LETTER NYA ဉ
+ * U+100A MYANMAR LETTER NNYA ည
+ * U+100B MYANMAR LETTER TTA ဋ
+ * U+100C MYANMAR LETTER TTHA ဌ
+ * U+100D MYANMAR LETTER DDA ဍ
+ * U+100E MYANMAR LETTER DDHA ဎ
+ * U+100F MYANMAR LETTER NNA ဏ
+ * U+1010 MYANMAR LETTER TA တ
+ * U+1011 MYANMAR LETTER THA ထ
+ * U+1012 MYANMAR LETTER DA ဒ
+ * U+1013 MYANMAR LETTER DHA ဓ
+ * U+1014 MYANMAR LETTER NA န
+ * U+1015 MYANMAR LETTER PA ပ
+ * U+1016 MYANMAR LETTER PHA ဖ
+ * U+1017 MYANMAR LETTER BA ဗ
+ * U+1018 MYANMAR LETTER BHA ဘ
+ * U+1019 MYANMAR LETTER MA မ
+ * U+101A MYANMAR LETTER YA ယ
+ * U+101B MYANMAR LETTER RA ရ
+ * U+101C MYANMAR LETTER LA လ
+ * U+101D MYANMAR LETTER WA ဝ
+ * U+101E MYANMAR LETTER SA သ
+ * U+101F MYANMAR LETTER HA ဟ
+ * U+1020 MYANMAR LETTER LLA ဠ
+ * U+103F MYANMAR LETTER GREAT SA ဿ
+ *
+ * List of medials :
+ * U+103B MYANMAR CONSONANT SIGN MEDIAL YA ျ
+ * U+103C MYANMAR CONSONANT SIGN MEDIAL RA ြ
+ * U+103D MYANMAR CONSONANT SIGN MEDIAL WA ွ
+ * U+103E MYANMAR CONSONANT SIGN MEDIAL HA ှ
+ * U+105E MYANMAR CONSONANT SIGN MON MEDIAL NA ၞ
+ * U+105F MYANMAR CONSONANT SIGN MON MEDIAL MA ၟ
+ * U+1060 MYANMAR CONSONANT SIGN MON MEDIAL LA ၠ
+ * U+1082 MYANMAR CONSONANT SIGN SHAN MEDIAL WA ႂ
+ *
+ * Other relevant characters :
+ * U+200C ZERO WIDTH NON-JOINER
+ * U+200B ZERO WIDTH SPACE
+ */
+
+@LargeTest
+public class InputLogicTestsReorderingMyanmar extends InputTestsBase {
+    // The tests are formatted as follows.
+    // Each test is an entry in the array of Pair arrays.
+
+    // One test is an array of pairs. Each pair contains, in the `first' member,
+    // the code points that the next key press should contain. In the `second'
+    // member is stored the string that should be in the text view after this
+    // key press.
+
+    private static final Pair[][] TESTS = {
+
+        // Tests for U+1031 MYANMAR VOWEL SIGN E : ေ
+        new Pair[] { // Type : U+1031 U+1000 U+101F ေ က ဟ
+            Pair.create(new int[] { 0x1031 }, "\u1031"), // ေ
+            Pair.create(new int[] { 0x1000 }, "\u1000\u1031"), // ကေ
+            Pair.create(new int[] { 0x101F }, "\u1000\u1031\u101F") // ကေဟ
+        },
+
+        new Pair[] { // Type : U+1000 U+1031 U+101F က ေ ဟ
+            Pair.create(new int[] { 0x1000 }, "\u1000"), // က
+            Pair.create(new int[] { 0x1031 }, "\u1000\u200B\u1031"), // က‌ေ
+            Pair.create(new int[] { 0x101F }, "\u1000\u101F\u1031") // ကဟေ
+        },
+
+        new Pair[] { // Type : U+1031 U+101D U+103E U+1018 ေ ဝ ှ ဘ
+            Pair.create(new int[] { 0x1031 }, "\u1031"), // ေ
+            Pair.create(new int[] { 0x101D }, "\u101D\u1031"), // ဝေ
+            Pair.create(new int[] { 0x103E }, "\u101D\u103E\u1031"), // ဝှေ
+            Pair.create(new int[] { 0x1018 }, "\u101D\u103E\u1031\u1018") // ဝှေဘ
+        },
+
+        new Pair[] { // Type : U+1031 U+1014 U+1031 U+1000 U+102C U+1004 U+103A U+1038 U+101C
+            // U+102C U+1038 U+104B ေ န ေ က ာ င ် း လ ာ း ။
+            Pair.create(new int[] { 0x1031 }, "\u1031"), // ေ
+            Pair.create(new int[] { 0x1014 }, "\u1014\u1031"), // နေ
+            Pair.create(new int[] { 0x1031 }, "\u1014\u1031\u1031"), // နေ‌ေ
+            Pair.create(new int[] { 0x1000 }, "\u1014\u1031\u1000\u1031"), // နေကေ
+            Pair.create(new int[] { 0x102C }, "\u1014\u1031\u1000\u1031\u102C"), // နေကော
+            Pair.create(new int[] { 0x1004 }, "\u1014\u1031\u1000\u1031\u102C\u1004"), // နေကောင
+            Pair.create(new int[] { 0x103A }, // နေကောင်
+                    "\u1014\u1031\u1000\u1031\u102C\u1004\u103A"),
+            Pair.create(new int[] { 0x1038 }, // နေကောင်း
+                    "\u1014\u1031\u1000\u1031\u102C\u1004\u103A\u1038"),
+            Pair.create(new int[] { 0x101C }, // နေကောင်းလ
+                    "\u1014\u1031\u1000\u1031\u102C\u1004\u103A\u1038\u101C"),
+            Pair.create(new int[] { 0x102C }, // နေကောင်းလာ
+                    "\u1014\u1031\u1000\u1031\u102C\u1004\u103A\u1038\u101C\u102C"),
+            Pair.create(new int[] { 0x1038 }, // နေကောင်းလား
+                    "\u1014\u1031\u1000\u1031\u102C\u1004\u103A\u1038\u101C\u102C\u1038"),
+            Pair.create(new int[] { 0x104B }, // နေကောင်းလား။
+                    "\u1014\u1031\u1000\u1031\u102C\u1004\u103A\u1038\u101C\u102C\u1038\u104B")
+        },
+
+        new Pair[] { // Type : U+1031 U+1031 U+1031 U+1000 ေ ေ ေ က
+            Pair.create(new int[] { 0x1031 }, "\u1031"), // ေ
+            Pair.create(new int[] { 0x1031 }, "\u1031\u1031"), // ေေ
+            Pair.create(new int[] { 0x1031 }, "\u1031\u1031\u1031"), // U+1031ေေေ
+            Pair.create(new int[] { 0x1000 }, "\u1031\u1031\u1000\u1031") // ေေကေ
+        },
+
+        new Pair[] { // Type : U+1031 U+1001 U+103B U+103D U+1038 ေ ခ ျ ွ း
+            Pair.create(new int[] { 0x1031 }, "\u1031"), // ေ
+            Pair.create(new int[] { 0x1001 }, "\u1001\u1031"), // ခေ
+            Pair.create(new int[] { 0x103B }, "\u1001\u103B\u1031"), // ချေ
+            Pair.create(new int[] { 0x103D }, "\u1001\u103B\u103D\u1031"), // ချွေ
+            Pair.create(new int[] { 0x1038 }, "\u1001\u103B\u103D\u1031\u1038") // ချွေး
+        },
+
+        // Tests for Kinzi U+1004 U+103A U+1039 :
+
+        /* Kinzi reordering is not implemented yet. Uncomment these tests when it is.
+
+        new Pair[] { // Type : U+1021 U+1002 (U+1004 U+103A U+1039)
+            // U+101C U+1014 U+103A အ ဂ (င ် ္) လ န ်
+            Pair.create(new int[] { 0x1021 }, "\u1021"), // အ
+            Pair.create(new int[] { 0x1002 }, "\u1021\u1002"), // အဂ
+            Pair.create(new int[] { 0x1004, 0x103A, 0x1039 }, // အင်္ဂ
+                    "\u1021\u1004\u103A\u1039\u1002"),
+            Pair.create(new int[] { 0x101C }, // အင်္ဂလ
+                    "\u1021\u1004\u103A\u1039\u1002\u101C"),
+            Pair.create(new int[] { 0x1014 }, // အင်္ဂလန
+                    "\u1021\u1004\u103A\u1039\u1002\u101C\u1014"),
+            Pair.create(new int[] { 0x103A }, // အင်္ဂလန်
+                    "\u1021\u1004\u103A\u1039\u1002\u101C\u1014\u103A")
+        },
+
+        new Pair[] { //Type : kinzi after a whole syllable U+101E U+1001 U+103B U+102D U+102F
+            // (U+1004 U+103A U+1039) U+1004 U+103A U+1038 သ ခ ျ ိ ု င ် ္ င ် း
+            Pair.create(new int[] { 0x101E }, "\u101E"), // သခ
+            Pair.create(new int[] { 0x1001 }, "\u101E\u1001"), // သခ
+            Pair.create(new int[] { 0x103B }, "\u101E\u1001\u103B"), // သချ
+            Pair.create(new int[] { 0x102D }, "\u101E\u1001\u103B\u102D"), // သချိ
+            Pair.create(new int[] { 0x102F }, "\u101E\u1001\u103B\u102D\u102F"), // သချို
+            Pair.create(new int[] { 0x1004, 0x103A, 0x1039}, // သင်္ချို
+                    "\u101E\u1004\u103A\u1039\u1001\u103B\u102D\u102F"),
+            Pair.create(new int[] { 0x1004 }, // သင်္ချိုင
+                    "\u101E\u1004\u103A\u1039\u1001\u103B\u102D\u102F\u1004"),
+            Pair.create(new int[] { 0x103A }, // သင်္ချိုင်
+                    "\u101E\u1004\u103A\u1039\u1001\u103B\u102D\u102F\u1004\u103A"),
+            Pair.create(new int[] { 0x1038 }, // သင်္ချိုင်း
+                    "\u101E\u1004\u103A\u1039\u1001\u103B\u102D\u102F\u1004\u103A\u1038")
+        },
+
+        new Pair[] { // Type : kinzi after the consonant U+101E U+1001 (U+1004 U+103A U+1039)
+            // U+103B U+102D U+102F U+1004 U+103A U+1038 သ ခ င ် ္ ျ ိ ု င ် း
+            Pair.create(new int[] { 0x101E }, "\u101E"), // သခ
+            Pair.create(new int[] { 0x1001 }, "\u101E\u1001"), // သခ
+            Pair.create(new int[] { 0x1004, 0x103A, 0x1039 }, // သင်္ခ
+                    "\u101E\u1004\u103A\u1039\u1001"),
+            Pair.create(new int[] { 0x103B }, // သင်္ချ
+                    "\u101E\u1004\u103A\u1039\u1001\u103B"),
+            Pair.create(new int[] { 0x102D }, // သင်္ချိ
+                    "\u101E\u1004\u103A\u1039\u1001\u103B\u102D"),
+            Pair.create(new int[] { 0x102F }, // သင်္ချို
+                    "\u101E\u1004\u103A\u1039\u1001\u103B\u102D\u102F"),
+            Pair.create(new int[] { 0x1004 }, // သင်္ချိုင
+                    "\u101E\u1004\u103A\u1039\u1001\u103B\u102D\u102F\u1004"),
+            Pair.create(new int[] { 0x103A }, // သင်္ချိုင်
+                    "\u101E\u1004\u103A\u1039\u1001\u103B\u102D\u102F\u1004\u103A"),
+            Pair.create(new int[] { 0x1038 }, // သင်္ချိုင်း
+                    "\u101E\u1004\u103A\u1039\u1001\u103B\u102D\u102F\u1004\u103A\u1038")
+        },
+        */
+    };
+
+    private void doMyanmarTest(final int testNumber, final Pair[] test) {
+        int stepNumber = 0;
+        for (final Pair<int[], String> step : test) {
+            ++stepNumber;
+            final int[] input = step.first;
+            final String expectedResult = step.second;
+            if (input.length > 1) {
+                mLatinIME.onTextInput(new String(input, 0, input.length));
+            } else {
+                type(input[0]);
+            }
+            assertEquals("Myanmar reordering test " + testNumber + ", step " + stepNumber,
+                    expectedResult, mEditText.getText().toString());
+        }
+    }
+
+    public void testMyanmarReordering() {
+        int testNumber = 0;
+        changeLanguage("mm_MY");
+        for (final Pair[] test : TESTS) {
+            // Small trick to reset LatinIME : setText("") and send updateSelection with values
+            // LatinIME has never seen, and cursor pos 0,0.
+            mEditText.setText("");
+            mLatinIME.onUpdateSelection(1, 1, 0, 0, -1, -1);
+            doMyanmarTest(++testNumber, test);
+        }
+    }
+}
diff --git a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java
index b68df1c..47f781e 100644
--- a/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java
+++ b/tools/dicttool/compat/com/android/inputmethod/event/CombinerChain.java
@@ -20,6 +20,13 @@
 
 import java.util.ArrayList;
 
+/**
+ * Compatibility class that stands in for the combiner chain in LatinIME.
+ *
+ * This is not used by dicttool, it's just needed by the dependency chain.
+ */
+// TODO: there should not be a dependency to this in dicttool, so there
+// should be a sensible way to separate them cleanly.
 public class CombinerChain {
     private StringBuilder mComposingWord = new StringBuilder();
     public CombinerChain(final Combiner... combinerList) {}
@@ -35,4 +42,9 @@
     public void reset() {
         mComposingWord.setLength(0);
     }
+
+    public static Combiner[] createCombiners(final String spec) {
+        // Dicttool never uses a combiner at all, so we just return a zero-sized array.
+        return new Combiner[0];
+    }
 }