Merge "[IL135] Make getCurrentAutoCapsState private"
diff --git a/java/res/color/emoji_tab_label_color_gb.xml b/java/res/color/emoji_tab_label_color_gb.xml
deleted file mode 100644
index e1d2f71..0000000
--- a/java/res/color/emoji_tab_label_color_gb.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2013, 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_focused="true"
-        android:color="@color/key_text_color_gb" />
-    <item
-        android:state_pressed="true"
-        android:color="@color/key_text_color_gb" />
-    <item
-        android:state_selected="true"
-        android:color="@color/key_text_color_gb" />
-    <item
-        android:color="@color/key_text_inactivated_color_gb" />
-</selector>
diff --git a/java/res/drawable-hdpi/keyboard_background_gb.9.png b/java/res/drawable-hdpi/keyboard_background_gb.9.png
deleted file mode 100644
index fa3d449..0000000
--- a/java/res/drawable-hdpi/keyboard_background_gb.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_popup_panel_background_gb.9.png b/java/res/drawable-hdpi/keyboard_popup_panel_background_gb.9.png
deleted file mode 100644
index baff809..0000000
--- a/java/res/drawable-hdpi/keyboard_popup_panel_background_gb.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_suggest_strip_gb.9.png b/java/res/drawable-hdpi/keyboard_suggest_strip_gb.9.png
deleted file mode 100644
index 7cab5a8..0000000
--- a/java/res/drawable-hdpi/keyboard_suggest_strip_gb.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_space_led_gb.9.png b/java/res/drawable-hdpi/sym_keyboard_space_led_gb.9.png
deleted file mode 100644
index c76f64b..0000000
--- a/java/res/drawable-hdpi/sym_keyboard_space_led_gb.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_background_gb.9.png b/java/res/drawable-mdpi/keyboard_background_gb.9.png
deleted file mode 100644
index 4f81704..0000000
--- a/java/res/drawable-mdpi/keyboard_background_gb.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_popup_panel_background_gb.9.png b/java/res/drawable-mdpi/keyboard_popup_panel_background_gb.9.png
deleted file mode 100644
index 0d9ab97..0000000
--- a/java/res/drawable-mdpi/keyboard_popup_panel_background_gb.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_suggest_strip_gb.9.png b/java/res/drawable-mdpi/keyboard_suggest_strip_gb.9.png
deleted file mode 100644
index fa6c0fe..0000000
--- a/java/res/drawable-mdpi/keyboard_suggest_strip_gb.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_space_led_gb.9.png b/java/res/drawable-mdpi/sym_keyboard_space_led_gb.9.png
deleted file mode 100644
index 1c1ca2c..0000000
--- a/java/res/drawable-mdpi/sym_keyboard_space_led_gb.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_background_gb.9.png b/java/res/drawable-xhdpi/keyboard_background_gb.9.png
deleted file mode 100644
index 27b7a10..0000000
--- a/java/res/drawable-xhdpi/keyboard_background_gb.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_popup_panel_background_gb.9.png b/java/res/drawable-xhdpi/keyboard_popup_panel_background_gb.9.png
deleted file mode 100644
index 79f7ab0..0000000
--- a/java/res/drawable-xhdpi/keyboard_popup_panel_background_gb.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/keyboard_suggest_strip_gb.9.png b/java/res/drawable-xhdpi/keyboard_suggest_strip_gb.9.png
deleted file mode 100644
index 1b568df..0000000
--- a/java/res/drawable-xhdpi/keyboard_suggest_strip_gb.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-xhdpi/sym_keyboard_space_led_gb.9.png b/java/res/drawable-xhdpi/sym_keyboard_space_led_gb.9.png
deleted file mode 100644
index 6525fef..0000000
--- a/java/res/drawable-xhdpi/sym_keyboard_space_led_gb.9.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable/btn_keyboard_key_functional_gb.xml b/java/res/drawable/btn_keyboard_key_functional_gb.xml
deleted file mode 100644
index 431359c..0000000
--- a/java/res/drawable/btn_keyboard_key_functional_gb.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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" />
-    <item android:drawable="@drawable/btn_keyboard_key_dark_normal" />
-</selector>
diff --git a/java/res/drawable/btn_keyboard_key_gb.xml b/java/res/drawable/btn_keyboard_key_gb.xml
deleted file mode 100644
index 3fc253e..0000000
--- a/java/res/drawable/btn_keyboard_key_gb.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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" />
-    <item android:state_single="true"
-          android:drawable="@drawable/btn_keyboard_key_dark_normal" />
-
-    <!-- Action keys. -->
-    <item android:state_active="true" android:state_pressed="true"
-          android:drawable="@drawable/btn_keyboard_key_dark_pressed" />
-    <item android:state_active="true"
-          android:drawable="@drawable/btn_keyboard_key_dark_normal" />
-
-    <!-- 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" />
-    <item android:state_checkable="true" android:state_pressed="true"
-          android:drawable="@drawable/btn_keyboard_key_dark_pressed_off" />
-    <item android:state_checkable="true" android:state_checked="true"
-          android:drawable="@drawable/btn_keyboard_key_dark_normal_on" />
-    <item android:state_checkable="true"
-          android:drawable="@drawable/btn_keyboard_key_dark_normal_off" />
-
-    <!-- Empty background keys. -->
-    <item android:state_empty="true"
-          android:drawable="@drawable/transparent" />
-
-    <!-- Normal keys. -->
-    <item android:state_pressed="true"
-          android:drawable="@drawable/btn_keyboard_key_light_pressed" />
-    <item android:drawable="@drawable/btn_keyboard_key_light_normal" />
-</selector>
diff --git a/java/res/drawable/btn_keyboard_key_popup_gb.xml b/java/res/drawable/btn_keyboard_key_popup_gb.xml
deleted file mode 100644
index 9e3670d..0000000
--- a/java/res/drawable/btn_keyboard_key_popup_gb.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_pressed="true"
-          android:drawable="@drawable/btn_keyboard_key_light_popup_selected" />
-    <item android:drawable="@drawable/transparent" />
-</selector>
diff --git a/java/res/drawable/btn_keyboard_spacebar_gb.xml b/java/res/drawable/btn_keyboard_spacebar_gb.xml
deleted file mode 100644
index 4d51f3c..0000000
--- a/java/res/drawable/btn_keyboard_spacebar_gb.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 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" />
-    <item android:drawable="@drawable/btn_keyboard_key_light_normal" />
-</selector>
diff --git a/java/res/drawable/btn_suggestion_gb.xml b/java/res/drawable/btn_suggestion_gb.xml
deleted file mode 100644
index cde12fe..0000000
--- a/java/res/drawable/btn_suggestion_gb.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<selector
-    xmlns:android="http://schemas.android.com/apk/res/android"
->
-    <item
-        android:state_pressed="true"
-        android:drawable="@drawable/btn_suggestion_pressed" />
-</selector>
diff --git a/java/res/drawable/keyboard_key_feedback_gb.xml b/java/res/drawable/keyboard_key_feedback_gb.xml
deleted file mode 100644
index 397e948..0000000
--- a/java/res/drawable/keyboard_key_feedback_gb.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 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"
->
-    <item latin:state_has_morekeys="true"
-          android:drawable="@drawable/keyboard_key_feedback_more_background" />
-    <item android:drawable="@drawable/keyboard_key_feedback_background" />
-</selector>
diff --git a/java/res/values-land/config.xml b/java/res/values-land/config.xml
index ade7d00..43ae068 100644
--- a/java/res/values-land/config.xml
+++ b/java/res/values-land/config.xml
@@ -33,14 +33,6 @@
     <!-- config_more_keys_keyboard_key_height x 1.2 -->
     <dimen name="config_more_keys_keyboard_slide_allowance">53.76dp</dimen>
 
-    <fraction name="config_keyboard_top_padding_gb">1.818%p</fraction>
-    <fraction name="config_keyboard_bottom_padding_gb">0.0%p</fraction>
-    <fraction name="config_key_vertical_gap_gb">5.941%p</fraction>
-    <fraction name="config_key_horizontal_gap_gb">0.997%p</fraction>
-    <!-- config_more_keys_keyboard_key_height x -1.0 -->
-    <dimen name="config_more_keys_keyboard_vertical_correction_gb">-44.8dp</dimen>
-    <dimen name="config_key_preview_offset_gb">0.0dp</dimen>
-
     <fraction name="config_keyboard_top_padding_holo">2.727%p</fraction>
     <fraction name="config_keyboard_bottom_padding_holo">0.0%p</fraction>
     <fraction name="config_key_vertical_gap_holo">5.368%p</fraction>
diff --git a/java/res/values-sw600dp-land/config.xml b/java/res/values-sw600dp-land/config.xml
index bd123c4..00edde1 100644
--- a/java/res/values-sw600dp-land/config.xml
+++ b/java/res/values-sw600dp-land/config.xml
@@ -27,11 +27,6 @@
 
     <dimen name="config_more_keys_keyboard_key_height">81.9dp</dimen>
 
-    <fraction name="config_keyboard_top_padding_gb">2.444%p</fraction>
-    <fraction name="config_keyboard_bottom_padding_gb">0.0%p</fraction>
-    <fraction name="config_key_vertical_gap_gb">5.200%p</fraction>
-    <fraction name="config_key_horizontal_gap_gb">1.447%p</fraction>
-
     <fraction name="config_keyboard_top_padding_holo">2.727%p</fraction>
     <fraction name="config_keyboard_bottom_padding_holo">0.0%p</fraction>
     <fraction name="config_key_vertical_gap_holo">4.5%p</fraction>
diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw600dp/config.xml
index 700350c..3bd8439 100644
--- a/java/res/values-sw600dp/config.xml
+++ b/java/res/values-sw600dp/config.xml
@@ -34,14 +34,6 @@
     <!-- config_more_keys_keyboard_key_height x 1.2 -->
     <dimen name="config_more_keys_keyboard_slide_allowance">98.3dp</dimen>
 
-    <fraction name="config_keyboard_top_padding_gb">2.291%p</fraction>
-    <fraction name="config_keyboard_bottom_padding_gb">0.0%p</fraction>
-    <fraction name="config_key_vertical_gap_gb">4.625%p</fraction>
-    <fraction name="config_key_horizontal_gap_gb">2.113%p</fraction>
-    <!-- config_more_keys_keyboard_key_height x -1.0 -->
-    <dimen name="config_more_keys_keyboard_vertical_correction_gb">-81.9dp</dimen>
-    <dimen name="config_key_preview_offset_gb">16.0dp</dimen>
-
     <fraction name="config_keyboard_top_padding_holo">2.335%p</fraction>
     <fraction name="config_keyboard_bottom_padding_holo">4.0%p</fraction>
     <fraction name="config_key_vertical_gap_holo">4.5%p</fraction>
diff --git a/java/res/values-sw600dp/touch-position-correction.xml b/java/res/values-sw600dp/touch-position-correction.xml
index 932b8fc..6aaa605 100644
--- a/java/res/values-sw600dp/touch-position-correction.xml
+++ b/java/res/values-sw600dp/touch-position-correction.xml
@@ -37,17 +37,6 @@
     </string-array>
 
     <string-array
-        name="touch_position_correction_data_gb"
-        translatable="false"
-    >
-        <!-- The default touch position data (See com.android.inputmethod.keyboard.ProximityInfo)
-             correctionX = 0.0f
-             correctionY = 0.0f
-             correctionR = DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS
-        -->
-    </string-array>
-
-    <string-array
         name="touch_position_correction_data_holo"
         translatable="false"
     >
diff --git a/java/res/values-sw768dp-land/config.xml b/java/res/values-sw768dp-land/config.xml
index 4040e29..3878a9e 100644
--- a/java/res/values-sw768dp-land/config.xml
+++ b/java/res/values-sw768dp-land/config.xml
@@ -25,11 +25,6 @@
     <dimen name="config_default_keyboard_height">365.4dp</dimen>
     <fraction name="config_min_keyboard_height">45%p</fraction>
 
-    <fraction name="config_keyboard_top_padding_gb">1.896%p</fraction>
-    <fraction name="config_keyboard_bottom_padding_gb">0.0%p</fraction>
-    <fraction name="config_key_vertical_gap_gb">3.896%p</fraction>
-    <fraction name="config_key_horizontal_gap_gb">1.195%p</fraction>
-
     <fraction name="config_keyboard_top_padding_holo">1.896%p</fraction>
     <fraction name="config_keyboard_bottom_padding_holo">0.0%p</fraction>
     <fraction name="config_key_vertical_gap_holo">3.690%p</fraction>
diff --git a/java/res/values-sw768dp/config.xml b/java/res/values-sw768dp/config.xml
index 33286c6..34eec38 100644
--- a/java/res/values-sw768dp/config.xml
+++ b/java/res/values-sw768dp/config.xml
@@ -26,14 +26,6 @@
     <fraction name="config_max_keyboard_height">46%p</fraction>
     <fraction name="config_min_keyboard_height">-35.0%p</fraction>
 
-    <fraction name="config_keyboard_top_padding_gb">2.291%p</fraction>
-    <fraction name="config_keyboard_bottom_padding_gb">0.0%p</fraction>
-    <fraction name="config_key_vertical_gap_gb">4.687%p</fraction>
-    <fraction name="config_key_horizontal_gap_gb">1.272%p</fraction>
-    <!-- config_more_keys_keyboard_key_height x -1.0 -->
-    <dimen name="config_more_keys_keyboard_vertical_correction_gb">-81.9dp</dimen>
-    <dimen name="config_key_preview_offset_gb">16.0dp</dimen>
-
     <fraction name="config_keyboard_top_padding_holo">2.335%p</fraction>
     <fraction name="config_keyboard_bottom_padding_holo">0.0%p</fraction>
     <fraction name="config_key_vertical_gap_holo">3.312%p</fraction>
diff --git a/java/res/values/colors.xml b/java/res/values/colors.xml
index 5171744..824928c 100644
--- a/java/res/values/colors.xml
+++ b/java/res/values/colors.xml
@@ -19,20 +19,6 @@
 -->
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
-    <!-- Color resources for Gingerbread theme. -->
-    <color name="highlight_color_gb">#FFFCAE00</color>
-    <color name="typed_word_color_gb">@android:color/white</color>
-    <color name="highlight_translucent_color_gb">#99FCAE00</color>
-    <color name="key_text_color_gb">@android:color/white</color>
-    <color name="key_text_shadow_color_gb">#BB000000</color>
-    <color name="key_text_inactivated_color_gb">#66E0E4E5</color>
-    <color name="key_hint_letter_color_gb">#80000000</color>
-    <color name="key_hint_label_color_gb">#E0E0E4E5</color>
-    <color name="key_shifted_letter_hint_inactivated_color_gb">#66E0E4E5</color>
-    <color name="key_shifted_letter_hint_activated_color_gb">#CCE0E4E5</color>
-    <color name="spacebar_text_color_gb">#FFC0C0C0</color>
-    <color name="spacebar_text_shadow_color_gb">#80000000</color>
-    <color name="gesture_floating_preview_color_gb">#C0000000</color>
     <!-- Color resources for IceCreamSandwich theme. Base color = 33B5E5 -->
     <!-- android:color/holo_blue_light value is #FF33B5E5 -->
     <color name="highlight_color_ics">#FF33B5E5</color>
diff --git a/java/res/values/config-common.xml b/java/res/values/config-common.xml
index 20d5860..3fe4b94 100644
--- a/java/res/values/config-common.xml
+++ b/java/res/values/config-common.xml
@@ -24,8 +24,8 @@
          at input history to suggest a hopefully helpful suggestions for the next word? -->
     <bool name="config_default_next_word_prediction">true</bool>
 
-    <!-- This configuration is an index of  {@link KeyboardSwitcher#KEYBOARD_THEMES[]}. -->
-    <string name="config_default_keyboard_theme_index" translatable="false">2</string>
+    <!-- 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 e64b4b1..45ea483 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -36,14 +36,6 @@
     <dimen name="config_more_keys_keyboard_slide_allowance">63.36dp</dimen>
     <dimen name="config_more_keys_keyboard_key_horizontal_padding">8dp</dimen>
 
-    <fraction name="config_keyboard_top_padding_gb">1.556%p</fraction>
-    <fraction name="config_keyboard_bottom_padding_gb">4.669%p</fraction>
-    <fraction name="config_key_vertical_gap_gb">6.495%p</fraction>
-    <fraction name="config_key_horizontal_gap_gb">1.971%p</fraction>
-    <!-- config_more_keys_keyboard_key_height x -1.0 -->
-    <dimen name="config_more_keys_keyboard_vertical_correction_gb">-52.8dp</dimen>
-    <dimen name="config_key_preview_offset_gb">-8.0dp</dimen>
-
     <fraction name="config_keyboard_top_padding_holo">2.335%p</fraction>
     <fraction name="config_keyboard_bottom_padding_holo">4.669%p</fraction>
     <fraction name="config_key_vertical_gap_holo">6.127%p</fraction>
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index 4be5863..9a610a0 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -47,31 +47,13 @@
     <string name="prefs_debug_mode">Debug Mode</string>
     <string name="prefs_force_non_distinct_multitouch">Force non-distinct multitouch</string>
 
-    <!-- Keyboard theme names -->
-    <string name="layout_gingerbread">Gingerbread</string>
-    <string name="layout_ics">IceCreamSandwich</string>
-    <string name="layout_klp">KeyLimePie</string>
-
-    <!-- For keyboard theme switcher dialog -->
-    <string-array name="keyboard_layout_modes">
-        <item>@string/layout_ics</item>
-        <item>@string/layout_gingerbread</item>
-        <item>@string/layout_klp</item>
-    </string-array>
-    <!-- An element must be an index of {@link KeyboardSwitcher#KEYBOARD_THEMES[]}. -->
-    <string-array name="keyboard_layout_modes_values">
-        <item>0</item>
-        <item>1</item>
-        <item>2</item>
-    </string-array>
-
     <!-- For keyboard color scheme option dialog. -->
-    <string-array name="keyboard_color_schemes">
+    <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 an index of {@link KeyboardSwitcher#KEYBOARD_THEMES[]}. -->
-    <string-array name="keyboard_color_schemes_values">
+    <!-- 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>
diff --git a/java/res/values/themes-gb.xml b/java/res/values/themes-gb.xml
deleted file mode 100644
index c189da3..0000000
--- a/java/res/values/themes-gb.xml
+++ /dev/null
@@ -1,150 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2011, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<resources>
-    <style name="KeyboardTheme.GB" parent="KeyboardIcons.GB">
-        <item name="keyboardStyle">@style/Keyboard.GB</item>
-        <item name="keyboardViewStyle">@style/KeyboardView.GB</item>
-        <item name="mainKeyboardViewStyle">@style/MainKeyboardView.GB</item>
-        <item name="keyPreviewTextViewStyle">@style/KeyPreviewTextView.GB</item>
-        <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.GB</item>
-        <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.GB</item>
-        <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.GB</item>
-        <item name="suggestionStripViewStyle">@style/SuggestionStripView.GB</item>
-        <item name="suggestionWordStyle">@style/SuggestionWord.GB</item>
-    </style>
-    <style name="KeyboardIcons.GB">
-        <!-- 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_mic_holo_dark</item>
-        <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space</item>
-        <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_holo_dark</item>
-        <!-- TODO: Needs non-holo disabled shortcut icon drawable -->
-        <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>
-        <!-- TODO: Needs dedicated black theme ZWNJ and ZWJ icons -->
-        <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>
-    <style
-        name="Keyboard.GB"
-        parent="Keyboard"
-    >
-        <!-- This should be aligned with KeyboardSwitcher.KEYBOARD_THEMES[] -->
-        <item name="themeId">1</item>
-        <item name="touchPositionCorrectionData">@array/touch_position_correction_data_gb</item>
-        <item name="keyboardTopPadding">@fraction/config_keyboard_top_padding_gb</item>
-        <item name="keyboardBottomPadding">@fraction/config_keyboard_bottom_padding_gb</item>
-        <item name="horizontalGap">@fraction/config_key_horizontal_gap_gb</item>
-        <item name="verticalGap">@fraction/config_key_vertical_gap_gb</item>
-    </style>
-    <style
-        name="KeyboardView.GB"
-        parent="KeyboardView"
-    >
-        <item name="android:background">@drawable/keyboard_background_gb</item>
-        <item name="keyBackground">@drawable/btn_keyboard_key_gb</item>
-        <item name="keyTypeface">bold</item>
-        <item name="keyTextColor">@color/key_text_color_gb</item>
-        <item name="keyTextInactivatedColor">@color/key_text_inactivated_color_gb</item>
-        <item name="keyHintLetterColor">@color/key_hint_letter_color_gb</item>
-        <item name="keyHintLabelColor">@color/key_hint_label_color_gb</item>
-        <item name="keyShiftedLetterHintInactivatedColor">@color/key_shifted_letter_hint_inactivated_color_gb</item>
-        <item name="keyShiftedLetterHintActivatedColor">@color/key_shifted_letter_hint_activated_color_gb</item>
-        <item name="keyPreviewTextColor">@color/key_text_color_gb</item>
-        <item name="keyTextShadowColor">@color/key_text_shadow_color_gb</item>
-        <item name="keyTextShadowRadius">2.75</item>
-    </style>
-    <style
-        name="MainKeyboardView.GB"
-        parent="KeyboardView.GB"
-    >
-        <item name="keyPreviewOffset">@dimen/config_key_preview_offset_gb</item>
-        <item name="gestureFloatingPreviewTextColor">@color/highlight_color_gb</item>
-        <item name="gestureFloatingPreviewColor">@color/gesture_floating_preview_color_gb</item>
-        <item name="gestureTrailColor">@color/highlight_color_gb</item>
-        <item name="slidingKeyInputPreviewColor">@color/highlight_translucent_color_gb</item>
-        <item name="autoCorrectionSpacebarLedEnabled">true</item>
-        <item name="autoCorrectionSpacebarLedIcon">@drawable/sym_keyboard_space_led_gb</item>
-        <item name="languageOnSpacebarTextColor">@color/spacebar_text_color_gb</item>
-        <item name="languageOnSpacebarTextShadowColor">@color/spacebar_text_shadow_color_gb</item>
-        <item name="spacebarBackground">@drawable/btn_keyboard_spacebar_gb</item>
-    </style>
-    <style
-        name="KeyPreviewTextView.GB"
-        parent="KeyPreviewTextView"
-    >
-        <item name="android:background">@drawable/keyboard_key_feedback_gb</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.GB"
-        parent="KeyboardView.GB"
-    >
-        <item name="keyBackground">@drawable/btn_keyboard_key_functional_gb</item>
-        <item name="emojiTabLabelColor">@color/emoji_tab_label_color_gb</item>
-    </style>
-    <style
-        name="MoreKeysKeyboard.GB"
-        parent="Keyboard.GB"
-    >
-        <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.GB"
-        parent="KeyboardView.GB"
-    >
-        <item name="android:background">@drawable/keyboard_popup_panel_background_gb</item>
-        <item name="keyBackground">@drawable/btn_keyboard_key_popup_gb</item>
-        <item name="keyTypeface">normal</item>
-        <item name="verticalCorrection">@dimen/config_more_keys_keyboard_vertical_correction_gb</item>
-    </style>
-    <style
-        name="SuggestionStripView.GB"
-        parent="SuggestionStripView"
-    >
-        <item name="android:background">@drawable/keyboard_suggest_strip_gb</item>
-        <item name="suggestionStripOptions">autoCorrectBold|validTypedWordBold</item>
-        <item name="colorValidTypedWord">@color/highlight_color_gb</item>
-        <item name="colorTypedWord">@color/typed_word_color_gb</item>
-        <item name="colorAutoCorrect">@color/highlight_color_gb</item>
-        <item name="colorSuggested">@color/highlight_color_gb</item>
-        <item name="alphaObsoleted">50%</item>
-    </style>
-    <style
-        name="SuggestionWord.GB"
-        parent="SuggestionWord"
-    >
-        <item name="android:background">@drawable/btn_suggestion_gb</item>
-        <item name="android:textColor">@color/highlight_color_gb</item>
-    </style>
-</resources>
diff --git a/java/res/values/touch-position-correction.xml b/java/res/values/touch-position-correction.xml
index becec0e..e090d10 100644
--- a/java/res/values/touch-position-correction.xml
+++ b/java/res/values/touch-position-correction.xml
@@ -37,26 +37,6 @@
     </string-array>
 
     <string-array
-        name="touch_position_correction_data_gb"
-        translatable="false"
-    >
-        <!-- First row -->
-        <item>0.0091285</item>
-        <item>0.1193203</item>
-        <item>0.1622607</item>
-
-        <!-- Second row -->
-        <item>-0.0233128</item>
-        <item>0.1379798</item>
-        <item>0.1585229</item>
-
-        <!-- Third row -->
-        <item>-0.0080185</item>
-        <item>0.1911477</item>
-        <item>0.1570948</item>
-    </string-array>
-
-    <string-array
         name="touch_position_correction_data_holo"
         translatable="false"
     >
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index a39ce4a..3e3bedf 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -168,9 +168,9 @@
                 android:key="pref_keyboard_layout_20110916"
                 android:title="@string/keyboard_color_scheme"
                 android:persistent="true"
-                android:entryValues="@array/keyboard_color_schemes_values"
-                android:entries="@array/keyboard_color_schemes"
-                android:defaultValue="@string/config_default_keyboard_theme_index" />
+                android:entryValues="@array/keyboard_theme_ids"
+                android:entries="@array/keyboard_theme_names"
+                android:defaultValue="@string/config_default_keyboard_theme_id" />
             <PreferenceScreen
                 android:fragment="com.android.inputmethod.latin.settings.AdditionalSubtypeSettings"
                 android:key="custom_input_styles"
diff --git a/java/res/xml/prefs_for_debug.xml b/java/res/xml/prefs_for_debug.xml
index 7b2b8ea..bb6a641 100644
--- a/java/res/xml/prefs_for_debug.xml
+++ b/java/res/xml/prefs_for_debug.xml
@@ -26,14 +26,6 @@
         android:summary="@string/prefs_description_log"
         android:persistent="true"
         android:defaultValue="false" />
-    <ListPreference
-        android:key="pref_keyboard_layout_20110916"
-        android:title="@string/keyboard_layout"
-        android:summary="%s"
-        android:persistent="true"
-        android:entryValues="@array/keyboard_layout_modes_values"
-        android:entries="@array/keyboard_layout_modes"
-        android:defaultValue="@string/config_default_keyboard_theme_index" />
     <CheckBoxPreference
         android:key="debug_mode"
         android:title="@string/prefs_debug_mode"
diff --git a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java
index 89e623a..bef4d85 100644
--- a/java/src/com/android/inputmethod/event/DeadKeyCombiner.java
+++ b/java/src/com/android/inputmethod/event/DeadKeyCombiner.java
@@ -52,12 +52,16 @@
                 // how dead keys work).
                 // If the event is a space, we should commit the dead char alone, but if it's
                 // not, we need to commit both.
+                // TODO: this is not necessarily triggered by hardware key events, so it's not
+                // a good idea to masquerade as one. This should be typed as a software
+                // composite event or something.
                 return Event.createHardwareKeypressEvent(deadCodePoint, event.mKeyCode,
-                        Constants.CODE_SPACE == event.mCodePoint ? null : event /* next */);
+                        Constants.CODE_SPACE == event.mCodePoint ? null : event /* next */,
+                        false /* isKeyRepeat */);
             } else {
                 // We could combine the characters.
                 return Event.createHardwareKeypressEvent(resultingCodePoint, event.mKeyCode,
-                        null /* next */);
+                        null /* next */, false /* isKeyRepeat */);
             }
         }
     }
diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java
index 6535d2d..4a9163c 100644
--- a/java/src/com/android/inputmethod/event/Event.java
+++ b/java/src/com/android/inputmethod/event/Event.java
@@ -65,6 +65,8 @@
     // This event is a dead character, usually input by a dead key. Examples include dead-acute
     // or dead-abovering.
     final private static int FLAG_DEAD = 0x1;
+    // This event is coming from a key repeat, software or hardware.
+    final private static int FLAG_REPEAT = 0x2;
 
     final private int mEventType; // The type of event - one of the constants above
     // The code point associated with the event, if relevant. This is a unicode code point, and
@@ -130,16 +132,16 @@
     }
 
     public static Event createSoftwareKeypressEvent(final int codePoint, final int keyCode,
-            final int x, final int y) {
+            final int x, final int y, final boolean isKeyRepeat) {
         return new Event(EVENT_TYPE_INPUT_KEYPRESS, null /* text */, codePoint, keyCode, x, y,
-                null /* suggestedWordInfo */, FLAG_NONE, null /* next */);
+                null /* suggestedWordInfo */, isKeyRepeat ? FLAG_REPEAT : FLAG_NONE, null);
     }
 
     public static Event createHardwareKeypressEvent(final int codePoint, final int keyCode,
-            final Event next) {
+            final Event next, final boolean isKeyRepeat) {
         return new Event(EVENT_TYPE_INPUT_KEYPRESS, null /* text */, codePoint, keyCode,
                 Constants.EXTERNAL_KEYBOARD_COORDINATE, Constants.EXTERNAL_KEYBOARD_COORDINATE,
-                null /* suggestedWordInfo */, FLAG_NONE, next);
+                null /* suggestedWordInfo */, isKeyRepeat ? FLAG_REPEAT : FLAG_NONE, next);
     }
 
     // This creates an input event for a dead character. @see {@link #FLAG_DEAD}
@@ -228,6 +230,10 @@
         return 0 != (FLAG_DEAD & mFlags);
     }
 
+    public boolean isKeyRepeat() {
+        return 0 != (FLAG_REPEAT & mFlags);
+    }
+
     // Returns whether this is a fake key press from the suggestion strip. This happens with
     // punctuation signs selected from the suggestion strip.
     public boolean isSuggestionStripPress() {
diff --git a/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java b/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java
index da6780e..05ba999 100644
--- a/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java
+++ b/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java
@@ -46,9 +46,10 @@
         // do not necessarily map to a unicode character. This represents a physical key, like
         // the key for 'A' or Space, but also Backspace or Ctrl or Caps Lock.
         final int keyCode = keyEvent.getKeyCode();
+        final boolean isKeyRepeat = (0 != keyEvent.getRepeatCount());
         if (KeyEvent.KEYCODE_DEL == keyCode) {
             return Event.createHardwareKeypressEvent(Event.NOT_A_CODE_POINT, Constants.CODE_DELETE,
-                    null /* next */);
+                    null /* next */, isKeyRepeat);
         }
         if (keyEvent.isPrintingKey() || KeyEvent.KEYCODE_SPACE == keyCode
                 || KeyEvent.KEYCODE_ENTER == keyCode) {
@@ -65,15 +66,16 @@
                 // Latin IME decide what to do with it.
                 if (keyEvent.isShiftPressed()) {
                     return Event.createHardwareKeypressEvent(Event.NOT_A_CODE_POINT,
-                            Constants.CODE_SHIFT_ENTER, null /* next */);
+                            Constants.CODE_SHIFT_ENTER, null /* next */, isKeyRepeat);
                 } else {
                     return Event.createHardwareKeypressEvent(Constants.CODE_ENTER, keyCode,
-                            null /* next */);
+                            null /* next */, isKeyRepeat);
                 }
             }
             // If not Enter, then this is just a regular keypress event for a normal character
             // that can be committed right away, taking into account the current state.
-            return Event.createHardwareKeypressEvent(keyCode, codePointAndFlags, null /* next */);
+            return Event.createHardwareKeypressEvent(keyCode, codePointAndFlags, null /* next */,
+                    isKeyRepeat);
         }
         return Event.createNotHandledEvent();
     }
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
index 4edc616..8822cce 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
@@ -606,7 +606,8 @@
             return;
         }
         final int code = (Integer) tag;
-        mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE);
+        mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE,
+                false /* isKeyRepeat */);
         mKeyboardActionListener.onReleaseKey(code, false /* withSliding */);
     }
 
@@ -634,7 +635,8 @@
         if (code == Constants.CODE_OUTPUT_TEXT) {
             mKeyboardActionListener.onTextInput(key.getOutputText());
         } else {
-            mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE);
+            mKeyboardActionListener.onCodeInput(code, NOT_A_COORDINATE, NOT_A_COORDINATE,
+                    false /* isKeyRepeat */);
         }
         mKeyboardActionListener.onReleaseKey(code, false /* withSliding */);
     }
@@ -901,8 +903,8 @@
         }
 
         private void handleKeyUp() {
-            mKeyboardActionListener.onCodeInput(
-                    Constants.CODE_DELETE, NOT_A_COORDINATE, NOT_A_COORDINATE);
+            mKeyboardActionListener.onCodeInput(Constants.CODE_DELETE,
+                    NOT_A_COORDINATE, NOT_A_COORDINATE, false /* isKeyRepeat */);
             mKeyboardActionListener.onReleaseKey(
                     Constants.CODE_DELETE, false /* withSliding */);
             ++mRepeatCount;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
index dc760e6..c565866 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
@@ -53,8 +53,10 @@
      *            {@link PointerTracker} or so, the value should be
      *            {@link Constants#NOT_A_COORDINATE}.If it's called on insertion from the
      *            suggestion strip, it should be {@link Constants#SUGGESTION_STRIP_COORDINATE}.
+     * @param isKeyRepeat true if this is a key repeat, false otherwise
      */
-    public void onCodeInput(int primaryCode, int x, int y);
+    // TODO: change this to send an Event object instead
+    public void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat);
 
     /**
      * Sends a string of characters to the listener.
@@ -107,7 +109,7 @@
         @Override
         public void onReleaseKey(int primaryCode, boolean withSliding) {}
         @Override
-        public void onCodeInput(int primaryCode, int x, int y) {}
+        public void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat) {}
         @Override
         public void onTextInput(String text) {}
         @Override
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 6f93d82..dcf7f74 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -38,35 +38,12 @@
 import com.android.inputmethod.latin.RichInputMethodManager;
 import com.android.inputmethod.latin.SubtypeSwitcher;
 import com.android.inputmethod.latin.WordComposer;
-import com.android.inputmethod.latin.settings.Settings;
 import com.android.inputmethod.latin.settings.SettingsValues;
 import com.android.inputmethod.latin.utils.ResourceUtils;
 
 public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
     private static final String TAG = KeyboardSwitcher.class.getSimpleName();
 
-    public static final class KeyboardTheme {
-        public final int mThemeId;
-        public final int mStyleId;
-
-        // Note: The themeId should be aligned with "themeId" attribute of Keyboard style
-        // in values/style.xml.
-        public KeyboardTheme(final int themeId, final int styleId) {
-            mThemeId = themeId;
-            mStyleId = styleId;
-        }
-    }
-
-    public static final int THEME_INDEX_ICS = 0;
-    public static final int THEME_INDEX_GB = 1;
-    public static final int THEME_INDEX_KLP = 2;
-    public static final int DEFAULT_THEME_INDEX = THEME_INDEX_KLP;
-    public static final KeyboardTheme[] KEYBOARD_THEMES = {
-        new KeyboardTheme(THEME_INDEX_ICS, R.style.KeyboardTheme_ICS),
-        new KeyboardTheme(THEME_INDEX_GB, R.style.KeyboardTheme_GB),
-        new KeyboardTheme(THEME_INDEX_KLP, R.style.KeyboardTheme_KLP),
-    };
-
     private SubtypeSwitcher mSubtypeSwitcher;
     private SharedPreferences mPrefs;
 
@@ -88,7 +65,7 @@
      * what user actually typed. */
     private boolean mIsAutoCorrectionActive;
 
-    private KeyboardTheme mKeyboardTheme = KEYBOARD_THEMES[DEFAULT_THEME_INDEX];
+    private KeyboardTheme mKeyboardTheme = KeyboardTheme.getDefaultKeyboardTheme();
     private Context mThemeContext;
 
     private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
@@ -117,25 +94,12 @@
 
     public void updateKeyboardTheme() {
         final boolean themeUpdated = updateKeyboardThemeAndContextThemeWrapper(
-                mLatinIME, getKeyboardTheme(mLatinIME, mPrefs));
+                mLatinIME, KeyboardTheme.getKeyboardTheme(mPrefs));
         if (themeUpdated && mKeyboardView != null) {
             mLatinIME.setInputView(onCreateInputView(mIsHardwareAcceleratedDrawingEnabled));
         }
     }
 
-    private static KeyboardTheme getKeyboardTheme(final Context context,
-            final SharedPreferences prefs) {
-        final Resources res = context.getResources();
-        final int index = Settings.readKeyboardThemeIndex(prefs, res);
-        if (index >= 0 && index < KEYBOARD_THEMES.length) {
-            return KEYBOARD_THEMES[index];
-        }
-        final int defaultThemeIndex = Settings.resetAndGetDefaultKeyboardThemeIndex(prefs, res);
-        Log.w(TAG, "Illegal keyboard theme in preference: " + index + ", default to "
-                + defaultThemeIndex);
-        return KEYBOARD_THEMES[defaultThemeIndex];
-    }
-
     private boolean updateKeyboardThemeAndContextThemeWrapper(final Context context,
             final KeyboardTheme keyboardTheme) {
         if (mThemeContext == null || mKeyboardTheme.mThemeId != keyboardTheme.mThemeId) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
new file mode 100644
index 0000000..4db72ad
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
@@ -0,0 +1,81 @@
+/*
+ * 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.util.Log;
+
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.settings.Settings;
+
+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;
+
+    private static final KeyboardTheme[] KEYBOARD_THEMES = {
+        new KeyboardTheme(THEME_ID_ICS, R.style.KeyboardTheme_ICS),
+        new KeyboardTheme(THEME_ID_KLP, R.style.KeyboardTheme_KLP),
+    };
+
+    public final int mThemeId;
+    public final int mStyleId;
+
+    // Note: The themeId should be aligned with "themeId" attribute of Keyboard style
+    // in values/style.xml.
+    public KeyboardTheme(final int themeId, final int styleId) {
+        mThemeId = themeId;
+        mStyleId = styleId;
+    }
+
+    private static KeyboardTheme searchKeyboardTheme(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) {
+                return theme;
+            }
+        }
+        return null;
+    }
+
+    public static KeyboardTheme getDefaultKeyboardTheme() {
+        return searchKeyboardTheme(DEFAULT_THEME_ID);
+    }
+
+    public static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs) {
+        final String themeIdString = prefs.getString(Settings.PREF_KEYBOARD_LAYOUT, null);
+        if (themeIdString == null) {
+            return getDefaultKeyboardTheme();
+        }
+        try {
+            final int themeId = Integer.parseInt(themeIdString);
+            final KeyboardTheme theme = searchKeyboardTheme(themeId);
+            if (theme != null) {
+                return theme;
+            }
+            Log.w(TAG, "Unknown keyboard theme in preference: " + themeIdString);
+        } 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();
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index d8dd93a..1cafd41 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -626,8 +626,8 @@
             final int moreKeyCode = key.getMoreKeys()[0].mCode;
             tracker.onLongPressed();
             listener.onPressKey(moreKeyCode, 0 /* repeatCount */, true /* isSinglePointer */);
-            listener.onCodeInput(moreKeyCode,
-                    Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
+            listener.onCodeInput(moreKeyCode, Constants.NOT_A_COORDINATE,
+                    Constants.NOT_A_COORDINATE, false /* isKeyRepeat */);
             listener.onReleaseKey(moreKeyCode, false /* withSliding */);
             return;
         }
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index fc33197..65242dd 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -143,9 +143,10 @@
             mListener.onTextInput(mCurrentKey.getOutputText());
         } else if (code != Constants.CODE_UNSPECIFIED) {
             if (getKeyboard().hasProximityCharsCorrection(code)) {
-                mListener.onCodeInput(code, x, y);
+                mListener.onCodeInput(code, x, y, false /* isKeyRepeat */);
             } else {
-                mListener.onCodeInput(code, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
+                mListener.onCodeInput(code, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
+                        false /* isKeyRepeat */);
             }
         }
     }
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 3539a87..4777166 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -325,7 +325,7 @@
     // Note that we need primaryCode argument because the keyboard may in shifted state and the
     // primaryCode is different from {@link Key#mKeyCode}.
     private void callListenerOnCodeInput(final Key key, final int primaryCode, final int x,
-            final int y, final long eventTime) {
+            final int y, final long eventTime, final boolean isKeyRepeat) {
         final boolean ignoreModifierKey = mIsInDraggingFinger && key.isModifier();
         final boolean altersCode = key.altCodeWhileTyping() && sTimerProxy.isTypingState();
         final int code = altersCode ? key.getAltCode() : primaryCode;
@@ -350,10 +350,10 @@
                 sListener.onTextInput(key.getOutputText());
             } else if (code != Constants.CODE_UNSPECIFIED) {
                 if (mKeyboard.hasProximityCharsCorrection(code)) {
-                    sListener.onCodeInput(code, x, y);
+                    sListener.onCodeInput(code, x, y, isKeyRepeat);
                 } else {
                     sListener.onCodeInput(code,
-                            Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
+                            Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE, isKeyRepeat);
                 }
             }
         }
@@ -1204,7 +1204,7 @@
         }
 
         final int code = key.getCode();
-        callListenerOnCodeInput(key, code, x, y, eventTime);
+        callListenerOnCodeInput(key, code, x, y, eventTime, false /* isKeyRepeat */);
         callListenerOnRelease(key, code, false /* withSliding */);
     }
 
@@ -1229,7 +1229,8 @@
         final int nextRepeatCount = repeatCount + 1;
         startKeyRepeatTimer(nextRepeatCount);
         callListenerOnPressAndCheckKeyboardLayoutChange(key, repeatCount);
-        callListenerOnCodeInput(key, code, mKeyX, mKeyY, SystemClock.uptimeMillis());
+        callListenerOnCodeInput(key, code, mKeyX, mKeyY, SystemClock.uptimeMillis(),
+                true /* isKeyRepeat */);
     }
 
     private void startKeyRepeatTimer(final int repeatCount) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 7fa9b6e..1fdb8d1 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1221,7 +1221,8 @@
 
     // Implementation of {@link KeyboardActionListener}.
     @Override
-    public void onCodeInput(final int codePoint, final int x, final int y) {
+    public void onCodeInput(final int codePoint, final int x, final int y,
+            final boolean isKeyRepeat) {
         final MainKeyboardView mainKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
         // x and y include some padding, but everything down the line (especially native
         // code) needs the coordinates in the keyboard frame.
@@ -1247,7 +1248,7 @@
             mSubtypeSwitcher.switchToShortcutIME(this);
             // Still call the *#onCodeInput methods for readability.
         }
-        final Event event = createSoftwareKeypressEvent(codeToSend, keyX, keyY);
+        final Event event = createSoftwareKeypressEvent(codeToSend, keyX, keyY, isKeyRepeat);
         final InputTransaction completeInputTransaction =
                 mInputLogic.onCodeInput(mSettings.getCurrent(), event,
                         mKeyboardSwitcher.getKeyboardShiftMode(), mHandler);
@@ -1259,7 +1260,7 @@
     // A helper method to split the code point and the key code. Ultimately, they should not be
     // squashed into the same variable, and this method should be removed.
     private static Event createSoftwareKeypressEvent(final int keyCodeOrCodePoint, final int keyX,
-             final int keyY) {
+             final int keyY, final boolean isKeyRepeat) {
         final int keyCode;
         final int codePoint;
         if (keyCodeOrCodePoint <= 0) {
@@ -1269,7 +1270,7 @@
             keyCode = Event.NOT_A_KEY_CODE;
             codePoint = keyCodeOrCodePoint;
         }
-        return Event.createSoftwareKeypressEvent(codePoint, keyCode, keyX, keyY);
+        return Event.createSoftwareKeypressEvent(codePoint, keyCode, keyX, keyY, isKeyRepeat);
     }
 
     // Called from PointerTracker through the KeyboardActionListener interface
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index bf8467e..491d980 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -884,10 +884,17 @@
         mSpaceState = SpaceState.NONE;
         mDeleteCount++;
 
-        // In many cases, we may have to put the keyboard in auto-shift state again. However
-        // we want to wait a few milliseconds before doing it to avoid the keyboard flashing
-        // during key repeat.
-        inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_LATER);
+        // In many cases after backspace, we need to update the shift state. Normally we need
+        // to do this right away to avoid the shift state being out of date in case the user types
+        // backspace then some other character very fast. However, in the case of backspace key
+        // repeat, this can lead to flashiness when the cursor flies over positions where the
+        // shift state should be updated, so if this is a key repeat, we update after a small delay.
+        // Then again, even in the case of a key repeat, if the cursor is at start of text, it
+        // can't go any further back, so we can update right away even if it's a key repeat.
+        final int shiftUpdateKind =
+                inputTransaction.mEvent.isKeyRepeat() && mConnection.getExpectedSelectionStart() > 0
+                ? InputTransaction.SHIFT_UPDATE_LATER : InputTransaction.SHIFT_UPDATE_NOW;
+        inputTransaction.requireShiftUpdate(shiftUpdateKind);
 
         if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) {
             // If we are in the middle of a recorrection, we need to commit the recorrection
@@ -910,11 +917,6 @@
             }
             mConnection.setComposingText(getTextWithUnderline(mWordComposer.getTypedWord()), 1);
             inputTransaction.setRequiresUpdateSuggestions();
-            if (!mWordComposer.isComposingWord()) {
-                // If we just removed the last character, auto-caps mode may have changed so we
-                // need to re-evaluate.
-                inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
-            }
         } else {
             if (mLastComposedWord.canRevertCommit()) {
                 if (inputTransaction.mSettingsValues.mIsInternal) {
@@ -1025,8 +1027,6 @@
                 restartSuggestionsOnWordTouchedByCursor(inputTransaction.mSettingsValues,
                         true /* includeResumedWordInSuggestions */);
             }
-            // We just removed at least one character. We need to update the auto-caps state.
-            inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
         }
     }
 
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index 1ba92ad..353b746 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -23,7 +23,6 @@
 import android.preference.PreferenceManager;
 import android.util.Log;
 
-import com.android.inputmethod.keyboard.KeyboardSwitcher;
 import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
 import com.android.inputmethod.latin.InputAttributes;
 import com.android.inputmethod.latin.R;
@@ -270,42 +269,6 @@
         return prefs.getBoolean(PREF_SHOW_LANGUAGE_SWITCH_KEY, true);
     }
 
-    public static int readKeyboardThemeIndex(final SharedPreferences prefs, final Resources res) {
-        final int defaultThemeIndex = readDefaultKeyboardThemeIndex(res);
-        final String themeIndexString = prefs.getString(PREF_KEYBOARD_LAYOUT, null);
-        if (themeIndexString == null) {
-            return defaultThemeIndex;
-        }
-        try {
-            return Integer.parseInt(themeIndexString);
-        } catch (final NumberFormatException e) {
-            // Format error, returns default keyboard theme index.
-            Log.e(TAG, "Illegal keyboard theme in preference: " + themeIndexString + ", default to "
-                    + defaultThemeIndex, e);
-        }
-        return defaultThemeIndex;
-    }
-
-    private static int readDefaultKeyboardThemeIndex(final Resources res) {
-        final String defaultThemeIndexString = res.getString(
-                R.string.config_default_keyboard_theme_index);
-        try {
-            return Integer.parseInt(defaultThemeIndexString);
-        } catch (final NumberFormatException e) {
-            final int defaultThemeIndex = KeyboardSwitcher.DEFAULT_THEME_INDEX;
-            Log.e(TAG, "Corrupted default keyoard theme in resource: " + defaultThemeIndexString
-                    + ", default to " + defaultThemeIndex, e);
-            return defaultThemeIndex;
-        }
-    }
-
-    public static int resetAndGetDefaultKeyboardThemeIndex(final SharedPreferences prefs,
-            final Resources res) {
-        final int defaultThemeIndex = readDefaultKeyboardThemeIndex(res);
-        prefs.edit().putString(PREF_KEYBOARD_LAYOUT, Integer.toString(defaultThemeIndex)).apply();
-        return defaultThemeIndex;
-    }
-
     public static String readPrefAdditionalSubtypes(final SharedPreferences prefs,
             final Resources res) {
         final String predefinedPrefSubtypes = AdditionalSubtypeUtils.createPrefSubtypes(
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index a102344..0cb6614 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -19,16 +19,19 @@
 #include "com_android_inputmethod_latin_BinaryDictionary.h"
 
 #include <cstring> // for memset()
+#include <vector>
 
 #include "defines.h"
 #include "jni.h"
 #include "jni_common.h"
 #include "suggest/core/dictionary/dictionary.h"
+#include "suggest/core/dictionary/property/unigram_property.h"
 #include "suggest/core/dictionary/property/word_property.h"
 #include "suggest/core/result/suggestion_results.h"
 #include "suggest/core/suggest_options.h"
 #include "suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h"
 #include "utils/char_utils.h"
+#include "utils/jni_data_utils.h"
 #include "utils/time_keeper.h"
 
 namespace latinime {
@@ -288,22 +291,24 @@
 }
 
 static void latinime_BinaryDictionary_addUnigramWord(JNIEnv *env, jclass clazz, jlong dict,
-        jintArray word, jint probability, jintArray shortcutTarget, jint shortuctProbability,
+        jintArray word, jint probability, jintArray shortcutTarget, jint shortcutProbability,
         jboolean isNotAWord, jboolean isBlacklisted, jint timestamp) {
     Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
     if (!dictionary) {
         return;
     }
-    jsize wordLength = env->GetArrayLength(word);
-    int codePoints[wordLength];
-    env->GetIntArrayRegion(word, 0, wordLength, codePoints);
-    jsize shortcutLength = shortcutTarget ? env->GetArrayLength(shortcutTarget) : 0;
-    int shortcutTargetCodePoints[shortcutLength];
-    if (shortcutTarget) {
-        env->GetIntArrayRegion(shortcutTarget, 0, shortcutLength, shortcutTargetCodePoints);
+    jsize codePointCount = env->GetArrayLength(word);
+    int codePoints[codePointCount];
+    env->GetIntArrayRegion(word, 0, codePointCount, codePoints);
+    std::vector<UnigramProperty::ShortcutProperty> shortcuts;
+    std::vector<int> shortcutTargetCodePoints;
+    JniDataUtils::jintarrayToVector(env, shortcutTarget, &shortcutTargetCodePoints);
+    if (!shortcutTargetCodePoints.empty()) {
+        shortcuts.emplace_back(&shortcutTargetCodePoints, shortcutProbability);
     }
-    dictionary->addUnigramWord(codePoints, wordLength, probability, shortcutTargetCodePoints,
-            shortcutLength, shortuctProbability, isNotAWord, isBlacklisted, timestamp);
+    const UnigramProperty unigramProperty(isNotAWord, isBlacklisted,
+            probability, timestamp, 0 /* level */, 0 /* count */, &shortcuts);
+    dictionary->addUnigramWord(codePoints, codePointCount, &unigramProperty);
 }
 
 static void latinime_BinaryDictionary_addBigramWords(JNIEnv *env, jclass clazz, jlong dict,
@@ -394,15 +399,17 @@
         jboolean isBlacklisted = env->GetBooleanField(languageModelParam, isBlacklistedFieldId);
         jintArray shortcutTarget = static_cast<jintArray>(
                 env->GetObjectField(languageModelParam, shortcutTargetFieldId));
-        jsize shortcutLength = shortcutTarget ? env->GetArrayLength(shortcutTarget) : 0;
-        int shortcutTargetCodePoints[shortcutLength];
-        if (shortcutTarget) {
-            env->GetIntArrayRegion(shortcutTarget, 0, shortcutLength, shortcutTargetCodePoints);
+        std::vector<UnigramProperty::ShortcutProperty> shortcuts;
+        std::vector<int> shortcutTargetCodePoints;
+        JniDataUtils::jintarrayToVector(env, shortcutTarget, &shortcutTargetCodePoints);
+        if (!shortcutTargetCodePoints.empty()) {
+            jint shortcutProbability =
+                    env->GetIntField(languageModelParam, shortcutProbabilityFieldId);
+            shortcuts.emplace_back(&shortcutTargetCodePoints, shortcutProbability);
         }
-        jint shortcutProbability = env->GetIntField(languageModelParam, shortcutProbabilityFieldId);
-        dictionary->addUnigramWord(word1CodePoints, word1Length, unigramProbability,
-                shortcutTargetCodePoints, shortcutLength, shortcutProbability,
-                isNotAWord, isBlacklisted, timestamp);
+        const UnigramProperty unigramProperty(isNotAWord, isBlacklisted,
+                unigramProbability, timestamp, 0 /* level */, 0 /* count */, &shortcuts);
+        dictionary->addUnigramWord(word1CodePoints, word1Length, &unigramProperty);
         if (word0) {
             jint bigramProbability = env->GetIntField(languageModelParam, bigramProbabilityFieldId);
             dictionary->addBigramWords(word0CodePoints, word0Length, word1CodePoints, word1Length,
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index 8445da3..e288413 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -50,15 +50,10 @@
     TimeKeeper::setCurrentTime();
     DicTraverseSession::initSessionInstance(
             traverseSession, this, prevWordCodePoints, prevWordLength, suggestOptions);
-    if (suggestOptions->isGesture()) {
-        mGestureSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
-                ycoordinates, times, pointerIds, inputCodePoints, inputSize,
-                languageWeight, outSuggestionResults);
-    } else {
-        mTypingSuggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
-                ycoordinates, times, pointerIds, inputCodePoints, inputSize,
-                languageWeight, outSuggestionResults);
-    }
+    const auto &suggest = suggestOptions->isGesture() ? mGestureSuggest : mTypingSuggest;
+    suggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
+            ycoordinates, times, pointerIds, inputCodePoints, inputSize,
+            languageWeight, outSuggestionResults);
     if (DEBUG_DICT) {
         outSuggestionResults->dumpSuggestions();
     }
@@ -87,14 +82,10 @@
     return mBigramDictionary.getBigramProbability(word0, length0, word1, length1);
 }
 
-void Dictionary::addUnigramWord(const int *const word, const int length, const int probability,
-        const int *const shortcutTargetCodePoints, const int shortcutLength,
-        const int shortcutProbability, const bool isNotAWord, const bool isBlacklisted,
-        const int timestamp) {
+void Dictionary::addUnigramWord(const int *const word, const int length,
+        const UnigramProperty *const unigramProperty) {
     TimeKeeper::setCurrentTime();
-    mDictionaryStructureWithBufferPolicy->addUnigramWord(word, length, probability,
-            shortcutTargetCodePoints, shortcutLength, shortcutProbability, isNotAWord,
-            isBlacklisted, timestamp);
+    mDictionaryStructureWithBufferPolicy->addUnigramWord(word, length, unigramProperty);
 }
 
 void Dictionary::addBigramWords(const int *const word0, const int length0, const int *const word1,
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index 6b77565..b6149b3 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -34,7 +34,6 @@
 class ProximityInfo;
 class SuggestionResults;
 class SuggestOptions;
-class WordProperty;
 
 class Dictionary {
  public:
@@ -74,10 +73,8 @@
 
     int getBigramProbability(const int *word0, int length0, const int *word1, int length1) const;
 
-    void addUnigramWord(const int *const word, const int length, const int probability,
-            const int *const shortcutTargetCodePoints, const int shortcutLength,
-            const int shortcutProbability, const bool isNotAWord, const bool isBlacklisted,
-            const int timestamp);
+    void addUnigramWord(const int *const codePoints, const int codePointCount,
+            const UnigramProperty *const unigramProperty);
 
     void addBigramWords(const int *const word0, const int length0, const int *const word1,
             const int length1, const int probability, const int timestamp);
diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
index ae2e7a8..807f9b8 100644
--- a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
+++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
@@ -29,6 +29,7 @@
 class DictionaryBigramsStructurePolicy;
 class DictionaryHeaderStructurePolicy;
 class DictionaryShortcutsStructurePolicy;
+class UnigramProperty;
 
 /*
  * This class abstracts the structure of dictionaries.
@@ -69,9 +70,7 @@
 
     // Returns whether the update was success or not.
     virtual bool addUnigramWord(const int *const word, const int length,
-            const int probability, const int *const shortcutTargetCodePoints,
-            const int shortcutLength, const int shortcutProbability, const bool isNotAWord,
-            const bool isBlacklisted,const int timestamp) = 0;
+            const UnigramProperty *const unigramProperty) = 0;
 
     // Returns whether the update was success or not.
     virtual bool addBigramWords(const int *const word0, const int length0, const int *const word1,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
index 79500b9..85f4660 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
@@ -81,10 +81,8 @@
         return &mShortcutListPolicy;
     }
 
-    bool addUnigramWord(const int *const word, const int length, const int probability,
-            const int *const shortcutTargetCodePoints, const int shortcutLength,
-            const int shortcutProbability, const bool isNotAWord, const bool isBlacklisted,
-            const int timestamp) {
+    bool addUnigramWord(const int *const word, const int length,
+            const UnigramProperty *const unigramProperty) {
         // This method should not be called for non-updatable dictionary.
         AKLOGI("Warning: addUnigramWord() is called for non-updatable dictionary.");
         return false;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
index 6cf8409..bbfd22e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
@@ -154,9 +154,7 @@
 }
 
 bool Ver4PatriciaTriePolicy::addUnigramWord(const int *const word, const int length,
-        const int probability, const int *const shortcutTargetCodePoints, const int shortcutLength,
-        const int shortcutProbability, const bool isNotAWord, const bool isBlacklisted,
-        const int timestamp) {
+        const UnigramProperty *const unigramProperty) {
     if (!mBuffers->isUpdatable()) {
         AKLOGI("Warning: addUnigramWord() is called for non-updatable dictionary.");
         return false;
@@ -170,20 +168,24 @@
         AKLOGE("The word is too long to insert to the dictionary, length: %d", length);
         return false;
     }
-    if (shortcutLength > MAX_WORD_LENGTH) {
-        AKLOGE("The shortcutTarget is too long to insert to the dictionary, length: %d",
-                shortcutLength);
-        return false;
+    for (const auto &shortcut : unigramProperty->getShortcuts()) {
+        if (shortcut.getTargetCodePoints()->size() > MAX_WORD_LENGTH) {
+            AKLOGE("One of shortcut targets is too long to insert to the dictionary, length: %d",
+                    shortcut.getTargetCodePoints()->size());
+            return false;
+        }
     }
     DynamicPtReadingHelper readingHelper(&mNodeReader, &mPtNodeArrayReader);
     readingHelper.initWithPtNodeArrayPos(getRootPosition());
     bool addedNewUnigram = false;
-    if (mUpdatingHelper.addUnigramWord(&readingHelper, word, length, probability, isNotAWord,
-            isBlacklisted, timestamp,  &addedNewUnigram)) {
+    if (mUpdatingHelper.addUnigramWord(&readingHelper, word, length,
+            unigramProperty->getProbability(), unigramProperty->isNotAWord(),
+            unigramProperty->isBlacklisted(), unigramProperty->getTimestamp(),
+            &addedNewUnigram)) {
         if (addedNewUnigram) {
             mUnigramCount++;
         }
-        if (shortcutLength > 0) {
+        if (unigramProperty->getShortcuts().size() > 0) {
             // Add shortcut target.
             const int wordPos = getTerminalPtNodePositionOfWord(word, length,
                     false /* forceLowerCaseSearch */);
@@ -191,11 +193,15 @@
                 AKLOGE("Cannot find terminal PtNode position to add shortcut target.");
                 return false;
             }
-            if (!mUpdatingHelper.addShortcutTarget(wordPos, shortcutTargetCodePoints,
-                    shortcutLength, shortcutProbability)) {
-                AKLOGE("Cannot add new shortcut target. PtNodePos: %d, length: %d, probability: %d",
-                        wordPos, shortcutLength, shortcutProbability);
-                return false;
+            for (const auto &shortcut : unigramProperty->getShortcuts()) {
+                if (!mUpdatingHelper.addShortcutTarget(wordPos,
+                        shortcut.getTargetCodePoints()->data(),
+                        shortcut.getTargetCodePoints()->size(), shortcut.getProbability())) {
+                    AKLOGE("Cannot add new shortcut target. PtNodePos: %d, length: %d, "
+                            "probability: %d", wordPos, shortcut.getTargetCodePoints()->size(),
+                            shortcut.getProbability());
+                    return false;
+                }
             }
         }
         return true;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
index cffb1f6..8f981de 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
@@ -90,10 +90,8 @@
         return &mShortcutPolicy;
     }
 
-    bool addUnigramWord(const int *const word, const int length, const int probability,
-            const int *const shortcutTargetCodePoints, const int shortcutLength,
-            const int shortcutProbability, const bool isNotAWord, const bool isBlacklisted,
-            const int timestamp);
+    bool addUnigramWord(const int *const word, const int length,
+            const UnigramProperty *const unigramProperty);
 
     bool addBigramWords(const int *const word0, const int length0, const int *const word1,
             const int length1, const int probability, const int timestamp);
diff --git a/native/jni/src/utils/jni_data_utils.h b/native/jni/src/utils/jni_data_utils.h
new file mode 100644
index 0000000..e0bbdfd
--- /dev/null
+++ b/native/jni/src/utils/jni_data_utils.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+#ifndef LATINIME_JNI_DATA_UTILS_H
+#define LATINIME_JNI_DATA_UTILS_H
+
+#include <vector>
+
+#include "defines.h"
+#include "jni.h"
+
+namespace latinime {
+
+class JniDataUtils {
+ public:
+    static void jintarrayToVector(JNIEnv *env, jintArray array, std::vector<int> *const outVector) {
+        if (!array) {
+            outVector->clear();
+            return;
+        }
+        const jsize arrayLength = env->GetArrayLength(array);
+        outVector->resize(arrayLength);
+        env->GetIntArrayRegion(array, 0 /* start */, arrayLength, outVector->data());
+    }
+
+ private:
+    DISALLOW_IMPLICIT_CONSTRUCTORS(JniDataUtils);
+};
+} // namespace latinime
+#endif // LATINIME_JNI_DATA_UTILS_H
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
index a4c69e0..0fb6ff2 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
@@ -27,7 +27,6 @@
 
 import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
 import com.android.inputmethod.keyboard.KeyboardLayoutSet.Builder;
-import com.android.inputmethod.keyboard.KeyboardSwitcher.KeyboardTheme;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.RichInputMethodManager;
@@ -42,7 +41,7 @@
 @SmallTest
 public class KeyboardLayoutSetTestsBase extends AndroidTestCase {
     private static final KeyboardTheme DEFAULT_KEYBOARD_THEME =
-            KeyboardSwitcher.KEYBOARD_THEMES[KeyboardSwitcher.DEFAULT_THEME_INDEX];
+            KeyboardTheme.getDefaultKeyboardTheme();
 
     // All input method subtypes of LatinIME.
     private final ArrayList<InputMethodSubtype> mAllSubtypesList = CollectionUtils.newArrayList();
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index e5f111a..260e534 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -254,7 +254,7 @@
     }
 
     // type(int) and type(String): helper methods to send a code point resp. a string to LatinIME.
-    protected void type(final int codePoint) {
+    protected void typeInternal(final int codePoint, final boolean isKeyRepeat) {
         // onPressKey and onReleaseKey are explicitly deactivated here, but they do happen in the
         // code (although multitouch/slide input and other factors make the sequencing complicated).
         // They are supposed to be entirely deconnected from the input logic from LatinIME point of
@@ -263,16 +263,26 @@
         // but keep them in mind if something breaks. Commenting them out as is should work.
         //mLatinIME.onPressKey(codePoint, 0 /* repeatCount */, true /* isSinglePointer */);
         final Key key = mKeyboard.getKey(codePoint);
-        if (key != null) {
+        if (key == null) {
+            mLatinIME.onCodeInput(codePoint, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
+                    isKeyRepeat);
+        } else {
             final int x = key.getX() + key.getWidth() / 2;
             final int y = key.getY() + key.getHeight() / 2;
-            mLatinIME.onCodeInput(codePoint, x, y);
-            return;
+            mLatinIME.onCodeInput(codePoint, x, y, isKeyRepeat);
         }
-        mLatinIME.onCodeInput(codePoint, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
+        // Also see the comment at the top of this function about onReleaseKey
         //mLatinIME.onReleaseKey(codePoint, false /* withSliding */);
     }
 
+    protected void type(final int codePoint) {
+        typeInternal(codePoint, false /* isKeyRepeat */);
+    }
+
+    protected void repeatKey(final int codePoint) {
+        typeInternal(codePoint, true /* isKeyRepeat */);
+    }
+
     protected void type(final String stringToType) {
         for (int i = 0; i < stringToType.length(); i = stringToType.offsetByCodePoints(i, 1)) {
             type(stringToType.codePointAt(i));
diff --git a/tests/src/com/android/inputmethod/latin/ShiftModeTests.java b/tests/src/com/android/inputmethod/latin/ShiftModeTests.java
index 806fad0..6fc9df7 100644
--- a/tests/src/com/android/inputmethod/latin/ShiftModeTests.java
+++ b/tests/src/com/android/inputmethod/latin/ShiftModeTests.java
@@ -53,4 +53,29 @@
         type(" ");
         assertTrue("Caps after period space", isCapsModeAutoShifted());
     }
+
+    public void testBackspace() {
+        assertTrue("Initial auto caps state", isCapsModeAutoShifted());
+        type("A");
+        assertFalse("Caps state after one letter", isCapsModeAutoShifted());
+        type(Constants.CODE_DELETE);
+        assertTrue("Auto caps state at start after delete", isCapsModeAutoShifted());
+    }
+
+    public void testRepeatingBackspace() {
+        final String SENTENCE_TO_TYPE = "Test sentence. Another.";
+        final int BACKSPACE_COUNT =
+                SENTENCE_TO_TYPE.length() - SENTENCE_TO_TYPE.lastIndexOf(' ') - 1;
+
+        type(SENTENCE_TO_TYPE);
+        assertFalse("Caps after typing \"" + SENTENCE_TO_TYPE + "\"", isCapsModeAutoShifted());
+        type(Constants.CODE_DELETE);
+        for (int i = 1; i < BACKSPACE_COUNT; ++i) {
+            repeatKey(Constants.CODE_DELETE);
+        }
+        assertFalse("Caps immediately after repeating Backspace a lot", isCapsModeAutoShifted());
+        sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+        runMessages();
+        assertTrue("Caps after a while after repeating Backspace a lot", isCapsModeAutoShifted());
+    }
 }