am 44aeff2b: (-s ours) am e75e00d8: Merge "Key release event should be sent when finger sliding (DO NOT MERGE)" into gingerbread

* commit '44aeff2b5ce81c23495f982102c35abd2dab969a':
  Key release event should be sent when finger sliding (DO NOT MERGE)
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
old mode 100755
new mode 100644
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_holo.9.png
new file mode 100644
index 0000000..d13386a
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_holo.9.png
new file mode 100644
index 0000000..95b73c0
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_off_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_holo.9.png
new file mode 100644
index 0000000..3bd2249
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_normal_on_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_holo.9.png
new file mode 100644
index 0000000..77a0e7d
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
new file mode 100644
index 0000000..1760075
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
new file mode 100644
index 0000000..b6d0dbc
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_light_normal_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_light_normal_holo.9.png
new file mode 100644
index 0000000..763c538
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_light_normal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_holo.9.png
new file mode 100644
index 0000000..328fe16
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_light_pressed_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_holo.9.png b/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_holo.9.png
new file mode 100644
index 0000000..e0129ab
--- /dev/null
+++ b/java/res/drawable-hdpi/btn_keyboard_key_popup_selected_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_subtype_keyboard.png b/java/res/drawable-hdpi/ic_subtype_keyboard.png
deleted file mode 100644
index 7015e26..0000000
--- a/java/res/drawable-hdpi/ic_subtype_keyboard.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/ic_subtype_mic.png b/java/res/drawable-hdpi/ic_subtype_mic.png
deleted file mode 100644
index cb86a55..0000000
--- a/java/res/drawable-hdpi/ic_subtype_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_at_holo.9.png b/java/res/drawable-hdpi/key_hint_at_holo.9.png
new file mode 100644
index 0000000..ebde12d
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_at_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_at_large_holo.9.png b/java/res/drawable-hdpi/key_hint_at_large_holo.9.png
new file mode 100644
index 0000000..29d21bc
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_at_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_colon_holo.9.png b/java/res/drawable-hdpi/key_hint_colon_holo.9.png
new file mode 100644
index 0000000..14c4699
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_colon_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_colon_large_holo.9.png b/java/res/drawable-hdpi/key_hint_colon_large_holo.9.png
new file mode 100644
index 0000000..91e7883
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_colon_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_comma_holo.9.png b/java/res/drawable-hdpi/key_hint_comma_holo.9.png
new file mode 100644
index 0000000..82e4a93
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_comma_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_dash_holo.9.png b/java/res/drawable-hdpi/key_hint_dash_holo.9.png
new file mode 100644
index 0000000..2ee22ba
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_dash_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_doublecross_holo.9.png b/java/res/drawable-hdpi/key_hint_doublecross_holo.9.png
new file mode 100644
index 0000000..0da9332
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_doublecross_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_equal_holo.9.png b/java/res/drawable-hdpi/key_hint_equal_holo.9.png
new file mode 100644
index 0000000..f5a9ba2
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_equal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_exclamation_holo.9.png b/java/res/drawable-hdpi/key_hint_exclamation_holo.9.png
new file mode 100644
index 0000000..6887156
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_exclamation_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_exclamation_large_holo.9.png b/java/res/drawable-hdpi/key_hint_exclamation_large_holo.9.png
new file mode 100644
index 0000000..e20a137
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_exclamation_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_larger_holo.9.png b/java/res/drawable-hdpi/key_hint_larger_holo.9.png
new file mode 100644
index 0000000..50652bb
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_larger_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_parenclose_holo.9.png b/java/res/drawable-hdpi/key_hint_parenclose_holo.9.png
new file mode 100644
index 0000000..52ee86a
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_parenclose_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_parenopen_holo.9.png b/java/res/drawable-hdpi/key_hint_parenopen_holo.9.png
new file mode 100644
index 0000000..b0ed388
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_parenopen_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_period_holo.9.png b/java/res/drawable-hdpi/key_hint_period_holo.9.png
new file mode 100644
index 0000000..8d798a5
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_period_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_plus_holo.9.png b/java/res/drawable-hdpi/key_hint_plus_holo.9.png
new file mode 100644
index 0000000..f1d232e
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_plus_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_plus_large_holo.9.png b/java/res/drawable-hdpi/key_hint_plus_large_holo.9.png
new file mode 100644
index 0000000..5f7d315
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_plus_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_question_holo.9.png b/java/res/drawable-hdpi/key_hint_question_holo.9.png
new file mode 100644
index 0000000..9055c76
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_question_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_question_large_holo.9.png b/java/res/drawable-hdpi/key_hint_question_large_holo.9.png
new file mode 100644
index 0000000..ade394c
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_question_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_quote_holo.9.png b/java/res/drawable-hdpi/key_hint_quote_holo.9.png
new file mode 100644
index 0000000..361e3a8
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_quote_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_quote_large_holo.9.png b/java/res/drawable-hdpi/key_hint_quote_large_holo.9.png
new file mode 100644
index 0000000..cc5e8d7
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_quote_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_semicolon_holo.9.png b/java/res/drawable-hdpi/key_hint_semicolon_holo.9.png
new file mode 100644
index 0000000..7f9e8c9
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_semicolon_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_simplequote_holo.9.png b/java/res/drawable-hdpi/key_hint_simplequote_holo.9.png
new file mode 100644
index 0000000..5e1a45c
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_simplequote_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_slash_holo.9.png b/java/res/drawable-hdpi/key_hint_slash_holo.9.png
new file mode 100644
index 0000000..645586a
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_slash_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_slash_large_holo.9.png b/java/res/drawable-hdpi/key_hint_slash_large_holo.9.png
new file mode 100644
index 0000000..75c3bb1
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_slash_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_smaller_holo.9.png b/java/res/drawable-hdpi/key_hint_smaller_holo.9.png
new file mode 100644
index 0000000..2a0587c
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_smaller_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_star_holo.9.png b/java/res/drawable-hdpi/key_hint_star_holo.9.png
new file mode 100644
index 0000000..9f33b98
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_star_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/key_hint_underline_holo.9.png b/java/res/drawable-hdpi/key_hint_underline_holo.9.png
new file mode 100644
index 0000000..a8841d0
--- /dev/null
+++ b/java/res/drawable-hdpi/key_hint_underline_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_background_holo.9.png b/java/res/drawable-hdpi/keyboard_background_holo.9.png
new file mode 100644
index 0000000..87aa98e
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_key_feedback_background_holo.9.png b/java/res/drawable-hdpi/keyboard_key_feedback_background_holo.9.png
new file mode 100644
index 0000000..571f3aa
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_key_feedback_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/keyboard_popup_panel_background_holo.9.png b/java/res/drawable-hdpi/keyboard_popup_panel_background_holo.9.png
new file mode 100644
index 0000000..2b529b8
--- /dev/null
+++ b/java/res/drawable-hdpi/keyboard_popup_panel_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-hdpi/mic_slash_holo.png b/java/res/drawable-hdpi/mic_slash_holo.png
new file mode 100644
index 0000000..8108b6e
--- /dev/null
+++ b/java/res/drawable-hdpi/mic_slash_holo.png
Binary files differ
diff --git a/java/res/drawable-hdpi/sym_keyboard_shift_locked_holo.png b/java/res/drawable-hdpi/sym_keyboard_shift_locked_holo.png
new file mode 100644
index 0000000..f99a0ed
--- /dev/null
+++ b/java/res/drawable-hdpi/sym_keyboard_shift_locked_holo.png
Binary files differ
diff --git a/java/res/drawable-hdpi/working.png b/java/res/drawable-hdpi/working.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/java/res/drawable-land-hdpi/btn_keyboard_key_normal.9.png b/java/res/drawable-land-hdpi/btn_keyboard_key_normal.9.png
new file mode 100755
index 0000000..603bf0e
--- /dev/null
+++ b/java/res/drawable-land-hdpi/btn_keyboard_key_normal.9.png
Binary files differ
diff --git a/java/res/drawable-land-hdpi/btn_keyboard_key_normal_off.9.png b/java/res/drawable-land-hdpi/btn_keyboard_key_normal_off.9.png
new file mode 100755
index 0000000..6ddd516
--- /dev/null
+++ b/java/res/drawable-land-hdpi/btn_keyboard_key_normal_off.9.png
Binary files differ
diff --git a/java/res/drawable-land-hdpi/btn_keyboard_key_normal_off_stone.9.png b/java/res/drawable-land-hdpi/btn_keyboard_key_normal_off_stone.9.png
new file mode 100644
index 0000000..67a204f
--- /dev/null
+++ b/java/res/drawable-land-hdpi/btn_keyboard_key_normal_off_stone.9.png
Binary files differ
diff --git a/java/res/drawable-land-hdpi/btn_keyboard_key_normal_on.9.png b/java/res/drawable-land-hdpi/btn_keyboard_key_normal_on.9.png
new file mode 100755
index 0000000..65fdeb3
--- /dev/null
+++ b/java/res/drawable-land-hdpi/btn_keyboard_key_normal_on.9.png
Binary files differ
diff --git a/java/res/drawable-land-hdpi/btn_keyboard_key_normal_on_stone.9.png b/java/res/drawable-land-hdpi/btn_keyboard_key_normal_on_stone.9.png
new file mode 100644
index 0000000..63cbe60
--- /dev/null
+++ b/java/res/drawable-land-hdpi/btn_keyboard_key_normal_on_stone.9.png
Binary files differ
diff --git a/java/res/drawable-land-hdpi/btn_keyboard_key_normal_stone.9.png b/java/res/drawable-land-hdpi/btn_keyboard_key_normal_stone.9.png
new file mode 100644
index 0000000..0dd33b4
--- /dev/null
+++ b/java/res/drawable-land-hdpi/btn_keyboard_key_normal_stone.9.png
Binary files differ
diff --git a/java/res/drawable-land-hdpi/btn_keyboard_key_pressed.9.png b/java/res/drawable-land-hdpi/btn_keyboard_key_pressed.9.png
new file mode 100755
index 0000000..7ec915f
--- /dev/null
+++ b/java/res/drawable-land-hdpi/btn_keyboard_key_pressed.9.png
Binary files differ
diff --git a/java/res/drawable-land-hdpi/btn_keyboard_key_pressed_off.9.png b/java/res/drawable-land-hdpi/btn_keyboard_key_pressed_off.9.png
new file mode 100755
index 0000000..4392717
--- /dev/null
+++ b/java/res/drawable-land-hdpi/btn_keyboard_key_pressed_off.9.png
Binary files differ
diff --git a/java/res/drawable-land-hdpi/btn_keyboard_key_pressed_on.9.png b/java/res/drawable-land-hdpi/btn_keyboard_key_pressed_on.9.png
new file mode 100755
index 0000000..c2cc320
--- /dev/null
+++ b/java/res/drawable-land-hdpi/btn_keyboard_key_pressed_on.9.png
Binary files differ
diff --git a/java/res/drawable-land-hdpi/keyboard_suggest_strip_divider.png b/java/res/drawable-land-hdpi/keyboard_suggest_strip_divider.png
new file mode 100755
index 0000000..1a03c52
--- /dev/null
+++ b/java/res/drawable-land-hdpi/keyboard_suggest_strip_divider.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/hint_popup_holo.9.png b/java/res/drawable-land-mdpi/hint_popup_holo.9.png
new file mode 100644
index 0000000..c409cea
--- /dev/null
+++ b/java/res/drawable-land-mdpi/hint_popup_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_at_holo.9.png b/java/res/drawable-land-mdpi/key_hint_at_holo.9.png
new file mode 100644
index 0000000..627e7a0
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_at_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_at_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_at_large_holo.9.png
new file mode 100644
index 0000000..9569217
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_at_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_colon_holo.9.png b/java/res/drawable-land-mdpi/key_hint_colon_holo.9.png
new file mode 100644
index 0000000..6470ed3
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_colon_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_colon_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_colon_large_holo.9.png
new file mode 100644
index 0000000..bdf4ed5
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_colon_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_comma_holo.9.png b/java/res/drawable-land-mdpi/key_hint_comma_holo.9.png
new file mode 100644
index 0000000..f939162
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_comma_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_dash_holo.9.png b/java/res/drawable-land-mdpi/key_hint_dash_holo.9.png
new file mode 100644
index 0000000..1cb0bdf
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_dash_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_doublecross_holo.9.png b/java/res/drawable-land-mdpi/key_hint_doublecross_holo.9.png
new file mode 100644
index 0000000..7e7ceb3
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_doublecross_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_equal_holo.9.png b/java/res/drawable-land-mdpi/key_hint_equal_holo.9.png
new file mode 100644
index 0000000..8e57059
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_equal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_exclamation_holo.9.png b/java/res/drawable-land-mdpi/key_hint_exclamation_holo.9.png
new file mode 100644
index 0000000..89c5aae
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_exclamation_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_exclamation_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_exclamation_large_holo.9.png
new file mode 100644
index 0000000..932bcb9
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_exclamation_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_larger_holo.9.png b/java/res/drawable-land-mdpi/key_hint_larger_holo.9.png
new file mode 100644
index 0000000..37c0527
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_larger_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_parenclose_holo.9.png b/java/res/drawable-land-mdpi/key_hint_parenclose_holo.9.png
new file mode 100644
index 0000000..97e1f14
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_parenclose_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_parenopen_holo.9.png b/java/res/drawable-land-mdpi/key_hint_parenopen_holo.9.png
new file mode 100644
index 0000000..36add5d
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_parenopen_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_period_holo.9.png b/java/res/drawable-land-mdpi/key_hint_period_holo.9.png
new file mode 100644
index 0000000..4a70f07
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_period_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_plus_holo.9.png b/java/res/drawable-land-mdpi/key_hint_plus_holo.9.png
new file mode 100644
index 0000000..7698a58
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_plus_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_plus_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_plus_large_holo.9.png
new file mode 100644
index 0000000..206d990
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_plus_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_question_holo.9.png b/java/res/drawable-land-mdpi/key_hint_question_holo.9.png
new file mode 100644
index 0000000..8373b69
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_question_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_question_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_question_large_holo.9.png
new file mode 100644
index 0000000..a9eaeea
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_question_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_quote_holo.9.png b/java/res/drawable-land-mdpi/key_hint_quote_holo.9.png
new file mode 100644
index 0000000..01a3a9a
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_quote_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_quote_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_quote_large_holo.9.png
new file mode 100644
index 0000000..7cba264
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_quote_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_semicolon_holo.9.png b/java/res/drawable-land-mdpi/key_hint_semicolon_holo.9.png
new file mode 100644
index 0000000..63a3875
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_semicolon_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_simplequote_holo.9.png b/java/res/drawable-land-mdpi/key_hint_simplequote_holo.9.png
new file mode 100644
index 0000000..3c217b0
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_simplequote_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_slash_holo.9.png b/java/res/drawable-land-mdpi/key_hint_slash_holo.9.png
new file mode 100644
index 0000000..98545f0
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_slash_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_slash_large_holo.9.png b/java/res/drawable-land-mdpi/key_hint_slash_large_holo.9.png
new file mode 100644
index 0000000..a3a0297
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_slash_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_smaller_holo.9.png b/java/res/drawable-land-mdpi/key_hint_smaller_holo.9.png
new file mode 100644
index 0000000..5af1836
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_smaller_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_star_holo.9.png b/java/res/drawable-land-mdpi/key_hint_star_holo.9.png
new file mode 100644
index 0000000..18304d7
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_star_holo.9.png
Binary files differ
diff --git a/java/res/drawable-land-mdpi/key_hint_underline_holo.9.png b/java/res/drawable-land-mdpi/key_hint_underline_holo.9.png
new file mode 100644
index 0000000..a95a575
--- /dev/null
+++ b/java/res/drawable-land-mdpi/key_hint_underline_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_holo.9.png
new file mode 100644
index 0000000..8002da2
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_holo.9.png
new file mode 100644
index 0000000..506feec
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_off_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_holo.9.png
new file mode 100644
index 0000000..9c34ccc
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_normal_on_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_holo.9.png
new file mode 100644
index 0000000..f33e4cb
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
new file mode 100644
index 0000000..f6882c0
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_off_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
new file mode 100644
index 0000000..e86eea7
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_dark_pressed_on_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_normal_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_normal_holo.9.png
new file mode 100644
index 0000000..a8375d4
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_light_normal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_popup_normal.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_popup_normal.9.png
index 02d0fcf..b4a50f2 100644
--- a/java/res/drawable-mdpi/btn_keyboard_key_light_popup_normal.9.png
+++ b/java/res/drawable-mdpi/btn_keyboard_key_light_popup_normal.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_holo.9.png
new file mode 100644
index 0000000..4718865
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_light_pressed_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_holo.9.png b/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_holo.9.png
new file mode 100644
index 0000000..dc41d58
--- /dev/null
+++ b/java/res/drawable-mdpi/btn_keyboard_key_popup_selected_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/cancel_holo.9.png b/java/res/drawable-mdpi/cancel_holo.9.png
new file mode 100644
index 0000000..74f967e
--- /dev/null
+++ b/java/res/drawable-mdpi/cancel_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/hint_popup_holo.9.png b/java/res/drawable-mdpi/hint_popup_holo.9.png
new file mode 100644
index 0000000..c409cea
--- /dev/null
+++ b/java/res/drawable-mdpi/hint_popup_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_subtype_keyboard.png b/java/res/drawable-mdpi/ic_subtype_keyboard.png
deleted file mode 100644
index 0d7ebd4..0000000
--- a/java/res/drawable-mdpi/ic_subtype_keyboard.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_subtype_mic.png b/java/res/drawable-mdpi/ic_subtype_mic.png
deleted file mode 100644
index 247d5b3..0000000
--- a/java/res/drawable-mdpi/ic_subtype_mic.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_at_holo.9.png b/java/res/drawable-mdpi/key_hint_at_holo.9.png
new file mode 100644
index 0000000..627e7a0
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_at_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_at_large_holo.9.png b/java/res/drawable-mdpi/key_hint_at_large_holo.9.png
new file mode 100644
index 0000000..9569217
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_at_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_colon_holo.9.png b/java/res/drawable-mdpi/key_hint_colon_holo.9.png
new file mode 100644
index 0000000..14c4699
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_colon_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_colon_large_holo.9.png b/java/res/drawable-mdpi/key_hint_colon_large_holo.9.png
new file mode 100644
index 0000000..91e7883
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_colon_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_comma_holo.9.png b/java/res/drawable-mdpi/key_hint_comma_holo.9.png
new file mode 100644
index 0000000..82e4a93
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_comma_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_dash_holo.9.png b/java/res/drawable-mdpi/key_hint_dash_holo.9.png
new file mode 100644
index 0000000..2ee22ba
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_dash_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_doublecross_holo.9.png b/java/res/drawable-mdpi/key_hint_doublecross_holo.9.png
new file mode 100644
index 0000000..0da9332
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_doublecross_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_equal_holo.9.png b/java/res/drawable-mdpi/key_hint_equal_holo.9.png
new file mode 100644
index 0000000..f5a9ba2
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_equal_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_exclamation_holo.9.png b/java/res/drawable-mdpi/key_hint_exclamation_holo.9.png
new file mode 100644
index 0000000..89c5aae
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_exclamation_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_exclamation_large_holo.9.png b/java/res/drawable-mdpi/key_hint_exclamation_large_holo.9.png
new file mode 100644
index 0000000..932bcb9
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_exclamation_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_larger_holo.9.png b/java/res/drawable-mdpi/key_hint_larger_holo.9.png
new file mode 100644
index 0000000..50652bb
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_larger_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_parenclose_holo.9.png b/java/res/drawable-mdpi/key_hint_parenclose_holo.9.png
new file mode 100644
index 0000000..52ee86a
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_parenclose_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_parenopen_holo.9.png b/java/res/drawable-mdpi/key_hint_parenopen_holo.9.png
new file mode 100644
index 0000000..b0ed388
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_parenopen_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_period_holo.9.png b/java/res/drawable-mdpi/key_hint_period_holo.9.png
new file mode 100644
index 0000000..8d798a5
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_period_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_plus_holo.9.png b/java/res/drawable-mdpi/key_hint_plus_holo.9.png
new file mode 100644
index 0000000..f1d232e
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_plus_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_plus_large_holo.9.png b/java/res/drawable-mdpi/key_hint_plus_large_holo.9.png
new file mode 100644
index 0000000..5f7d315
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_plus_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_question_holo.9.png b/java/res/drawable-mdpi/key_hint_question_holo.9.png
new file mode 100644
index 0000000..8373b69
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_question_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_question_large_holo.9.png b/java/res/drawable-mdpi/key_hint_question_large_holo.9.png
new file mode 100644
index 0000000..a9eaeea
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_question_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_quote_holo.9.png b/java/res/drawable-mdpi/key_hint_quote_holo.9.png
new file mode 100644
index 0000000..01a3a9a
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_quote_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_quote_large_holo.9.png b/java/res/drawable-mdpi/key_hint_quote_large_holo.9.png
new file mode 100644
index 0000000..7cba264
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_quote_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_semicolon_holo.9.png b/java/res/drawable-mdpi/key_hint_semicolon_holo.9.png
new file mode 100644
index 0000000..7f9e8c9
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_semicolon_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_simplequote_holo.9.png b/java/res/drawable-mdpi/key_hint_simplequote_holo.9.png
new file mode 100644
index 0000000..5e1a45c
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_simplequote_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_slash_holo.9.png b/java/res/drawable-mdpi/key_hint_slash_holo.9.png
new file mode 100644
index 0000000..645586a
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_slash_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_slash_large_holo.9.png b/java/res/drawable-mdpi/key_hint_slash_large_holo.9.png
new file mode 100644
index 0000000..75c3bb1
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_slash_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_smaller_holo.9.png b/java/res/drawable-mdpi/key_hint_smaller_holo.9.png
new file mode 100644
index 0000000..2a0587c
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_smaller_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_star_holo.9.png b/java/res/drawable-mdpi/key_hint_star_holo.9.png
new file mode 100644
index 0000000..9f33b98
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_star_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_underline_holo.9.png b/java/res/drawable-mdpi/key_hint_underline_holo.9.png
new file mode 100644
index 0000000..a95a575
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_underline_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/key_hint_underline_large_holo.9.png b/java/res/drawable-mdpi/key_hint_underline_large_holo.9.png
new file mode 100644
index 0000000..bef74c1
--- /dev/null
+++ b/java/res/drawable-mdpi/key_hint_underline_large_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_background_holo.9.png b/java/res/drawable-mdpi/keyboard_background_holo.9.png
new file mode 100644
index 0000000..0ea57c0
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_at.9.png b/java/res/drawable-mdpi/keyboard_hint_at.9.png
new file mode 100644
index 0000000..69baede
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_at.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_colon.9.png b/java/res/drawable-mdpi/keyboard_hint_colon.9.png
new file mode 100644
index 0000000..9d0d7cb
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_colon.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_doublecross.9.png b/java/res/drawable-mdpi/keyboard_hint_doublecross.9.png
new file mode 100644
index 0000000..d24aa0f
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_doublecross.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_exclamation.9.png b/java/res/drawable-mdpi/keyboard_hint_exclamation.9.png
new file mode 100644
index 0000000..f6cc7fe
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_exclamation.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_greater.9.png b/java/res/drawable-mdpi/keyboard_hint_greater.9.png
new file mode 100644
index 0000000..5210392
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_greater.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_plus.9.png b/java/res/drawable-mdpi/keyboard_hint_plus.9.png
new file mode 100644
index 0000000..d1d85ac
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_plus.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_question.9.png b/java/res/drawable-mdpi/keyboard_hint_question.9.png
new file mode 100644
index 0000000..37f6e5f
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_question.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_quote.9.png b/java/res/drawable-mdpi/keyboard_hint_quote.9.png
new file mode 100644
index 0000000..e7d2cb5
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_quote.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_smaller.9.png b/java/res/drawable-mdpi/keyboard_hint_smaller.9.png
new file mode 100644
index 0000000..76553cf
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_smaller.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_hint_star.9.png b/java/res/drawable-mdpi/keyboard_hint_star.9.png
new file mode 100644
index 0000000..47978c4
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_hint_star.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_background_holo.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_background_holo.9.png
new file mode 100644
index 0000000..a7acb4a
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_key_feedback_more_background_holo.9.png b/java/res/drawable-mdpi/keyboard_key_feedback_more_background_holo.9.png
new file mode 100644
index 0000000..8cfd7cf
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_key_feedback_more_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/keyboard_popup_panel_background_holo.9.png b/java/res/drawable-mdpi/keyboard_popup_panel_background_holo.9.png
new file mode 100644
index 0000000..c5d938d
--- /dev/null
+++ b/java/res/drawable-mdpi/keyboard_popup_panel_background_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/mic_slash_holo.png b/java/res/drawable-mdpi/mic_slash_holo.png
new file mode 100644
index 0000000..8108b6e
--- /dev/null
+++ b/java/res/drawable-mdpi/mic_slash_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ok_cancel_holo.9.png b/java/res/drawable-mdpi/ok_cancel_holo.9.png
new file mode 100644
index 0000000..5eb078c
--- /dev/null
+++ b/java/res/drawable-mdpi/ok_cancel_holo.9.png
Binary files differ
diff --git a/java/res/drawable-mdpi/speak_now_level0_holo.png b/java/res/drawable-mdpi/speak_now_level0_holo.png
new file mode 100644
index 0000000..2a4fbd8
--- /dev/null
+++ b/java/res/drawable-mdpi/speak_now_level0_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/speak_now_level1_holo.png b/java/res/drawable-mdpi/speak_now_level1_holo.png
new file mode 100644
index 0000000..dd35b18
--- /dev/null
+++ b/java/res/drawable-mdpi/speak_now_level1_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/speak_now_level2_holo.png b/java/res/drawable-mdpi/speak_now_level2_holo.png
new file mode 100644
index 0000000..e3e42c4
--- /dev/null
+++ b/java/res/drawable-mdpi/speak_now_level2_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/speak_now_level3_holo.png b/java/res/drawable-mdpi/speak_now_level3_holo.png
new file mode 100644
index 0000000..7cf104e
--- /dev/null
+++ b/java/res/drawable-mdpi/speak_now_level3_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/speak_now_level4_holo.png b/java/res/drawable-mdpi/speak_now_level4_holo.png
new file mode 100644
index 0000000..baad6ca
--- /dev/null
+++ b/java/res/drawable-mdpi/speak_now_level4_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/speak_now_level5_holo.png b/java/res/drawable-mdpi/speak_now_level5_holo.png
new file mode 100644
index 0000000..34c161e
--- /dev/null
+++ b/java/res/drawable-mdpi/speak_now_level5_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/speak_now_level6_holo.png b/java/res/drawable-mdpi/speak_now_level6_holo.png
new file mode 100644
index 0000000..e6b26d1
--- /dev/null
+++ b/java/res/drawable-mdpi/speak_now_level6_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_delete_holo.png b/java/res/drawable-mdpi/sym_keyboard_delete_holo.png
new file mode 100644
index 0000000..9f1bfe8
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_delete_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_num0_holo.png b/java/res/drawable-mdpi/sym_keyboard_num0_holo.png
new file mode 100644
index 0000000..2bb2a8b
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_num0_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_num1_holo.png b/java/res/drawable-mdpi/sym_keyboard_num1_holo.png
new file mode 100644
index 0000000..0e05537
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_num1_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_num2_holo.png b/java/res/drawable-mdpi/sym_keyboard_num2_holo.png
new file mode 100644
index 0000000..3b2a550
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_num2_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_num3_holo.png b/java/res/drawable-mdpi/sym_keyboard_num3_holo.png
new file mode 100644
index 0000000..0d829bf
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_num3_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_num4_holo.png b/java/res/drawable-mdpi/sym_keyboard_num4_holo.png
new file mode 100644
index 0000000..d676a1c
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_num4_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_num5_holo.png b/java/res/drawable-mdpi/sym_keyboard_num5_holo.png
new file mode 100644
index 0000000..d47f2d5
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_num5_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_num6_holo.png b/java/res/drawable-mdpi/sym_keyboard_num6_holo.png
new file mode 100644
index 0000000..8e9138e
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_num6_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_num7_holo.png b/java/res/drawable-mdpi/sym_keyboard_num7_holo.png
new file mode 100644
index 0000000..7453b6b
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_num7_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_num8_holo.png b/java/res/drawable-mdpi/sym_keyboard_num8_holo.png
new file mode 100644
index 0000000..b59885f
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_num8_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_num9_holo.png b/java/res/drawable-mdpi/sym_keyboard_num9_holo.png
new file mode 100644
index 0000000..db465f7
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_num9_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_numbpound_holo.png b/java/res/drawable-mdpi/sym_keyboard_numbpound_holo.png
new file mode 100644
index 0000000..32f736c
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_numbpound_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_numbstar_holo.png b/java/res/drawable-mdpi/sym_keyboard_numbstar_holo.png
new file mode 100644
index 0000000..4fe9e6a
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_numbstar_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_return_holo.png b/java/res/drawable-mdpi/sym_keyboard_return_holo.png
new file mode 100644
index 0000000..695a163
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_return_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_shift_holo.png b/java/res/drawable-mdpi/sym_keyboard_shift_holo.png
new file mode 100644
index 0000000..8f5db5d
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_shift_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_shift_lock.png b/java/res/drawable-mdpi/sym_keyboard_shift_lock.png
deleted file mode 100644
index 244179c..0000000
--- a/java/res/drawable-mdpi/sym_keyboard_shift_lock.png
+++ /dev/null
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_shift_locked_holo.png b/java/res/drawable-mdpi/sym_keyboard_shift_locked_holo.png
new file mode 100644
index 0000000..0305827
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_shift_locked_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_smiley_holo.png b/java/res/drawable-mdpi/sym_keyboard_smiley_holo.png
new file mode 100644
index 0000000..302ea0f
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_smiley_holo.png
Binary files differ
diff --git a/java/res/drawable-mdpi/sym_keyboard_space_holo.png b/java/res/drawable-mdpi/sym_keyboard_space_holo.png
new file mode 100644
index 0000000..ec21a4f
--- /dev/null
+++ b/java/res/drawable-mdpi/sym_keyboard_space_holo.png
Binary files differ
diff --git a/java/res/drawable/btn_keyboard_key_honeycomb.xml b/java/res/drawable/btn_keyboard_key_honeycomb.xml
new file mode 100644
index 0000000..3dab843
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_key_honeycomb.xml
@@ -0,0 +1,43 @@
+<?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.
+-->
+
+<!-- TODO: Remove "gingerbread" from file name and rename this to "btn_keyboard_key.xml". -->
+<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_holo" />
+    <item android:state_single="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_normal_holo" />
+
+    <!-- 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_holo" />
+    <item android:state_checkable="true" android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_pressed_off_holo" />
+    <item android:state_checkable="true" android:state_checked="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_normal_on_holo" />
+    <item android:state_checkable="true"
+          android:drawable="@drawable/btn_keyboard_key_dark_normal_off_holo" />
+
+    <!-- Normal keys -->
+
+    <item android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_light_pressed_holo" />
+    <item android:drawable="@drawable/btn_keyboard_key_light_normal_holo" />
+</selector>
diff --git a/java/res/drawable/btn_keyboard_key_honeycomb_popup.xml b/java/res/drawable/btn_keyboard_key_honeycomb_popup.xml
new file mode 100644
index 0000000..6c27136
--- /dev/null
+++ b/java/res/drawable/btn_keyboard_key_honeycomb_popup.xml
@@ -0,0 +1,20 @@
+<?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">
+    <item android:state_pressed="true"
+          android:drawable="@drawable/btn_keyboard_key_popup_selected_holo" />
+</selector>
diff --git a/java/res/drawable/ic_subtype_keyboard.png b/java/res/drawable/ic_subtype_keyboard.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_cs.png b/java/res/drawable/ic_subtype_keyboard_cs.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_cs.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_da.png b/java/res/drawable/ic_subtype_keyboard_da.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_da.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_de.png b/java/res/drawable/ic_subtype_keyboard_de.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_de.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_en_gb.png b/java/res/drawable/ic_subtype_keyboard_en_gb.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_en_gb.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_en_us.png b/java/res/drawable/ic_subtype_keyboard_en_us.png
new file mode 100644
index 0000000..8ed6cc8
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_en_us.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_es.png b/java/res/drawable/ic_subtype_keyboard_es.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_es.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_es_us.png b/java/res/drawable/ic_subtype_keyboard_es_us.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_es_us.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_fr.png b/java/res/drawable/ic_subtype_keyboard_fr.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_fr.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_fr_ca.png b/java/res/drawable/ic_subtype_keyboard_fr_ca.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_fr_ca.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_fr_ch.png b/java/res/drawable/ic_subtype_keyboard_fr_ch.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_fr_ch.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_it.png b/java/res/drawable/ic_subtype_keyboard_it.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_it.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_nb.png b/java/res/drawable/ic_subtype_keyboard_nb.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_nb.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_nl.png b/java/res/drawable/ic_subtype_keyboard_nl.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_nl.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_ru.png b/java/res/drawable/ic_subtype_keyboard_ru.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_ru.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_sr.png b/java/res/drawable/ic_subtype_keyboard_sr.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_sr.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_keyboard_sv.png b/java/res/drawable/ic_subtype_keyboard_sv.png
new file mode 100644
index 0000000..ef5fe4b
--- /dev/null
+++ b/java/res/drawable/ic_subtype_keyboard_sv.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic.png b/java/res/drawable/ic_subtype_mic.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_cs.png b/java/res/drawable/ic_subtype_mic_cs.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_cs.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_de.png b/java/res/drawable/ic_subtype_mic_de.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_de.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_en_au.png b/java/res/drawable/ic_subtype_mic_en_au.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_en_au.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_en_gb.png b/java/res/drawable/ic_subtype_mic_en_gb.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_en_gb.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_en_in.png b/java/res/drawable/ic_subtype_mic_en_in.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_en_in.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_en_nz.png b/java/res/drawable/ic_subtype_mic_en_nz.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_en_nz.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_en_us.png b/java/res/drawable/ic_subtype_mic_en_us.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_en_us.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_es.png b/java/res/drawable/ic_subtype_mic_es.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_es.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_fr.png b/java/res/drawable/ic_subtype_mic_fr.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_fr.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_ja.png b/java/res/drawable/ic_subtype_mic_ja.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_ja.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_ko.png b/java/res/drawable/ic_subtype_mic_ko.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_ko.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_pl.png b/java/res/drawable/ic_subtype_mic_pl.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_pl.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_pt.png b/java/res/drawable/ic_subtype_mic_pt.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_pt.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_ru.png b/java/res/drawable/ic_subtype_mic_ru.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_ru.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_tr.png b/java/res/drawable/ic_subtype_mic_tr.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_tr.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_zh_cn.png b/java/res/drawable/ic_subtype_mic_zh_cn.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_zh_cn.png
Binary files differ
diff --git a/java/res/drawable/ic_subtype_mic_zh_tw.png b/java/res/drawable/ic_subtype_mic_zh_tw.png
new file mode 100644
index 0000000..03c0b69
--- /dev/null
+++ b/java/res/drawable/ic_subtype_mic_zh_tw.png
Binary files differ
diff --git a/java/res/drawable/keyboard_key_feedback_honeycomb.xml b/java/res/drawable/keyboard_key_feedback_honeycomb.xml
new file mode 100644
index 0000000..dd9b53e
--- /dev/null
+++ b/java/res/drawable/keyboard_key_feedback_honeycomb.xml
@@ -0,0 +1,21 @@
+<?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">
+    <item android:state_long_pressable="true"
+            android:drawable="@drawable/keyboard_key_feedback_more_background" />
+    <item android:drawable="@drawable/keyboard_key_feedback_background_holo" />
+</selector>
diff --git a/java/res/layout-xlarge/keyboard_popup_honeycomb.xml b/java/res/layout-xlarge/keyboard_popup_honeycomb.xml
new file mode 100644
index 0000000..0b8229c
--- /dev/null
+++ b/java/res/layout-xlarge/keyboard_popup_honeycomb.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:background="@drawable/keyboard_popup_panel_background_holo"
+        android:paddingLeft="40dip"
+        android:paddingRight="40dip"
+        >
+    <com.android.inputmethod.keyboard.KeyboardView
+            xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+            android:id="@+id/KeyboardView"
+            android:layout_alignParentBottom="true"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:background="@color/latinkeyboard_transparent"
+
+            latin:keyBackground="@drawable/btn_keyboard_key_honeycomb_popup"
+            latin:keyHysteresisDistance="0dip"
+            latin:verticalCorrection="@dimen/mini_keyboard_vertical_correction"
+            />
+</LinearLayout>
diff --git a/java/res/layout/input_basic.xml b/java/res/layout/input_basic.xml
index 168eba6..7b85bae 100644
--- a/java/res/layout/input_basic.xml
+++ b/java/res/layout/input_basic.xml
@@ -18,7 +18,7 @@
 */
 -->
 
-<com.android.inputmethod.latin.LatinKeyboardView
+<com.android.inputmethod.keyboard.LatinKeyboardView
         xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
         android:id="@+id/LatinkeyboardBaseView"
diff --git a/java/res/layout/input_basic_highcontrast.xml b/java/res/layout/input_basic_highcontrast.xml
index 19ff1db..d9200fd 100644
--- a/java/res/layout/input_basic_highcontrast.xml
+++ b/java/res/layout/input_basic_highcontrast.xml
@@ -18,7 +18,7 @@
 */
 -->
 
-<com.android.inputmethod.latin.LatinKeyboardView
+<com.android.inputmethod.keyboard.LatinKeyboardView
         xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
 
diff --git a/java/res/layout/input_gingerbread.xml b/java/res/layout/input_gingerbread.xml
index 73cf0a3..6233e6d 100644
--- a/java/res/layout/input_gingerbread.xml
+++ b/java/res/layout/input_gingerbread.xml
@@ -18,17 +18,17 @@
 */
 -->
 
-<com.android.inputmethod.latin.LatinKeyboardView
+<com.android.inputmethod.keyboard.LatinKeyboardView
         xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
         android:id="@+id/LatinkeyboardBaseView"
         android:layout_alignParentBottom="true"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
+        android:paddingTop="@dimen/keyboard_top_padding"
         android:paddingBottom="@dimen/keyboard_bottom_padding"
         android:background="@drawable/keyboard_dark_background"
-        android:textStyle="bold"
 
         latin:keyBackground="@drawable/btn_keyboard_key_gingerbread"
-        latin:keyTextStyle="bold"
+        latin:keyLetterStyle="bold"
         />
diff --git a/java/res/layout/input_honeycomb.xml b/java/res/layout/input_honeycomb.xml
new file mode 100644
index 0000000..b393874
--- /dev/null
+++ b/java/res/layout/input_honeycomb.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<com.android.inputmethod.keyboard.LatinKeyboardView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+        android:id="@+id/LatinkeyboardBaseView"
+        android:layout_alignParentBottom="true"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingTop="@dimen/keyboard_top_padding"
+        android:paddingBottom="@dimen/keyboard_bottom_padding"
+        android:background="@drawable/keyboard_background_holo"
+
+        latin:keyBackground="@drawable/btn_keyboard_key_honeycomb"
+        latin:keyPreviewLayout="@layout/key_preview_honeycomb"
+        latin:popupLayout="@layout/keyboard_popup_honeycomb"
+        latin:keyTextColorDisabled="#FF353535"
+        latin:keyLetterStyle="bold"
+        latin:shadowColor="#00000000"
+        latin:shadowRadius="0.0"
+        />
diff --git a/java/res/layout/input_stone_bold.xml b/java/res/layout/input_stone_bold.xml
index e3588bb..bf25e15 100644
--- a/java/res/layout/input_stone_bold.xml
+++ b/java/res/layout/input_stone_bold.xml
@@ -18,7 +18,7 @@
 */
 -->
 
-<com.android.inputmethod.latin.LatinKeyboardView
+<com.android.inputmethod.keyboard.LatinKeyboardView
         xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
         android:id="@+id/LatinkeyboardBaseView"
@@ -26,12 +26,11 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:background="@drawable/keyboard_background"
-        android:textStyle="bold"
 
         latin:keyBackground="@drawable/btn_keyboard_key_stone"
         latin:keyTextColor="@color/latinkeyboard_key_color_black"
         latin:shadowColor="@color/latinkeyboard_key_color_white"
-        latin:keyTextStyle="bold"
-        latin:symbolColorScheme="black"
+        latin:keyLetterStyle="bold"
+        latin:colorScheme="black"
         latin:popupLayout="@layout/input_stone_popup"
         />
diff --git a/java/res/layout/input_stone_normal.xml b/java/res/layout/input_stone_normal.xml
index fd7bf85..cf47086 100644
--- a/java/res/layout/input_stone_normal.xml
+++ b/java/res/layout/input_stone_normal.xml
@@ -18,7 +18,7 @@
 */
 -->
 
-<com.android.inputmethod.latin.LatinKeyboardView
+<com.android.inputmethod.keyboard.LatinKeyboardView
         xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
         android:id="@+id/LatinkeyboardBaseView"
@@ -30,6 +30,6 @@
         latin:keyBackground="@drawable/btn_keyboard_key_stone"
         latin:keyTextColor="@color/latinkeyboard_key_color_black"
         latin:shadowColor="@color/latinkeyboard_key_color_white"
-        latin:symbolColorScheme="black"
+        latin:colorScheme="black"
         latin:popupLayout="@layout/input_stone_popup"
         />
diff --git a/java/res/layout/input_stone_popup.xml b/java/res/layout/input_stone_popup.xml
index f159625..b4da045 100644
--- a/java/res/layout/input_stone_popup.xml
+++ b/java/res/layout/input_stone_popup.xml
@@ -25,9 +25,9 @@
         android:orientation="horizontal"
         android:background="@drawable/keyboard_popup_panel_background"
         >
-    <com.android.inputmethod.latin.LatinKeyboardBaseView
+    <com.android.inputmethod.keyboard.KeyboardView
             xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
-            android:id="@+id/LatinKeyboardBaseView"
+            android:id="@+id/KeyboardView"
             android:layout_alignParentBottom="true"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/java/res/layout/key_preview_honeycomb.xml b/java/res/layout/key_preview_honeycomb.xml
new file mode 100644
index 0000000..a90fe55
--- /dev/null
+++ b/java/res/layout/key_preview_honeycomb.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="80sp"
+    android:textSize="40sp"
+    android:textColor="@color/latinkeyboard_key_color_white"
+    android:minWidth="24dip"
+    android:gravity="center"
+    android:background="@drawable/keyboard_key_feedback_honeycomb"
+    />
diff --git a/java/res/layout/keyboard_popup.xml b/java/res/layout/keyboard_popup.xml
index 9ecbcd4..ac8134b 100644
--- a/java/res/layout/keyboard_popup.xml
+++ b/java/res/layout/keyboard_popup.xml
@@ -26,9 +26,9 @@
         android:paddingLeft="16dip"
         android:paddingRight="16dip"
         >
-    <com.android.inputmethod.latin.LatinKeyboardBaseView
+    <com.android.inputmethod.keyboard.KeyboardView
             xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
-            android:id="@+id/LatinKeyboardBaseView"
+            android:id="@+id/KeyboardView"
             android:layout_alignParentBottom="true"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/java/res/layout/keyboard_popup_honeycomb.xml b/java/res/layout/keyboard_popup_honeycomb.xml
new file mode 100644
index 0000000..e5fcbd4
--- /dev/null
+++ b/java/res/layout/keyboard_popup_honeycomb.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:background="@drawable/keyboard_popup_panel_background_holo"
+        android:paddingLeft="24dip"
+        android:paddingRight="24dip"
+        >
+    <com.android.inputmethod.keyboard.KeyboardView
+            xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+            android:id="@+id/KeyboardView"
+            android:layout_alignParentBottom="true"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:background="@color/latinkeyboard_transparent"
+
+            latin:keyBackground="@drawable/btn_keyboard_key_honeycomb_popup"
+            latin:keyHysteresisDistance="0dip"
+            latin:verticalCorrection="@dimen/mini_keyboard_vertical_correction"
+            />
+</LinearLayout>
diff --git a/java/res/layout/recognition_status.xml b/java/res/layout/recognition_status.xml
index 49af773..ea2d9ee 100644
--- a/java/res/layout/recognition_status.xml
+++ b/java/res/layout/recognition_status.xml
@@ -57,7 +57,7 @@
         android:layout_width="wrap_content"
         android:layout_marginTop="20dip"
         android:layout_gravity="center_horizontal"
-        android:src="@drawable/mic_slash"
+        android:src="@drawable/mic_slash_holo"
     />
 
     <ProgressBar android:id="@+id/progress"
diff --git a/java/res/raw/main.dict b/java/res/raw/main.dict
old mode 100755
new mode 100644
Binary files differ
diff --git a/java/res/raw/type3.ogg b/java/res/raw/type3.ogg
old mode 100755
new mode 100644
Binary files differ
diff --git a/java/res/values-ar/config.xml b/java/res/values-ar/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-ar/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
new file mode 100644
index 0000000..5a8f97b
--- /dev/null
+++ b/java/res/values-ar/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"لوحة مفاتيح Android"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"إعدادات لوحة مفاتيح Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"اهتزاز عند الضغط على مفتاح"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"صوت عند الضغط على مفتاح"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"تصحيح أخطاء الكتابة"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"تمكين تصحيح خطأ الإدخال"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"أخطاء في الإدخال الأفقي"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"تمكين تصحيح خطأ الإدخال"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"اقتراحات الكلمات"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"تصحيح الكلمة السابقة تلقائيًا"</string>
+    <string name="prediction" msgid="466220283138359837">"اقتراحات الكلمات"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"إعدادات اقتراحات الكلمات"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"تمكين الإكمال التلقائي أثناء الكتابة"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"إكمال تلقائي"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"زيادة حجم الحقل النصي"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"إخفاء اقتراحات الكلمات في طريقة العرض الأفقية"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"استخدام الأحرف الكبيرة تلقائيًا"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"استخدام الأحرف الكبيرة في بداية الجملة"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"ترقيم تلقائي"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"إصلاحات سريعة"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"تصحيح الأخطاء المكتوبة الشائعة"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"إكمال تلقائي"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"مفتاح المسافة والترقيم لإدخال كلمة محددة تلقائيًا"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"لا شيء"</item>
+    <item msgid="1669461741568287396">"أساسي"</item>
+    <item msgid="4894328801530136615">"متقدم"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : تم الحفظ"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"اضغط باستمرار على أحد المفاتيح لأسفل لمشاهدة علامات التشكيل"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"اضغط على مفتاح الرجوع ↶ لإغلاق لوحة المفاتيح في أي نقطة"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"الدخول إلى الأرقام والرموز"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"اضغط مع الاستمرار على أقصى يمين الكلمة لإضافتها إلى القاموس"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"المس هذا التلميح للمتابعة »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"المس هنا لإغلاق هذا التلميح وبدء الكتابة!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"تفتح لوحة المفاتيح في أي وقت تلمس فيه حقلًا نصيًا"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"المس مع الاستمرار أحد المفاتيح لعرض علامات التشكيل"\n"(ø, ö, ô, ó, وهكذا)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"التبديل إلى الأرقام والرموز من خلال لمس هذا الزر"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"يمكنك الرجوع إلى الأحرف من خلال لمس هذا المفتاح مرة أخرى"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"المس هذا المفتاح مع الاستمرار لتغيير إعدادات لوحة المفاتيح، مثل الإكمال التلقائي"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"جربه!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"تنفيذ"</string>
+    <string name="label_next_key" msgid="362972844525672568">"التالي"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"تم"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"إرسال"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"الإدخال الصوتي"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"الإدخال الصوتي غير معتمد حاليًا للغتك، ولكنه يعمل باللغة الإنجليزية."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"الإدخال الصوتي هو ميزة تجريبية تستخدم التعرف على الكلام المتصل في Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"لتشغيل الإدخال الصوتي، انتقل إلى إعدادات لوحة المفاتيح."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"لاستخدام الإدخال الصوتي، اضغط على زر الميكروفون أو مرر إصبعك عبر لوحة المفاتيح على الشاشة."</string>
+    <string name="voice_listening" msgid="467518160751321844">"تحدث الآن"</string>
+    <string name="voice_working" msgid="6666937792815731889">"العمل"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"خطأ. الرجاء المحاولة مرة أخرى."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"تعذر الاتصال"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"خطأ، كلام أكثر مما ينبغي."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"مشكلة بالإعدادات الصوتية"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"خطأ في الخادم"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"لم يتم سماع كلام"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"لم يتمّ العثور على أية تطابقات"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"لم يتم تثبيت البحث الصوتي"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"تلميح:"</b>" مرر عبر لوحة المفاتيح للتحدث"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"تلميح:"</b>" جرب في المرة التالية نطق الترقيم مثل \"نقطة\" أو \"فاصلة\" أو \"علامة استفهام\"."</string>
+    <string name="cancel" msgid="6830980399865683324">"إلغاء"</string>
+    <string name="ok" msgid="7898366843681727667">"موافق"</string>
+    <string name="voice_input" msgid="2466640768843347841">"الإدخال الصوتي"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"في لوحة المفاتيح الرئيسية"</item>
+    <item msgid="8529385602829095903">"على لوحة مفاتيح الرموز"</item>
+    <item msgid="7283103513488381103">"إيقاف"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"الميكروفون في لوحة المفاتيح الرئيسية"</item>
+    <item msgid="6907837061058876770">"الميكروفون على لوحة مفاتيح الرموز"</item>
+    <item msgid="3664304608587798036">"تم تعطيل الإدخال الصوتي"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"إرسال تلقائي بعد الصوت"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"الضغط تلقائيًا على المفتاح enter عند البحث أو الانتقال إلى الحقل التالي."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"افتح لوحة المفاتيح"\n</b></font><font size="3">\n</font>"المس أي حقل نصي."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"إغلاق لوحة المفاتيح"\n</b></font><font size="3">\n</font>"اضغط على المفتاح \"رجوع\"."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"المس أحد مفاتيح الخيارات مع الاستمرار"\n</b></font><font size="3">\n</font>"الدخول إلى الترقيم والحركات."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"إعدادات لوحة المفاتيح"\n</b></font><font size="3">\n</font>"المس مع الاستمرار المفتاح "<b>"?123"</b>"."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">"com."</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">"net."</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">"org."</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">"gov."</string>
+    <string name="popular_domain_4" msgid="35359437471311470">"edu."</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"لغات الإدخال"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"مرر إصبعك على مفتاح المسافة لتغيير اللغة"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← انقر مرة أخرى للحفظ"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"القاموس متاح"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-bg/config.xml b/java/res/values-bg/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-bg/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
new file mode 100644
index 0000000..3c1cccb
--- /dev/null
+++ b/java/res/values-bg/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Клавиатура на Android"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Настройки на клавиатурата на Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Да вибрира при натискане на клавиш"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Звук при натискане на клавиш"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Коригиране на грешките при въвеждане"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Активиране на корекция на грешки при въвеждане"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Грешки при въвеждане в хоризонтален изглед"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Активиране на корекция на грешки при въвеждане"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Предложения на думи"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Автоматично коригиране на предишната дума"</string>
+    <string name="prediction" msgid="466220283138359837">"Предложения на думи"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Настройки за предложения на думи"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Активиране на автодовършване, докато пишете"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Автодовършване"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Размерът на текстовото поле да се увеличи"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Скриване на предложенията на думи в хоризонтален изглед"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Автоматично поставяне на главни букви"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Поставя главна буква в началото на изреченията"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Автоматично поставяне на пунктуация"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Бързи корекции"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Коригира най-честите грешки при въвеждане"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Автоматично завършване"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Клавишът за интервал и пунктуация поставя автоматично откроена дума"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Няма"</item>
+    <item msgid="1669461741568287396">"Основен"</item>
+    <item msgid="4894328801530136615">"Разширени"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Запазено"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Задръжте клавиша, за да видите ударенията (ø, ö и т.н.)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Натиснете клавиша „Назад“ ↶, за да затворите клавиатурата във всяка една точка"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Достъп до номера и символи"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Натиснете и задръжте върху най-лявата дума, за да я добавите към речника"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Докоснете съвета, за да продължите »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Докоснете тук, за да затворите този съвет и да започнете да пишете!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Клавиатурата се отваря при всяко докосване на текстово поле"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Докоснете и задръжте клавиша, за да видите ударенията"\n"(ø, ö, ô, ó и т.н.)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Докосването на този клавиш води до преминаване към цифри и символи"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Върнете се към използване на букви чрез повторно докосване на този клавиш"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Докоснете и задръжте клавиша за промяна на настройките на клавиатурата, напр. автодовършване"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Пробвайте!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Старт"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Напред"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Изпращане"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Гласово въвеждане"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"За вашия език понастоящем не се поддържа гласово въвеждане, но можете да го използвате на английски."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Гласовото въвеждане е експериментална функция, използваща разпознаването на реч в мрежата на Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"За да изключите гласовото въвеждане, отворете настройките на клавиатурата."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"За да използвате гласово въвеждане, натиснете бутона на микрофона или плъзнете пръст през екранната клавиатура."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Говорете сега"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Обработва се"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Грешка. Моля, опитайте отново."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Не можа да се свърже"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Грешка, твърде много речева информация."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Аудиопроблем"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Грешка в сървъра"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Не се чува реч"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Нямаше съответствия"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Не е инсталирано гласово търсене"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Съвет:"</b>" Прокарайте палец през клавиатурата, за да говорите"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Съвет:"</b>" Следващия път опитайте да произнесете знаците за пунктуация, напр. „точка“, „запетая“ или „въпросителен знак“."</string>
+    <string name="cancel" msgid="6830980399865683324">"Отказ"</string>
+    <string name="ok" msgid="7898366843681727667">"OK"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Гласово въвеждане"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"На основната клавиатура"</item>
+    <item msgid="8529385602829095903">"На клавиатурата на символите"</item>
+    <item msgid="7283103513488381103">"Изкл."</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Микрофон на основната клавиатура"</item>
+    <item msgid="6907837061058876770">"Микрофон на клавиатурата на символите"</item>
+    <item msgid="3664304608587798036">"Гласовото въвеждане е деактивирано"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Автоматично изпращане след глас"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Да се натиска автоматично „Enter“ при търсене или преминаване към следващото поле."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Отворете клавиатурата"\n</b></font><font size="3">\n</font>"Докоснете текстово поле."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Затваряне на клавиатурата"\n</b></font><font size="3">\n</font>"Натиснете клавиша „Назад“."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Докоснете и задръжте клавиш за опции"\n</b></font><font size="3">\n</font>"Използвайте пунктуация и акценти."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Настройки на клавиатурата"\n</b></font><font size="3">\n</font>"Докоснете и задръжте клавиша "<b>"?123"</b>"."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Входни езици"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Плъзнете пръст по клавиша за интервал за промяна на езика"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Докоснете отново, за да запазите"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Има достъп до речник"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-ca/config.xml b/java/res/values-ca/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-ca/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
new file mode 100644
index 0000000..2cdbfe1
--- /dev/null
+++ b/java/res/values-ca/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Teclat Android"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Configuració del teclat d\'Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibra en prémer tecles"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"So en prémer una tecla"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Corregeix els errors ortogràfics"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Activa la correcció d\'errors d\'entrada"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Errors d\'entrada en horitzontal"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Activa la correcció d\'errors d\'entrada"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Suggeriments de paraules"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Corregeix automàticament la paraula anterior"</string>
+    <string name="prediction" msgid="466220283138359837">"Suggeriments de paraules"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Configuració de suggeriment de paraules"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Activa l\'emplenament automàtic mentre s\'escriu"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Emplenament automàtic"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Augmenta la mida del camp de text"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Oculta els suggeriments de paraules en visualització horitzontal"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Majúscules automàtiques"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Posa l\'inici d\'una frase en majúscula"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Puntuació automàtica"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Correccions ràpides"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Corregeix els errors d\'ortografia habituals"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Emplenament automàtic"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"La barra espaiadora i la puntuació insereixen automàticament la paraula ressaltada"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Cap"</item>
+    <item msgid="1669461741568287396">"Bàsic"</item>
+    <item msgid="4894328801530136615">"Avançat"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: desada"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Manteniu una tecla premuda per veure\'n les variants (ø, ö, etc.)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Premeu la tecla Enrere ↶ per tancar el teclat en qualsevol moment"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Accedeix a números i símbols"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Manteniu premuda la paraula de l\'extrem esquerre per afegir-la al diccionari"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Toqueu aquest suggeriment per continuar »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Toqueu aquí per tancar aquest suggeriment i començar a escriure."</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"S\'obre el teclat cada vegada que toqueu un camp de text"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Manteniu premuda una tecla per veure\'n les variants"\n"(ø, ö, ô, ó, etc.)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Toqueu aquesta tecla per canviar als números i als símbols"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Torneu a tocar aquesta tecla per tornar a les lletres"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Manteniu premuda aquesta tecla per canviar la configuració del teclat, com ara l\'emplenament automàtic"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Proveu-ho!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Vés"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Següent"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Fet"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Envia"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Entrada de veu"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Actualment, l\'entrada de veu no és compatible amb el vostre idioma, però funciona en anglès."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"L\'entrada de veu és una funció experimental que utilitza el reconeixement de la parla en xarxa de Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Per desactivar l\'entada de veu, aneu a la configuració del teclat."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Per utilitzar l\'entrada de veu, premeu el botó del micròfon o feu lliscar el dit pel teclat en pantalla."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Parleu ara"</string>
+    <string name="voice_working" msgid="6666937792815731889">"S\'està treballant"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Error. Torneu-ho a provar."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"No s\'ha pogut connectar"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Error; s\'ha parlat massa."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Problema d\'àudio"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Error del servidor"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"No s\'escolten paraules"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"No hi ha resultats"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Cerca per veu no instal·lada"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Consell:"</b>" Feu lliscar el dit pel teclat per parlar"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Suggeriment:"</b>" La propera vegada, proveu de dir la puntuació, com ara \"punt\", \"coma\" o \"interrogant\"."</string>
+    <string name="cancel" msgid="6830980399865683324">"Cancel·la"</string>
+    <string name="ok" msgid="7898366843681727667">"D\'acord"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Entrada de veu"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"Al teclat principal"</item>
+    <item msgid="8529385602829095903">"Al teclat de símbols"</item>
+    <item msgid="7283103513488381103">"Desactivat"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Micròfon al teclat principal"</item>
+    <item msgid="6907837061058876770">"Micròfon al teclat de símbols"</item>
+    <item msgid="3664304608587798036">"L\'entrada de veu està desactivada"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Enviament automàtic després de la veu"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Prem automàticament Retorn en cercar o en anar al camp següent."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Obrir el teclat"\n</b></font><font size="3">\n</font>"Toqueu qualsevol camp de text."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Tancar el teclat"\n</b></font><font size="3">\n</font>"Premeu la tecla Enrere."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Manteniu premuda una tecla per veure les opcions"\n</b></font><font size="3">\n</font>"Accediu a la puntuació i als accents."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Configuració del teclat"\n</b></font><font size="3">\n</font>"Manteniu premuda la tecla "<b>"?123"</b>"."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Idiomes d\'entrada"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Feu lliscar el dit a la barra espaiadora per canviar l\'idioma"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Piqueu un altre cop per desar-ho"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Diccionari disponible"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-cs/config.xml b/java/res/values-cs/config.xml
new file mode 100644
index 0000000..e0e3a8e
--- /dev/null
+++ b/java/res/values-cs/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0.22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index 7a4cf78..f8bb4dd 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Rychlé opravy"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Opravuje nejčastější chyby při psaní"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Zobrazit návrhy"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Zobrazovat navržená slova během psaní"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Automatické dokončování"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"Stisknutím mezerníku nebo interpunkčního znaménka automaticky vložíte zvýrazněné slovo."</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Zobrazit klávesu Nastavení"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automaticky"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Vždy zobrazovat"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Automatické dokončování"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Stisknutím mezerníku nebo interpunkčního znaménka automaticky vložíte zvýrazněné slovo."</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Vypnuto"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Mírné"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Agresivní"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Návrh Bigram"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Použít předchozí slovo ke zlepšení návrhu"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Další"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Hotovo"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Odeslat"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"Alt"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Další"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Karta"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Pauza"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Čekat"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Hlasový vstup"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Pro váš jazyk aktuálně není hlasový vstup podporován, ale funguje v angličtině."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Hlasový vstup je experimentální funkce, která využívá síťové rozpoznávání řeči společnosti Google."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Chcete-li vypnout hlasový vstup, přejděte do nastavení klávesnice."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Chcete-li použít hlasový vstup, stiskněte tlačítko mikrofonu nebo přejeďte prstem přes klávesnici na obrazovce."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Hlasový vstup je experimentální funkce, která využívá síťové rozpoznávání řeči společnosti Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Chcete-li vypnout hlasový vstup, přejděte do nastavení klávesnice."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Chcete-li použít hlasový vstup, stiskněte tlačítko mikrofonu nebo přejeďte prstem přes klávesnici na obrazovce."</string>
     <string name="voice_listening" msgid="467518160751321844">"Mluvte"</string>
     <string name="voice_working" msgid="6666937792815731889">"Probíhá zpracování"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Aktivovat zasílání statistik užívání a zpráv o selhání"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Automatickým zasíláním statistik o užívání editoru zadávání dat a zpráv o jeho selhání do Googlu můžete přispět k vylepšení tohoto nástroje."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Dotykem aktivujete opravy"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Dotknete-li se slov, která jste napsali, můžete je opravit."</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Dotknete-li se slov, která jste napsali, můžete je opravit."</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Motiv klávesnice"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"klávesnice"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"hlas"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-da/config.xml b/java/res/values-da/config.xml
new file mode 100644
index 0000000..419f196
--- /dev/null
+++ b/java/res/values-da/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0,22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-da/donottranslate-altchars.xml b/java/res/values-da/donottranslate-altchars.xml
index b1cc8b6..596994c 100644
--- a/java/res/values-da/donottranslate-altchars.xml
+++ b/java/res/values-da/donottranslate-altchars.xml
@@ -33,6 +33,8 @@
     <string name="alternates_for_z">źžż</string>
     <string name="alternates_for_l">ł</string>
     <string name="alternates_for_v">w</string>
-    <string name="alternates_for_ae">ä</string>
-    <string name="alternates_for_oe">öœ</string>
+    <string name="keylabel_for_scandinavia_row2_10">æ</string>
+    <string name="keylabel_for_scandinavia_row2_11">ø</string>
+    <string name="alternates_for_scandinavia_row2_10">ä</string>
+    <string name="alternates_for_scandinavia_row2_11">öœ</string>
 </resources>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
index c4d67fd..bef6560 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Hurtige løsninger"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Retter almindelige stavefejl"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Vis forslag"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Vis ordforslag under indtastning"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Udfyld automatisk"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"Mellemrumstast og tegnsætning indsætter automatisk fremhævet ord"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Vis indstillingsnøgle"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatisk"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Vis altid"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Udfyld automatisk"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Mellemrumstast og tegnsætning indsætter automatisk fremhævet ord"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Fra"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Beskeden"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Aggressiv"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram-forslag"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Brug forrige ord for at forbedre forslag"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Næste"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Udfør"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Send"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Mere"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Fane"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Vent"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Stemmeinput"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Stemmeinput understøttes i øjeblikket ikke for dit sprog, men fungerer på engelsk."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Stemme-input er en funktion på forsøgsbasis, som bruger Googles netværksstemmegenkendelse."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Slå stemmeinput fra i indstillingerne for tastaturet."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"For at bruge stemme-input skal du trykke på knappen mikrofon eller lade glide fingeren hen over skærmtastaturet."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Stemme-input er en funktion på forsøgsbasis, som bruger Googles netværksstemmegenkendelse."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Slå stemmeinput fra i indstillingerne for tastaturet."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"For at bruge stemme-input skal du trykke på knappen mikrofon eller lade glide fingeren hen over skærmtastaturet."</string>
     <string name="voice_listening" msgid="467518160751321844">"Tal nu"</string>
     <string name="voice_working" msgid="6666937792815731889">"Arbejder"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Aktiver brugerfeedback"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Vær med til at forbedre denne inputmetode ved at sende anvendelsesstatistikker og rapporter om nedbrud til Google."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tryk for at rette ord igen"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Du kan rette ordene igen ved at trykke på de ord, du har indtastet"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Du kan rette ordene igen ved at trykke på de ord, du har indtastet"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tastaturtema"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"tastatur"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"stemme"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-de/config.xml b/java/res/values-de/config.xml
new file mode 100644
index 0000000..419f196
--- /dev/null
+++ b/java/res/values-de/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0,22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
index b29bbb5..4df6b25 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Quick Fixes"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Korrigiert gängige Tippfehler"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Vorschläge anzeigen"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Vorgeschlagene Wörter während des Tippens anzeigen"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Autom. vervollständigen"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"Leertaste und Interpunktion fügen autom. ein markiertes Wort ein"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Einstellungstaste anz."</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatisch"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Immer anzeigen"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Autom. vervollständigen"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Leertaste und Interpunktion fügen autom. ein markiertes Wort ein"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Aus"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Mäßig"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Aggressiv"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigramm-Vorschläge"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Zur Verbesserung des Vorschlags vorheriges Wort verwenden"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Weiter"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Fertig"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Senden"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Mehr"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Warten"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Spracheingabe"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Spracheingaben werden derzeit nicht für Ihre Sprache unterstützt, funktionieren jedoch in Englisch."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Die Spracheingabe ist eine Funktion im Versuchsstadium, die die vernetzte Spracherkennung von Google verwendet."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Wenn Sie die Spracheingabe deaktivieren möchten, rufen Sie die Tastatureinstellungen auf."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Um die Spracheingabe zu verwenden, drücken Sie die Mikrofontaste oder ziehen Sie Ihren Finger über die Bildschirmtastatur."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Die Spracheingabe ist eine Funktion im Versuchsstadium, die die vernetzte Spracherkennung von Google verwendet."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Wenn Sie die Spracheingabe deaktivieren möchten, rufen Sie die Tastatureinstellungen auf."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Um die Spracheingabe zu verwenden, drücken Sie die Mikrofontaste oder ziehen Sie Ihren Finger über die Bildschirmtastatur."</string>
     <string name="voice_listening" msgid="467518160751321844">"Jetzt sprechen"</string>
     <string name="voice_working" msgid="6666937792815731889">"Vorgang läuft"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Nutzer-Feedback aktivieren"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Tragen Sie zur Verbesserung dieses Eingabemethodeneditors bei, indem Sie automatisch Nutzungsstatistiken und Absturzberichte an Google senden."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Wortkorrektur"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Sie können Wörter korrigieren, indem Sie die eingegebenen Wörter berühren."</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Sie können Wörter korrigieren, indem Sie die eingegebenen Wörter berühren."</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tastaturdesign"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"Tastatur"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"Sprache"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-el/config.xml b/java/res/values-el/config.xml
new file mode 100644
index 0000000..419f196
--- /dev/null
+++ b/java/res/values-el/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0,22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index f249e9a..66db962 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Γρήγορες διορθώσεις"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Διορθώνει συνηθισμένα λάθη πληκτρολόγησης"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Εμφάνιση υποδείξεων"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Προβολή προτεινόμενων λέξεων κατά την πληκτρολόγηση"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Αυτόματη συμπλήρωση"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"Τα πλήκ.διαστήμ.και τονισμού εισάγ.αυτόμ.την επιλ.λέξη"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Εμφάνιση πλήκτρου ρυθμίσεων"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Αυτόματο"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Να εμφανίζεται πάντα"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Αυτόματη συμπλήρωση"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Τα πλήκ.διαστήμ.και τονισμού εισάγ.αυτόμ.την επιλ.λέξη"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Απενεργοποιημένη"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Μέτρια"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Υψηλή"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Προτάσεις bigram"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Χρήση προηγούμενης λέξης για τη βελτίωση πρότασης"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Επόμενο"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Τέλος"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Αποστολή"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ΑΒΓ"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Περισσότερα"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Καρτ."</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Παύση"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Αναμ."</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Φωνητική είσοδος"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Η φωνητική είσοδος δεν υποστηρίζεται αυτή τη στιγμή για τη γλώσσα σας, ωστόσο λειτουργεί στα Αγγλικά."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Οι φωνητικές εντολές είναι μια πειραματική λειτουργία, η οποία χρησιμοποιεί τη δικτυακή αναγνώριση ομιλίας της Google."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Για να απενεργοποιήσετε τη φωνητική είσοδο, μεταβείτε στις ρυθμίσεις πληκτρολογίου."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Για να χρησιμοποιήσετε τις φωνητικές εντολές, πιέστε το κουμπί μικροφώνου ή σύρετε το δάχτυλό σας κατά μήκος του πληκτρολογίου της οθόνης."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Οι φωνητικές εντολές είναι μια πειραματική λειτουργία, η οποία χρησιμοποιεί τη δικτυακή αναγνώριση ομιλίας της Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Για να απενεργοποιήσετε τη φωνητική είσοδο, μεταβείτε στις ρυθμίσεις πληκτρολογίου."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Για να χρησιμοποιήσετε τις φωνητικές εντολές, πιέστε το κουμπί μικροφώνου ή σύρετε το δάχτυλό σας κατά μήκος του πληκτρολογίου της οθόνης."</string>
     <string name="voice_listening" msgid="467518160751321844">"Μιλήστε τώρα"</string>
     <string name="voice_working" msgid="6666937792815731889">"Σε λειτουργία"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Ενεργοποίηση σχολίων χρηστών"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Βοηθήστε μας να βελτιώσουμε αυτό το πρόγραμμα επεξεργασίας μεθόδου εισόδου στέλνοντας αυτόματα στατιστικά στοιχεία και αναφορές σφαλμάτων στην Google."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Αγγίξτε για να διορθώσετε ξανά τις λέξεις"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Μπορείτε να διορθώσετε ξανά τις λέξεις αγγίζοντας τις λέξεις που έχετε πληκτρολογήσει"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Μπορείτε να διορθώσετε ξανά τις λέξεις αγγίζοντας τις λέξεις που έχετε πληκτρολογήσει"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Θέμα πληκτρολογίου"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"πληκτρολόγιο"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"φωνητική"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-en-rGB/config.xml b/java/res/values-en-rGB/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-en-rGB/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..04771b0
--- /dev/null
+++ b/java/res/values-en-rGB/strings.xml
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Android keyboard"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Android keyboard settings"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrate on key-press"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Sound on key-press"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Correct typing errors"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Enable input error correction"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Landscape input errors"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Enable input error correction"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Word suggestions"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Automatically correct the previous word"</string>
+    <string name="prediction" msgid="466220283138359837">"Word suggestions"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Word suggestion settings"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Enable auto-completion while typing"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Auto-completion"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Increase text field size"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Hide word suggestions in landscape view"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Auto-capitalisation"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Capitalise the start of a sentence"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Auto-punctuate"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Quick fixes"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Corrects commonly typed mistakes"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Auto-complete"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Spacebar and punctuation automatically insert highlighted word"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram Suggestions"</string>
+    <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Use previous word to improve suggestion"</string>
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"None"</item>
+    <item msgid="1669461741568287396">"Basic"</item>
+    <item msgid="4894328801530136615">"Advanced"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Saved"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Hold a key down to see accents (ø, ö, etc.)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Press the back key ↶ to close the keyboard at any point"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Access numbers and symbols"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"press and hold the left-most word to add it to the dictionary"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Touch this hint to continue »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Touch here to close this hint and start typing!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"The keyboard opens any time you touch a text field"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Touch &amp; hold a key to view accents"\n"(ø, ö, ô, ó and so on)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Switch to numbers and symbols by touching this key"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Go back to letters by touching this key again"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Touch &amp; hold this key to change keyboard settings, like auto-complete"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Try it!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Go"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Next"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Done"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Send"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Voice input"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Voice input is not currently supported for your language, but does work in English."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Voice input is an experimental feature using Google\'s networked speech recognition."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"To turn off voice input, go to keyboard settings."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"To use voice input, press the microphone button or slide your finger across the on-screen keyboard."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Speak now"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Working"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Error: Please try again."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Couldn\'t connect"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Error, too much speech."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Audio problem"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Server error"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"No speech heard"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"No matches found"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Voice search not installed"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Hint:"</b>" Swipe across keyboard to speak"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Hint:"</b>" Next time, try speaking punctuation marks, like \"full stop\", \"comma\" or \"question mark\"."</string>
+    <string name="cancel" msgid="6830980399865683324">"Cancel"</string>
+    <string name="ok" msgid="7898366843681727667">"OK"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Voice input"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"On main keyboard"</item>
+    <item msgid="8529385602829095903">"On symbols keyboard"</item>
+    <item msgid="7283103513488381103">"Off"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Mic on main keyboard"</item>
+    <item msgid="6907837061058876770">"Mic on symbols keyboard"</item>
+    <item msgid="3664304608587798036">"Voice input is disabled"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Auto-submit after voice"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Automatically press enter when searching or going to the next field."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Open the keyboard"\n</b></font><font size="3">\n</font>"Touch any text field."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Close the keyboard"\n</b></font><font size="3">\n</font>"Press the Back key."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Touch &amp; hold a key for options"\n</b></font><font size="3">\n</font>"Access punctuation and accents."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Keyboard settings"\n</b></font><font size="3">\n</font>"Touch &amp; hold the "<b>"?123"</b>" key."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Input languages"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Slide finger on spacebar to change language"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Tap again to save"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Dictionary available"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-es-rUS/config.xml b/java/res/values-es-rUS/config.xml
new file mode 100644
index 0000000..e0e3a8e
--- /dev/null
+++ b/java/res/values-es-rUS/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0.22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index 3abc8de..b95a856 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Arreglos rápidos"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corrige errores de escritura comunes"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Mostrar sugerencias"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Mostrar palabras sugeridas mientras escribe"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Completar automát."</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"La barra espaciadora o la puntuación insertan automáticamente la palabra resaltada."</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Mostrar tecla de configuración"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automático"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Mostrar siempre"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Completar automát."</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"La barra espaciadora o la puntuación insertan automáticamente la palabra resaltada."</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Apagado"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Moderado"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Intenso"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Sugerencias de Vigoran"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Utiliza la palabra anterior para mejorar la sugerencia"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Siguiente"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Hecho"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Más"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Espera"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Entrada por voz"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"La entrada por voz no está admitida en tu idioma, pero sí funciona en inglés."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"La entrada por voz es una característica experimental que utiliza la red de reconocimiento de voz de Google."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Para desactivar la entrada por voz, ve a configuración del teclado."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Para realizar entrada por voz, presiona el botón del micrófono o desliza tus dedos por el teclado en pantalla."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La entrada por voz es una característica experimental que utiliza la red de reconocimiento de voz de Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Para desactivar la entrada por voz, ve a configuración del teclado."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Para realizar entrada por voz, presiona el botón del micrófono o desliza tus dedos por el teclado en pantalla."</string>
     <string name="voice_listening" msgid="467518160751321844">"Habla ahora"</string>
     <string name="voice_working" msgid="6666937792815731889">"Procesando"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Habilitar los comentarios del usuario"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Ayuda a mejorar este editor de método de introducción de texto al enviar las estadísticas de uso y los informes de error a Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tocar para corregir palabras"</string>
-    <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Toca las palabras ingresadas que desees corregir"</string>
+    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Toca las palabras ingresadas que desees corregir"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema del teclado"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"Teclado"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"Voz"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-es/config.xml b/java/res/values-es/config.xml
new file mode 100644
index 0000000..419f196
--- /dev/null
+++ b/java/res/values-es/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0,22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
index cd6dc8e..9e9afee 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Correcciones rápidas"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corrige los errores tipográficos que se cometen con más frecuencia."</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Mostrar sugerencias"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Muestra las palabras sugeridas mientras se escribe."</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Autocompletar"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"La barra espaciadora y los signos de puntuación insertan automáticamente la palabra resaltada."</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Mostrar tecla de ajustes"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automáticamente"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Mostrar siempre"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Autocompletar"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"La barra espaciadora y los signos de puntuación insertan automáticamente la palabra resaltada."</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Desactivada"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Parcial"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Total"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Sugerencias de bigramas"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Usar palabra anterior para mejorar sugerencias"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Sig."</string>
     <string name="label_done_key" msgid="2441578748772529288">"Listo"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Más"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab."</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Espera"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Introducción de voz"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Actualmente la introducción de voz no está disponible en tu idioma, pero se puede utilizar en inglés."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"La introducción de voz es una función en fase experimental que utiliza la tecnología de reconocimiento de voz en red de Google."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Para desactivar la función de introducción de voz, accede a la configuración del teclado."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Para utilizar la función de introducción de voz, pulsa el botón de micrófono o desliza el dedo por el teclado en pantalla."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La introducción de voz es una función en fase experimental que utiliza la tecnología de reconocimiento de voz en red de Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Para desactivar la función de introducción de voz, accede a la configuración del teclado."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Para utilizar la función de introducción de voz, pulsa el botón de micrófono o desliza el dedo por el teclado en pantalla."</string>
     <string name="voice_listening" msgid="467518160751321844">"Habla ahora"</string>
     <string name="voice_working" msgid="6666937792815731889">"En curso"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Habilitar comentarios de usuarios"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Ayuda a mejorar este editor de método de introducción de texto enviando estadísticas de uso e informes de error a Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tocar para corregir palabras"</string>
-    <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Tocar palabras introducidas para corregirlas"</string>
+    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Tocar palabras introducidas para corregirlas"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema de teclado"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"teclado"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"voz"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-fa/config.xml b/java/res/values-fa/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-fa/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
new file mode 100644
index 0000000..2cf84fc
--- /dev/null
+++ b/java/res/values-fa/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"صفحه کلید Android"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"تنظیمات صفحه کلید Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"لرزش با فشار کلید"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"صدا با فشار کلید"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"تصحیح خطاهای تایپی"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"فعال کردن تصحیح خطای ورودی"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"خطاهای ورود افقی"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"فعال کردن تصحیح خطای ورودی"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"پیشنهادات کلمه"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"تصحیح خودکار کلمه قبلی"</string>
+    <string name="prediction" msgid="466220283138359837">"پیشنهادات کلمه"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"تنظیمات پیشنهاد کلمه"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"فعال کردن تکمیل خودکار در حین تایپ"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"تکمیل خودکار"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"افزایش اندازه قسمت متنی"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"پنهان کردن پیشنهادات کلمه در نمای افقی"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"نوشتن با حروف بزرگ خودکار"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"بزرگ کردن اول هر جمله"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"نشان گذاری خودکار"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"راه حل های سریع"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"تصحیح خطاهای تایپی رایج"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"تکمیل خودکار"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"کلید خط فاصله و علائم نگارشی به صورت خودکار کلمه برجسته شده را وارد می کنند."</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"هیچکدام"</item>
+    <item msgid="1669461741568287396">"پایه"</item>
+    <item msgid="4894328801530136615">"پیشرفته"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : ذخیره شد"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"برای مشاهده علائم تکیه (ø، ö و موارد دیگر) کلیدی را پایین نگه دارید"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"برای بستن صفحه کلید در هر نقطه که بخواهید، کلید برگشت ↶ را فشار دهید"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"دسترسی به اعداد و نمادها"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"انتهای سمت چپ واژه را برای افزودن آن به فرهنگ لغت فشار داده و نگه دارید"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"این نکته را برای ادامه لمس کنید »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"برای بستن این نکته و شروع تایپ، اینجا را لمس کنید!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"هر زمان که قسمت متنی را لمس می کنید، صفحه کلید باز می شود"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"یک کلید را برای مشاهده تکیه های صدا لمس کرده و نگه دارید (ø، ö، ô، ó و موارد دیگر)"\n</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"تغییر شماره ها و نمادها با لمس این کلید"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"با لمس مجدد این کلید، به حروف برگردید"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"این کلید را برای تغییر تنظیمات صفحه کلید مانند تکمیل خودکار لمس کرده و فشار دهید"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"امتحان کنید!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"برو"</string>
+    <string name="label_next_key" msgid="362972844525672568">"بعدی"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"انجام شد"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"ارسال"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"ورودی صوتی"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"ورودی صوتی در حال حاضر برای زبان شما پشتیبانی نمی شود اما برای زبان انگلیسی فعال است."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"ورودی صوتی یک ویژگی آزمایشی با استفاده از تشخیص گفتار شبکه Google است."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"برای خاموش کردن ورودی صدا، به تنظیمات صفحه کلید بروید."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"برای استفاده از ورودی صوتی، دکمه میکروفن را فشار دهید یا انگشت خود را روی صفحه کلید روی صفحه حرکت دهید."</string>
+    <string name="voice_listening" msgid="467518160751321844">"اکنون صحبت کنید"</string>
+    <string name="voice_working" msgid="6666937792815731889">"در حال کار"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"خطا: لطفاً دوباره امتحان کنید."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"متصل نشد"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"خطا، گفتار بسیار زیاد است."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"مشکل صوتی"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"خطای سرور"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"گفتاری شنیده نشد"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"مورد منطبقی یافت نشد"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"جستجوی صوتی نصب نشده است"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"نکته: "</b>" برای صحبت روی صفحه کلید ضربه بزنید"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"نکته: دفعه دیگر، از نشانه گذاری های گفتاری مانند \"نقطه\"، \"کاما\" یا \"علامت سؤال\" استفاده کنید."</b></string>
+    <string name="cancel" msgid="6830980399865683324">"لغو"</string>
+    <string name="ok" msgid="7898366843681727667">"تأیید"</string>
+    <string name="voice_input" msgid="2466640768843347841">"ورودی صوتی"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"در صفحه کلید اصلی"</item>
+    <item msgid="8529385602829095903">"در صفحه کلید نمادها"</item>
+    <item msgid="7283103513488381103">"خاموش"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"میکروفن در صفحه کلید اصلی"</item>
+    <item msgid="6907837061058876770">"میکروفن در صفحه کلید نمادها"</item>
+    <item msgid="3664304608587798036">"ورودی صوتی غیر فعال شده است"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"ارائه خودکار بعد از صدا"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"هنگام جستجو یا رفتن به قسمت بعدی، Enter را به صورت خودکار فشار دهید."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"صفحه کلید را باز کنید"\n</b></font><font size="3">\n</font>"هر قسمت متنی را لمس کنید."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"بستن صفحه کلید"\n</b></font><font size="3">\n</font>"کلید برگشت را فشار دهید."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"یک کلید را برای گزینه های"\n</b></font><font size="3">\n</font>" دسترسی به علائم نگارشی و تکیه های صدا لمس کرده و نگه دارید."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"تنظیمات صفحه کلید"\n</b></font><font size="3">\n</font>"کلید "<b>"?123"</b>" را لمس کرده و نگهدارید."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"زبان های ورودی"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"برای تغییر زبان انگشت را روی کلید فاصله بلغزانید"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← جهت ذخیره دوباره ضربه بزنید"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"دیکشنری موجود است"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-fi/config.xml b/java/res/values-fi/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-fi/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml
new file mode 100644
index 0000000..3ef11c4
--- /dev/null
+++ b/java/res/values-fi/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Android-näppäimistö"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Android-näppäimistön asetukset"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Käytä värinää näppäimiä painettaessa"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Toista ääni näppäimiä painettaessa"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Korjaa kirjoitusvirheet"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Ota syöttövirheen korjaus käyttöön"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Vaakasuunnan syöttövirheet"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Ota syöttövirheen korjaus käyttöön"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Sanaehdotukset"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Korjaa edellinen sana automaattisesti"</string>
+    <string name="prediction" msgid="466220283138359837">"Sanaehdotukset"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Sanaehdotusasetukset"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Ota automaattinen täydennys käyttöön kirjoitettaessa"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Automaattinen täydennys"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Suurenna tekstikenttää"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Piilota sanaehdotukset vaakasuuntaisessa näkymässä"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Automaattiset isot kirjaimet"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Aloittaa lauseet isolla kirjaimella"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Automaattiset välimerkit"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Pikakorjaukset"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Korjaa yleiset kirjoitusvirheet"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Automaattinen täydennys"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Välilyönti ja välimerkki lisäävät automaattisesti korostetun sanan"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Ei mitään"</item>
+    <item msgid="1669461741568287396">"Tavallinen"</item>
+    <item msgid="4894328801530136615">"Edistynyt"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Tallennettu"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Näet aksenttimerkit (ø, ö jne.) pitämällä näppäintä painettuna."</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Voit sulkea näppäimistön milloin tahansa painamalla Takaisin-painiketta ↶"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Käytä numeroita ja symboleita"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Lisää vasemmanpuoleinen sana sanakirjaan pitämällä sitä painettuna"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Jatka koskettamalla tätä vihjettä »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Sulje tämä vihje ja aloita kirjoittaa koskettamalla tätä!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Näppäimistö avautuu, kun kosketat tekstikenttää"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Näytä aksenttimerkit pitämällä näppäintä painettuna"\n"(ø, ö, ô, ó ja niin edelleen"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Vaihda numeroihin ja symboleihin koskettamalla tätä näppäintä"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Siirry takaisin kirjaimiin koskettamalla tätä näppäintä uudelleen"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Muuta näppäimistön asetuksia, kuten automaattista täydentämistä, pitämällä tätä näppäintä painettuna"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Kokeile!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Siirry"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Seuraava"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Valmis"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Lähetä"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Äänisyöte"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Äänisyötettä ei vielä tueta kielelläsi, mutta voit käyttää sitä englanniksi."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Äänisyöte on kokeellinen Googlen puheentunnistusta käyttävä ominaisuus."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Siirry näppäimistön asetuksiin poistaaksesi äänisyötteen käytöstä."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Käytä äänisyötettä painamalla mikrofonipainiketta tai liu\'uttamalla sormeasi näytön näppäimistön poikki."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Puhu nyt"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Työstetään"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Virhe. Yritä uudelleen."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Ei yhteyttä"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Virhe, liikaa puhetta."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Ääniongelma"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Palvelinvirhe"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Puhetta ei kuulu"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Ei vastineita"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Äänihakua ei asennettu"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Vihje:"</b>" liu\'uta sormea näppäimistöllä ja puhu"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Vihje:"</b>" kokeile seuraavalla kerralla puhua välimerkit, kuten \"period\" (piste), \"comma\" (pilkku) tai \"question mark\" (kysymysmerkki)."</string>
+    <string name="cancel" msgid="6830980399865683324">"Peruuta"</string>
+    <string name="ok" msgid="7898366843681727667">"OK"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Äänisyöte"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"Päänäppäimistössä"</item>
+    <item msgid="8529385602829095903">"Symbolinäppäimistössä"</item>
+    <item msgid="7283103513488381103">"Pois käytöstä"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Päänäppäimistön mikrofoni"</item>
+    <item msgid="6907837061058876770">"Symbolinäppäimistön mikrofoni"</item>
+    <item msgid="3664304608587798036">"Äänisyöte ei ole käytössä"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Lähetä automaattisesti puheen jälkeen"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Paina automaattisesti enter-näppäintä tehdessäsi hakuja tai siirtyessäsi seuraavaan kenttään."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Avaa näppäimistö"\n</b></font><font size="3">\n</font>"Kosketa tekstikenttää."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Sulje näppäimistö"\n</b></font><font size="3">\n</font>"Paina Takaisin-näppäintä."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Näet asetukset pitämällä näppäintä painettuna"\n</b></font><font size="3">\n</font>"Käytä välimerkkejä ja aksenttimerkkejä."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Näppäimistön asetukset"\n</b></font><font size="3">\n</font>"Pidä painettuna"<b>"?123"</b>"-näppäintä."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Syöttökielet"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Vaihda kieltä liu\'uttamalla sormea välilyöntinäppäimellä"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Tallenna napauttamalla uudelleen"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Sanakirja saatavilla"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-fr/config.xml b/java/res/values-fr/config.xml
new file mode 100644
index 0000000..e0e3a8e
--- /dev/null
+++ b/java/res/values-fr/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0.22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index f8f4bac..d7abbd1 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Corrections rapides"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corrige les fautes de frappe courantes"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Afficher les suggestions"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Afficher les suggestions de terme lors de la saisie"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Saisie semi-automatique"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"Insérer auto. le terme surligné avec barre espace/ponctuation"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Afficher la touche des paramètres"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatique"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Toujours afficher"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Saisie semi-automatique"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Insérer auto. le terme surligné avec barre espace/ponctuation"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Désactivée"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Simple"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Proactive"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Suggestions de type bigramme"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Améliorer la suggestion en fonction du mot précédent"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Suivant"</string>
     <string name="label_done_key" msgid="2441578748772529288">"OK"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Envoyer"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Plus"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Onglet"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Attente"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Saisie vocale"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"La saisie vocale n\'est pas encore prise en charge pour votre langue, mais elle fonctionne en anglais."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"La saisie vocale est une fonctionnalité expérimentale qui fait appel à la reconnaissance vocale en réseau de Google."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Pour désactiver la saisie vocale, accédez aux paramètres du clavier."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Pour utiliser la saisie vocale, appuyez sur la touche du microphone ou faites glisser votre doigt sur le clavier à l\'écran."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"La saisie vocale est une fonctionnalité expérimentale qui fait appel à la reconnaissance vocale en réseau de Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Pour désactiver la saisie vocale, accédez aux paramètres du clavier."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Pour utiliser la saisie vocale, appuyez sur la touche du microphone ou faites glisser votre doigt sur le clavier à l\'écran."</string>
     <string name="voice_listening" msgid="467518160751321844">"Parlez maintenant"</string>
     <string name="voice_working" msgid="6666937792815731889">"Traitement en cours"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Autoriser les commentaires des utilisateurs"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Contribuer à l\'amélioration de cet éditeur du mode de saisie grâce à l\'envoi automatique de statistiques d\'utilisation et de rapports d\'incident à Google."</string>
     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Appuyer pour corriger les suggestions"</string>
-    <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Appuyer sur les mots saisis pour les corriger"</string>
+    <!-- outdated translation 1056068922330206170 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Appuyer sur les mots saisis pour les corriger"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Thème du clavier"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"clavier"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"voix"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-hr/config.xml b/java/res/values-hr/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-hr/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
new file mode 100644
index 0000000..7888fb8
--- /dev/null
+++ b/java/res/values-hr/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Android tipkovnica"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Postavke tipkovnice za Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibracija pri pritisku na tipku"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Zvuk pri pritisku tipke"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Ispravi pogreške u pisanju"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Omogućavanje ispravka pogreške pri unosu"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Pogreške pri pejzažnom unosu"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Omogućavanje ispravka pogreške pri unosu"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Prijedlozi riječi"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Automatsko ispravljanje prethodne riječi"</string>
+    <string name="prediction" msgid="466220283138359837">"Prijedlozi riječi"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Postavke prijedloga riječi"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Omogućavanje automatskog dovršavanja pri upisivanju"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Automatsko dovršavanje"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Povećaj tekstualno polje"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Sakrij prijedloge riječi u pejzažnom prikazu"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Automatsko pisanje velikih slova"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Stavi veliko slovo na početku rečenice"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Automatsko stavljanje interpunkcije"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Brzi popravci"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Ispravlja uobičajene pogreške u pisanju"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Automatsko dovršavanje"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Razmaknica i interpunkcija automatski umeću istaknutu riječ"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Nijedan"</item>
+    <item msgid="1669461741568287396">"Osnovni"</item>
+    <item msgid="4894328801530136615">"Napredno"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Spremljeno"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Pritisnite i držite tipku da biste vidjeli naglaske (ø, ö itd.)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Pritisnite tipku \"Natrag\" ↶ za zatvaranje tipkovnice"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Pristup brojevima i simbolima"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Pritisnite i držite krajnju lijevu riječ da biste je dodali u rječnik."</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Dodirnite ovaj savjet za nastavak »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Dodirnite ovdje da biste zatvorili savjet i počeli upisivati!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Tipkovnica se otvara svaki put kada dodirnete tekstualno polje"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Dodirnite i držite tipku da biste vidjeli naglaske"\n"(ø, ö, ô, ó i tako dalje)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Prijeđite na brojeve i simbole dodirom na ovu tipku"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Dodirnite ponovo ovu tipku za povratak na slova"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Dodirnite i držite ovu tipku da biste promijenili postavke tipkovnice, poput automatskog dovršavanja"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Isprobajte!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Idi"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Dalje"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Gotovo"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Pošalji"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Glasovni unos"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Vaš jezik trenutno nije podržan za glasovni unos, ali radi za engleski."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Glasovni unos je pokusna značajka koja koristi Googleovo umreženo prepoznavanje govora."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Za isključivanje glasovnog unosa idite na postavke tipkovnice."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Da biste koristili glasovni unos pritisnite gumb mikrofona ili kliznite prstom preko tipkovnice na zaslonu."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Govorite sad"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Obrada"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Pogreška. Pokušajte ponovo."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Spajanje nije bilo moguće"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Pogreška, predugi govor."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Problem sa zvukom"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Pogreška na poslužitelju"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Nije se čuo govor"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Nisu pronađeni rezultati"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Glasovno pretraživanje nije instalirano"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Savjet:"</b>" Prijeđite preko tipkovnice pa govorite"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Savjet:"</b>" Sljedeći put pokušajte izgovoriti znakove interpunkcije poput \"točka, \"zarez\" ili \"upitnik\"."</string>
+    <string name="cancel" msgid="6830980399865683324">"Odustani"</string>
+    <string name="ok" msgid="7898366843681727667">"U redu"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Glasovni unos"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"Na glavnoj tipkovnici"</item>
+    <item msgid="8529385602829095903">"Na tipkovnici sa simbolima"</item>
+    <item msgid="7283103513488381103">"Isključeno"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Mikrofon na glavnoj tipkovnici"</item>
+    <item msgid="6907837061058876770">"Mikrofon na tipkovnici sa simbolima"</item>
+    <item msgid="3664304608587798036">"Glasovni unos je onemogućen"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Automatski pošalji nakon glasovnog unosa"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Automatski se pritišće \"Enter\" kad pretražujete ili idete na sljedeće polje."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Otvaranje tipkovnice"\n</b></font><font size="3">\n</font>"Dodirnite bilo koje tekstualno polje"</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Zatvaranje tipkovnice"\n</b></font><font size="3">\n</font>"Pritisnite tipku \"Natrag\"."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Dodirnite i držite tipku da biste vidjeli opcije"\n</b></font><font size="3">\n</font>"Pristup interpunkciji i naglascima."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Postavke tipkovnice"\n</b></font><font size="3">\n</font>"Dodirnite i držite tipku "<b>"?123"</b>"."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Jezici unosa"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Kliznite prstom po razmaknici za promjenu jezika"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Dotaknite ponovo za spremanje"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Rječnik je dostupan"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-hu/config.xml b/java/res/values-hu/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-hu/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
new file mode 100644
index 0000000..6bc8ce9
--- /dev/null
+++ b/java/res/values-hu/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Android-billentyűzet"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Android billentyűzetbeállítások"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Rezgés billentyű megnyomása esetén"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Hangjelzés billentyű megnyomása esetén"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Gépelési hibák kijavítása"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Beviteli hibák javításának engedélyezése"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Fekvő beviteli hibák"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Beviteli hibák javításának engedélyezése"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Szójavaslatok"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Az előző szó automatikus kijavítása"</string>
+    <string name="prediction" msgid="466220283138359837">"Szójavaslatok"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Szójavaslati beállítások"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Automatikus kiegészítés engedélyezése gépelés közben"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Automatikus kiegészítés"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"A szövegmező méretének növelése"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Szójavaslatok elrejtése fekvő nézetben"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Automatikusan nagy kezdőbetű"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Nagybetűvel kezdi a mondatot"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Automatikus központozás"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Gyorsjavítások"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Kijavítja a gyakori gépelési hibákat"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Automatikus kiegészítés"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"A szóköz és az írásjelek használata automatikusan beszúrja a kiemelt szót"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Nincs"</item>
+    <item msgid="1669461741568287396">"Alap"</item>
+    <item msgid="4894328801530136615">"Speciális"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : mentve"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Az ékezetes betűk megtekintéséhez tartsa lenyomva valamelyik billentyűt (ø, ö stb.)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"A vissza gomb ↶ megnyomásával bármikor elrejtheti a billentyűzetet"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Számok és szimbólumok elérése"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"A szótárhoz történő hozzáadásához nyomja meg hosszan a bal oldali legszélső szót"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"A folytatáshoz érintse meg ezt a tippet »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Érintse meg itt a tipp bezárásához és a gépelés megkezdéséhez."</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Szövegmező megérintésekor a billentyűzet mindig megjelenik"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Érintse meg és tartsa lenyomva valamelyik billentyűt az ékezetes betűk megtekintéséhez"\n"(ø, ö, ô, ó stb.)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Számokra és szimbólumokra ennek a billentyűnek a megérintésével válthat"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"A billentyű újbóli megérintésével visszatérhet a betűkhöz"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Érintse meg és tartsa lenyomva ezt a billentyűt a billentyűzet-beállítások (pl. az automatikus kiegészítés) módosításához"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Próbálja ki!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Ugrás"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Tovább"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Kész"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Küldés"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Hangbevitel"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"A hangbevitel szolgáltatás jelenleg nem támogatja az Ön nyelvét, ám angolul működik."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"A hangbevitel a Google hálózati beszédfelismerését alkalmazó kísérleti funkció."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"A hangbevitelt a billentyűzet beállításai között lehet kikapcsolni."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"A hangbevitel használatához nyomja meg a mikrofon gombját vagy húzza végig az ujját a képernyő-billentyűzeten."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Most beszéljen"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Feldolgozás"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Hiba történt. Kérjük, próbálja újra."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Nem sikerült kapcsolódni"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Hiba történt; túl sokat beszélt."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Hangprobléma"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Szerverhiba"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Nem hallatszott beszéd"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Nem található egyezés"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"A hangalapú keresés nincs telepítve"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Tipp:"</b>" húzza végig az ujját a billentyűzeten a beszédhez"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Tipp:"</b>" következő alkalommal próbálja ki az írásjelek kimondását is, pl. \"period\", \"comma\" vagy \"question mark\"."</string>
+    <string name="cancel" msgid="6830980399865683324">"Mégse"</string>
+    <string name="ok" msgid="7898366843681727667">"OK"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Hangbevitel"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"Főbillentyűzeten"</item>
+    <item msgid="8529385602829095903">"Szimbólumbillentyűzeten"</item>
+    <item msgid="7283103513488381103">"Ki"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Mikrofon a főbillentyűzeten"</item>
+    <item msgid="6907837061058876770">"Mikrofon a szimbólumbillentyűzeten"</item>
+    <item msgid="3664304608587798036">"A hangbevitel ki van kapcsolva"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Automatikus küldés a beszéd után"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Az Enter automatikus megnyomása keresés vagy a következő mezőre ugrás során."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"A billentyűzet megjelenítése"\n</b></font><font size="3">\n</font>"Érintse meg valamelyik szövegmezőt."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"A billentyűzet bezárása"\n</b></font><font size="3">\n</font>"Nyomja meg a Vissza billentyűt."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"A lehetőségek megjelenítéséhez érintse meg és tartsa lenyomva valamelyik billentyűt"\n</b></font><font size="3">\n</font>"Az írásjelek és az ékezetes betűk elérése."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Billentyűzetbeállítások"\n</b></font><font size="3">\n</font>"Érintse meg és tartsa lenyomva a "<b>"?123"</b>" billentyűt."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Beviteli nyelvek"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"A nyelv módosításához húzza végig az ujját a szóköz billentyűn"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← A mentéshez érintse meg újra"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Van elérhető szótár"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-in/config.xml b/java/res/values-in/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-in/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
new file mode 100644
index 0000000..d88c223
--- /dev/null
+++ b/java/res/values-in/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Keyboard Android"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Setelan keyboard Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Getar jika tombol ditekan"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Berbunyi jika tombol ditekan"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Perbaiki kesalahan ketik"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Aktifkan perbaikan galat masukan"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Galat masukan lanskap"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Aktifkan perbaikan galat masukan"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Saran kata"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Perbaiki kata sebelumnya secara otomatis"</string>
+    <string name="prediction" msgid="466220283138359837">"Saran kata"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Setelan saran kata"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Aktifkan pengisian otomatis saat mengetik"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Pengisian otomatis"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Tambah ukuran bidang teks"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Sembunyikan saran kata dalam tampilan melintang"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Kapitalisasi otomatis"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Kapitalisasi awal kalimat"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Beri tanda baca otomatis"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Perbaikan cepat"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Memperbaiki kesalahan ketik umum"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Pengisian otomatis"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Bilah spasi dan tanda baca secara otomatis memasukkan kata yang disorot"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Tak Satu Pun"</item>
+    <item msgid="1669461741568287396">"Dasar"</item>
+    <item msgid="4894328801530136615">"Lanjutan"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Telah disimpan"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Tahan tombol untuk melihat aksen (ø, ö, dll.)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Tekan tombol kembali ↶ untuk menutup keyboard kapan saja"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Akses angka dan simbol"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Tekan terus kata yang paling kiri untuk menambahkannya ke kamus"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Sentuh petunjuk ini untuk melanjutkan »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Sentuh di sini untuk menutup petunjuk dan mulailah mengetik!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Keyboard terbuka setiap kali Anda menyentuh bidang teks"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Sentuh &amp; tahan tombol untuk melihat aksen"\n"(ø, ö, ô, ó, dan seterusnya)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Beralih ke angka dan simbol dengan menekan tombol ini"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Kembali ke huruf dengan menekan tombol ini lagi"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Sentuh &amp; tahan tombol ini untuk mengubah setelan keyboard, seperti lengkapi otomatis"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Cobalah!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Buka"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Berikutnya"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Selesai"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Kirimkan"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Masukan suara"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Masukan suara saat ini tidak didukung untuk bahasa Anda, tetapi bekerja dalam Bahasa Inggris."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Masukan suara adalah fitur eksperimental yang menggunakan pengenal suara berjaringan Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Untuk mematikan masukan suara, buka setelan keyboard."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Untuk menggunakan masukan suara, tekan tombol mikrofon atau geser jari Anda di sepanjang keyboard pada layar."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Ucapkan sekarang"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Bekerja"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Galat: Coba lagi."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Tidak dapat menyambung"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Galat, terlalu banyak ucapan."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Masalah audio"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Galat server"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Tidak terdengar ucapan"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Tak ditemukan yang cocok"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Penelusuran suara tidak terpasang"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Petunjuk:"</b>" Gesek keyboard untuk berbicara"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Petunjuk:"</b>" Selanjutnya, coba ucapkan tanda baca seperti \"titik\", \"koma\", atau \"tanda tanya\"."</string>
+    <string name="cancel" msgid="6830980399865683324">"Batal"</string>
+    <string name="ok" msgid="7898366843681727667">"OK"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Masukan suara"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"Di keyboard utama"</item>
+    <item msgid="8529385602829095903">"Di keyboard simbol"</item>
+    <item msgid="7283103513488381103">"Mati"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Mik di keyboard utama"</item>
+    <item msgid="6907837061058876770">"Mik di keyboard simbol"</item>
+    <item msgid="3664304608587798036">"Masukan suara dinonaktifkan"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Kirim otomatis setelah suara"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Tekan enter secara otomatis saat menelusuri atau menuju ke bidang berikutnya."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Buka keyboard"\n</b></font><font size="3">\n</font>"Sentuh bidang teks mana pun."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Tutup keyboard"\n</b></font><font size="3">\n</font>"Tekan tombol Kembali."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Sentuh &amp; tahan tombol tertentu untuk opsi"\n</b></font><font size="3">\n</font>"Akses tanda baca dan aksen."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Setelan keyboard"\n</b></font><font size="3">\n</font>"Sentuh &amp; tahan tombol "<b>"?123"</b>"."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Bahasa masukan"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Geser jari pada bilah spasi untuk mengubah bahasa"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Ketuk sekali lagi untuk menyimpan"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Kamus yang tersedia"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-it/config.xml b/java/res/values-it/config.xml
new file mode 100644
index 0000000..419f196
--- /dev/null
+++ b/java/res/values-it/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0,22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml
index 94cdb96..6e35b28 100644
--- a/java/res/values-it/strings.xml
+++ b/java/res/values-it/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Correzioni veloci"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corregge gli errori di digitazione più comuni"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Mostra suggerimenti"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Visualizza le parole suggerite durante la digitazione"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Completamento autom."</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"Barra spaziatrice e punteggiatura inseriscono la parola evidenziata"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Mostra tasto impostazioni"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatico"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Mostra sempre"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Completamento autom."</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Barra spaziatrice e punteggiatura inseriscono la parola evidenziata"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Non attivo"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Medio"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Massimo"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Suggerimenti sui bigrammi"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Utilizza parola precedente per migliorare il suggerimento"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Avanti"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Fine"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Invia"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Altro"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Attesa"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Comandi vocali"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"I comandi vocali non sono attualmente supportati per la tua lingua ma funzionano in inglese."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"I comandi vocali sono una funzione sperimentale che utilizza il riconoscimento vocale in rete di Google."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Per disattivare i comandi vocali, vai alle impostazioni della tastiera."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Per utilizzare i comandi vocali, premi il pulsante del microfono o fai scorrere il dito sulla tastiera sullo schermo."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"I comandi vocali sono una funzione sperimentale che utilizza il riconoscimento vocale in rete di Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Per disattivare i comandi vocali, vai alle impostazioni della tastiera."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Per utilizzare i comandi vocali, premi il pulsante del microfono o fai scorrere il dito sulla tastiera sullo schermo."</string>
     <string name="voice_listening" msgid="467518160751321844">"Parla ora"</string>
     <string name="voice_working" msgid="6666937792815731889">"Elaborazione in corso"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Attiva commenti degli utenti"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Aiuta a migliorare l\'editor del metodo di inserimento inviando automaticamente a Google statistiche sull\'utilizzo e segnalazioni sugli arresti anomali."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tocca per correggere di nuovo le parole"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Puoi correggere di nuovo le parole toccando quelle che hai digitato"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Puoi correggere di nuovo le parole toccando quelle che hai digitato"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema della tastiera"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"tastiera"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"vocale"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-iw/config.xml b/java/res/values-iw/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-iw/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
new file mode 100644
index 0000000..eb9c57a
--- /dev/null
+++ b/java/res/values-iw/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"מקלדת Android"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"הגדרות מקלדת של Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"רטט עם לחיצה על מקשים"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"צלילים עם לחיצה על מקשים"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"תקן שגיאות הקלדה"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"הפוך תיקון שגיאות קלט לפעיל"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"שגיאות קלט בפריסה לרוחב"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"הפוך תיקון שגיאות קלט לפעיל"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"הצעות למילים"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"תקן באופן אוטומטי את המילה הקודמת"</string>
+    <string name="prediction" msgid="466220283138359837">"הצעות למילים"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"הגדרות של הצעות מילים"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"הפוך השלמה אוטומטית לפעילה בעת הקלדה"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"השלמה אוטומטית"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"הגדל את הגודל של שדה הטקסט"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"הסתר הצעות למילים בתצוגה לרוחב"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"הפיכה אוטומטית של אותיות לרישיות"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"הוסף אות רישית בתחילת משפט"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"פיסוק אוטומטי"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"תיקונים מהירים"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"מתקן שגיאות הקלדה נפוצות"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"השלמה אוטומטית"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"הקשה על מקש הרווח וסימני הפיסוק תוסיף באופן אוטומטי את המילה המסומנת"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"ללא"</item>
+    <item msgid="1669461741568287396">"בסיסי"</item>
+    <item msgid="4894328801530136615">"מתקדם"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : נשמרה"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"החזק מקש לחוץ כדי לראות אקצנטים (ø, ö וכדומה)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"לחץ על המקש \'הקודם\' ↶ כדי לסגור את המקלדת בכל עת"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"גישה למספרים וסמלים"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"לחץ על המילה השמאלית הקיצונית והחזק אותה לחוצה כדי להוסיף למילון"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"גע ברמז זה כדי להמשיך »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"גע כאן כדי לסגור רמז זה ולהתחיל בהקלדה!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"המקלדת נפתחת בכל פעם שאתה נוגע בשדה טקסט"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"גע במקש והחזק אותו לחוץ כדי להציג אקצנטים"\n"(ø, ö, ô, ó וכדומה)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"עבור למספרים וסמלים על ידי נגיעה במקש זה"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"חזור לאותיות על ידי מגע במקש זה שוב"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"גע במקש זה והחזק אותו לחוץ כדי לשנות את הגדרות המקלדת, כגון השלמה אוטומטית"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"נסה אותו!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"בצע"</string>
+    <string name="label_next_key" msgid="362972844525672568">"הבא"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"בוצע"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"שלח"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"קלט קולי"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"קלט קולי אינו נתמך בשלב זה בשפתך, אך הוא פועל באנגלית."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"קלט קולי הוא תכונה ניסיונית של זיהוי הדיבור ברשת של Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"כדי לכבות את הקלט הקולי, עבור להגדרות מקלדת."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"כדי להשתמש בקלט הקולי, לחץ על לחצן המיקרופון או החלק את האצבע על המקלדת שבמסך."</string>
+    <string name="voice_listening" msgid="467518160751321844">"דבר כעת"</string>
+    <string name="voice_working" msgid="6666937792815731889">"פועל"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"שגיאה. נסה שוב."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"אין אפשרות להתחבר"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"שגיאה, דיבור רב מדי."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"בעיה באודיו"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"שגיאת שרת"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"לא נשמע דיבור"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"לא נמצאו התאמות"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"חיפוש קולי לא מותקן"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"רמז:"</b>" העבר על המקלדת כדי לדבר"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"רמז:"</b>" בפעם הבאה, נסה לומר את סימני הפיסוק כגון \"נקודה\", \"פסיק\" או \"סימן שאלה\"."</string>
+    <string name="cancel" msgid="6830980399865683324">"ביטול"</string>
+    <string name="ok" msgid="7898366843681727667">"אישור"</string>
+    <string name="voice_input" msgid="2466640768843347841">"קלט קולי"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"במקלדת הראשית"</item>
+    <item msgid="8529385602829095903">"מקלדת סמלים מופעלת"</item>
+    <item msgid="7283103513488381103">"כבוי"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"מיקרופון במקלדת הראשית"</item>
+    <item msgid="6907837061058876770">"מיקרופון במקלדת סמלים"</item>
+    <item msgid="3664304608587798036">"הקלט הקולי מושבת"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"שליחה אוטומטית לאחר הקלטת קול"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"הקש על Enter באופן אוטומטי בעת חיפוש או מעבר לשדה הבא."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"פתח את המקלדת"\n</b></font><font size="3">\n</font>"גע בשדה טקסט כלשהו."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"סגור את המקלדת"\n</b></font><font size="3">\n</font>"לחץ על הלחצן \'הקודם\'."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"גע במקש והחזק אותו לחוץ לקבלת אפשרויות"\n</b></font><font size="3">\n</font>"קבל גישה לסימני פיסוק ואקצנטים."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"הגדרות מקלדת"\n</b></font><font size="3">\n</font>"גע במקש "<b>"?123"</b>" והחזק אותו לחוץ."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">"‎.com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">"‎.net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">"‎.org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">"‎.gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">"‎.edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"שפות קלט"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"החלק את האצבע על מקש הרווח כדי לשנות שפה"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← הקש שוב כדי לשמור"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"מילון זמין"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-ja/config.xml b/java/res/values-ja/config.xml
new file mode 100644
index 0000000..e0e3a8e
--- /dev/null
+++ b/java/res/values-ja/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0.22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index 71a67a2..1bd5cbf 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"クイックフィックス"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"よくある誤字・脱字を修正します"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"入力候補を表示"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"入力時に入力候補を表示する"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"オートコンプリート"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"反転表示されている変換候補をスペースまたは句読点キーで挿入する"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"設定キーを表示"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"自動"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"常に表示"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"オートコンプリート"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"反転表示されている変換候補をスペースまたは句読点キーで挿入する"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"OFF"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"中"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"強"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"バイグラム入力候補表示"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"直前の単語から入力候補を予測します"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"次へ"</string>
     <string name="label_done_key" msgid="2441578748772529288">"完了"</string>
     <string name="label_send_key" msgid="2815056534433717444">"送信"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Shift"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"停止"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"待機"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"音声入力"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"音声入力は現在英語には対応していますが、日本語には対応していません。"</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"音声入力はGoogleのネットワーク音声認識技術を利用した試験段階の機能です。"</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"音声入力をOFFにするには、キーボードの設定を開きます。"</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"音声入力するには、マイクボタンを押すか画面キーボードをスワイプしてください。"</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"音声入力はGoogleのネットワーク音声認識技術を利用した試験段階の機能です。"</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"音声入力をOFFにするには、キーボードの設定を開きます。"</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"音声入力するには、マイクボタンを押すか画面キーボードをスワイプしてください。"</string>
     <string name="voice_listening" msgid="467518160751321844">"お話しください"</string>
     <string name="voice_working" msgid="6666937792815731889">"処理中"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"ユーザーフィードバックを有効にする"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"IMEの機能向上のため、使用統計状況やクラッシュレポートをGoogleに自動送信します。"</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"タップして語句を再修正"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"入力した語句をタップすると語句を再修正できます"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"入力した語句をタップすると語句を再修正できます"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"キーボードテーマ"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"キーボード"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"音声"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-ko/config.xml b/java/res/values-ko/config.xml
new file mode 100644
index 0000000..e0e3a8e
--- /dev/null
+++ b/java/res/values-ko/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0.22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
index ab3aa91..6e69b64 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"빠른 수정"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"자주 발생하는 오타를 수정합니다."</string>
-    <string name="show_suggestions" msgid="507074425254289133">"추천 단어 표시"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"글자를 입력하는 동안 추천 단어를 표시"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"자동 완성"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"스페이스바와 문장부호 키로 강조 표시된 단어를 자동 삽입"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"설정 키 표시"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"자동"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"항상 표시"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"자동 완성"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"스페이스바와 문장부호 키로 강조 표시된 단어를 자동 삽입"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"사용안함"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"보통"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"적극적"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram 추천"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"이전 단어를 사용하여 추천 기능 개선"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"다음"</string>
     <string name="label_done_key" msgid="2441578748772529288">"완료"</string>
     <string name="label_send_key" msgid="2815056534433717444">"전송"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"더보기"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"탭"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"일시 중지"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"대기"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"음성 입력"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"음성 입력은 현재 자국어로 지원되지 않으며 영어로 작동됩니다."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"음성 입력은 Google의 네트워크화된 음성 인식을 사용하는 실험적 기능입니다."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"음성 입력을 사용하지 않으려면 키보드 설정으로 이동하세요."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"음성 입력을 사용하려면 마이크 버튼을 누르거나 터치 키보드 위로 손가락을 미끄러지듯 움직이세요."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"음성 입력은 Google의 네트워크화된 음성 인식을 사용하는 실험적 기능입니다."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"음성 입력을 사용하지 않으려면 키보드 설정으로 이동하세요."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"음성 입력을 사용하려면 마이크 버튼을 누르거나 터치 키보드 위로 손가락을 미끄러지듯 움직이세요."</string>
     <string name="voice_listening" msgid="467518160751321844">"지금 말하세요."</string>
     <string name="voice_working" msgid="6666937792815731889">"인식 중"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"사용자 의견 사용"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"사용 통계 및 충돌 보고서를 Google에 자동으로 전송하여 입력 방법 편집기의 개선에 도움을 줍니다."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"터치하여 단어 다시 수정"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"입력한 단어를 터치하면 다시 수정할 수 있습니다."</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"입력한 단어를 터치하면 다시 수정할 수 있습니다."</string>
     <string name="keyboard_layout" msgid="437433231038683666">"키보드 테마"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"키보드"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"음성"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
index 043f4b3..f7fc4b1 100644
--- a/java/res/values-land/dimens.xml
+++ b/java/res/values-land/dimens.xml
@@ -23,13 +23,14 @@
     <dimen name="key_height">0.250in</dimen>
     <dimen name="key_bottom_gap">0.020in</dimen>
     <dimen name="popup_key_height">0.270in</dimen>
+    <dimen name="keyboard_top_padding">0.0in</dimen>
     <dimen name="keyboard_bottom_padding">0.0in</dimen>
     <dimen name="candidate_strip_height">38dip</dimen>
     <dimen name="candidate_strip_fading_edge_length">63dip</dimen>
     <dimen name="spacebar_vertical_correction">2dip</dimen>
     <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
-    <!-- popup_key_height x 1.7 -->
-    <dimen name="mini_keyboard_slide_allowance">0.459in</dimen>
-    <!-- popup_key_height x 1.0 -->
+    <!-- popup_key_height x 1.2 -->
+    <dimen name="mini_keyboard_slide_allowance">0.324in</dimen>
+    <!-- popup_key_height x -1.0 -->
     <dimen name="mini_keyboard_vertical_correction">-0.270in</dimen>
 </resources>
diff --git a/java/res/values-lt/config.xml b/java/res/values-lt/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-lt/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml
new file mode 100644
index 0000000..dc897e7
--- /dev/null
+++ b/java/res/values-lt/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"„Android“ klaviatūra"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"„Android“ klaviatūros nustatymai"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibruoti, kai paspaudžiami klavišai"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Klavišo paspaudimo garsas"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Taisyti rašybos klaidas"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Įgalinti įvesties klaidos taisymą"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Gulsčia įvestis"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Įgalinti įvesties klaidos taisymą"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Žodžių pasiūlymai"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Automatiškai taisyti ankstesnį žodį"</string>
+    <string name="prediction" msgid="466220283138359837">"Žodžių pasiūlymai"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Žodžių pasiūlymo nustatymai"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Įgalinti automatinį užbaigimą, kai įvedinėjamas tekstas"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Automatinis užbaigimas"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Padidinti teksto lauko dydį"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Gulsčiame rodinyje slėpti žodžių pasiūlymus"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Automatinis didžiųjų raidžių rašymas"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Sakinio pradžią rašyti didžiąja raide"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Automatiškai dėti skyrybos ženklus"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Greiti pataisymai"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Taiso dažnai padarytas rašybos klaidas"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Automatiškai užbaigti"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Tarpo klavišas ir skyrybos ženklai automatiškai įterpia paryškintą žodį"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Nėra"</item>
+    <item msgid="1669461741568287396">"Paprastas"</item>
+    <item msgid="4894328801530136615">"Išplėstinis"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: išsaugota"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Laikykite klavišą nuspaudę, kad pamatytumėte kirčius (ø, ö ir t. t.)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Paspauskite klavišą „Atgal“ ↶, kad uždarytumėte klaviatūrą"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Pasiekti skaičius ir simbolius"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Paspauskite ir laikykite nuspaudę kairiausią žodį, kad pridėtumėte jį prie žodyno"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Palieskite šią užuominą, jei norite tęsti »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Paleiskite čia, kad uždarytumėte šią užuominą ir pradėtumėte įvedinėti tekstą!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Klaviatūra atsidarys kaskart, kai paliesite teksto lauką"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Palieskite ir laikykite klavišą, kad pamatytumėte kirčius"\n"(ø, ö, ô, ó, and so on)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Perjunkite į skaičius ir simbolius, paliesdami šį klavišą"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Grįžkite prie raidžių dar kartą paliesdami šį klavišą"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Palieskite ir laikykite šį klavišą, kad pakeistumėte klaviatūros nustatymus, pvz., automatinį užbaigimą"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Išbandykite tai!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Pradėti"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Kitas"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Atlikta"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Siųsti"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Balso įvestis"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Šiuo metu balso įvestis jūsų kompiuteryje nepalaikoma, bet ji veikia anglų k."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Balso įvestis – tai eksperimentinė funkcija, naudojanti „Google“ tinklo kalbos atpažinimą."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Jei norite išjungti balso įvestį, eikite į klaviatūros nustatymus."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Jei norite naudoti balso įvestį, paspauskite mikrofono mygtuką arba pirštu slyskite ekranine klaviatūra."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Kalbėkite dabar"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Veikia"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Klaida. Bandykite dar kartą."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Nepavyko prijungti"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Klaida, per daug kalbos."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Problema su garsu"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Serverio klaida"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Negirdima jokia kalba"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Atitikmenų nerasta"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Balso paieška neįdiegta"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Užuomina:"</b>" perbraukite klaviatūra, kad galėtumėte kalbėti"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Užuomina:"</b>" kitą kartą pabandykite sakyti skyrybos ženklų pavadinimus, pvz., „taškas“, „kablelis“ arba „klaustukas“."</string>
+    <string name="cancel" msgid="6830980399865683324">"Atšaukti"</string>
+    <string name="ok" msgid="7898366843681727667">"Gerai"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Balso įvestis"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"Pagrindinėje klaviatūroje"</item>
+    <item msgid="8529385602829095903">"Simbolių klaviatūroje"</item>
+    <item msgid="7283103513488381103">"Išjungta"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Pagrindinės klaviatūros mikrofonas"</item>
+    <item msgid="6907837061058876770">"Mikrofonas simbolių klaviatūroje"</item>
+    <item msgid="3664304608587798036">"Balso įvestis išjungta"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Automatiškai pateikti po balso"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Automatiškai spausti „Įvesti“ ieškant ar einant į kitą lauką."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Atidarykite klaviatūrą"\n</b></font><font size="3">\n</font>"Palieskite bet kurį teksto lauką."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Uždarykite klaviatūrą"\n</b></font><font size="3">\n</font>"Paspauskite klavišą „Atgal“."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Palieskite ir laikykite klavišą, kad pamatytumėte parinktis"\n</b></font><font size="3">\n</font>"Pasiekite skyrybos ženklus ir kirčius."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Klaviatūros nustatymai"\n</b></font><font size="3">\n</font>"Palieskite ir laikykite klavišą "<b>"?123"</b>"."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Įvesties kalbos"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Pirštu slyskite tarpo klavišu, kad pakeistumėte kalbą"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Bakstelėkite dar kartą, kad išsaugotumėte"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Žodynas galimas"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-lv/config.xml b/java/res/values-lv/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-lv/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
new file mode 100644
index 0000000..a451874
--- /dev/null
+++ b/java/res/values-lv/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Android tastatūra"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Android tastatūras iestatījumi"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrēt, nospiežot taustiņu"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Skaņa, nospiežot taustiņu"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Labot drukas kļūdas"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Iespējot ievades kļūdu labošanu"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Ainavas orientācijas ievades kļūdas"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Iespējot ievades kļūdu labošanu"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Vārdu ieteikumi"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Automātiski labot iepriekšējo vārdu"</string>
+    <string name="prediction" msgid="466220283138359837">"Vārdu ieteikumi"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Vārdu ieteikumu iestatījumi"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Iespējot automātisko pabeigšanu ievades laikā"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Automātiska pabeigšana"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Palielināt teksta lauka lielumu"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Ainavas skatījumā slēpt vārdu ieteikumus"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Automātiska lielo burtu lietošana"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Sākt teikumu ar lielo burtu"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Automātiska pieturzīmju lietošana"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Ātrie labojumi"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Nodrošina izplatītu drukas kļūdu labošanu."</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Automātiska pabeigšana"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Automātiski ievietot iezīmēto vārdu, izmantojot atstarpes taustiņu un pieturzīmes"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Nav"</item>
+    <item msgid="1669461741568287396">"Pamata"</item>
+    <item msgid="4894328801530136615">"Uzlabots"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: saglabāts"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Turiet taustiņu nospiestu, lai skatītu uzsvēruma zīmes (ø, ö u.c.)."</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Jebkurā brīdī nospiediet taustiņu Atpakaļ ↶, lai aizvērtu tastatūru."</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Piekļūt cipariem un simboliem"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Nospiediet kreisajā pusē esošo vārdu un turiet, lai pievienotu to vārdnīcai."</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Pieskarieties šim ieteikumam, lai turpinātu »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Pieskarieties šeit, lai aizvērtu šo ieteikumu un sāktu ievadi."</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Tastatūra tiek atvērta ikreiz, kad pieskaraties teksta laukam"</b>"."</string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Pieskarieties taustiņam un turiet, lai skatītu uzsvara zīmes"\n"(ø, ö, ô, ó utt.)."</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Pieskarieties šim taustiņam, lai izmantotu ciparus un simbolus."</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Vēlreiz pieskarieties šim taustiņam, lai atkal izmantotu burtus."</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Pieskarieties taustiņam un turiet, lai mainītu tastatūras iestatījumus, piemēram, automātisko pabeigšanu."</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Izmēģiniet to!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Sākt"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Tālāk"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Gatavs"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Sūtīt"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Balss ievade"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Balss ievade jūsu valodā pašlaik netiek atbalstīta, taču tā ir pieejama angļu valodā."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Balss ievade ir izmēģinājuma funkcija, kuras pamatā ir Google tīkla runas atpazīšanas līdzeklis."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Lai izslēgtu balss ievadi, atveriet tastatūras iestatījumus."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Lai izmantotu balss ievadi, nospiediet mikrofona pogu vai slidiniet pirkstus pāri ekrāna tastatūrai."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Runājiet!"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Notiek apstrāde"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Kļūda. Lūdzu, mēģiniet vēlreiz."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Nevar izveidot savienojumu."</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Kļūda, pārāk ilga balss ievade."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Audio problēma"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Servera kļūda"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Nekas nav dzirdams."</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Nav atrasta neviena atbilstība."</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Balss meklēšana nav instalēta."</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Ieteikums:"</b>" slidiniet pirkstu pār tastatūru, lai veiktu balss ievadi."</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Ieteikums:"</b>" nākamreiz mēģiniet izrunāt pieturzīmes, piemēram, “punkts”, “komats” vai “jautājuma zīme”."</string>
+    <string name="cancel" msgid="6830980399865683324">"Atcelt"</string>
+    <string name="ok" msgid="7898366843681727667">"Labi"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Balss ievade"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"Izmantojot galveno tastatūru"</item>
+    <item msgid="8529385602829095903">"Izmantojot simbolu tastatūru"</item>
+    <item msgid="7283103513488381103">"Izsl."</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Galvenās tastatūras mikrofons"</item>
+    <item msgid="6907837061058876770">"Simbolu tastatūras mikrofons"</item>
+    <item msgid="3664304608587798036">"Balss ievade ir atspējota"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Automātiski iesniegt pēc balss ievades"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Automātiski nospiest ievades taustiņu, meklējot vai pārejot uz nākamo lauku."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Tastatūras atvēršana"\n</b></font><font size="3">\n</font>"Pieskarieties jebkuram teksta laukam."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Tastatūras aizvēršana"\n</b></font><font size="3">\n</font>"Nospiediet taustiņu Atpakaļ."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Pieskarieties taustiņam un turiet, lai skatītu opcijas."\n</b></font><font size="3">\n</font>"Piekļūstiet pieturzīmēm un uzsvara zīmēm."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Tastatūras iestatījumi"\n</b></font><font size="3">\n</font>"Pieskarieties taustiņam "<b>"?123"</b>" un turiet."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Ievades valodas"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Slidiniet pirkstu uz atstarpes taustiņa, lai mainītu valodu"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Vēlreiz pieskarieties, lai saglabātu"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Ir pieejama vārdnīca."</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-nb/config.xml b/java/res/values-nb/config.xml
new file mode 100644
index 0000000..419f196
--- /dev/null
+++ b/java/res/values-nb/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0,22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-nb/donottranslate-altchars.xml b/java/res/values-nb/donottranslate-altchars.xml
index 6257dfc..2644029 100644
--- a/java/res/values-nb/donottranslate-altchars.xml
+++ b/java/res/values-nb/donottranslate-altchars.xml
@@ -33,5 +33,8 @@
     <string name="alternates_for_z">źžż</string>
     <string name="alternates_for_l">ł</string>
     <string name="alternates_for_v">w</string>
-    <string name="alternates_for_oe">œ</string>
+    <string name="keylabel_for_scandinavia_row2_10">ø</string>
+    <string name="keylabel_for_scandinavia_row2_11">æ</string>
+    <string name="alternates_for_scandinavia_row2_10">ö</string>
+    <string name="alternates_for_scandinavia_row2_11">ä</string>
 </resources>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
index c98b8f4..a0fa5f5 100644
--- a/java/res/values-nb/strings.xml
+++ b/java/res/values-nb/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Autokorrektur"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Retter vanlige stavefeil"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Vis forslag"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Vis foreslåtte ord under skriving"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Autofullføring"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"Mellomrom og punktum setter automatisk inn valgt ord"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Vis innstillingsnøkkel"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatisk"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Vis alltid"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Autofullføring"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Mellomrom og punktum setter automatisk inn valgt ord"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Av"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Moderat"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Omfattende"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram-forslag"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Bruk forrige ord til å forbedre forslaget"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Neste"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Utfør"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Send"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Mer"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Pause"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Vent"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Stemmedata"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Stemmedata håndteres foreløpig ikke på ditt språk, men fungerer på engelsk."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Talekommandoer er en eksperimentell funksjon som bruker Googles nettverksbaserte talegjenkjenning."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Gå til innstillinger for tastatur for å slå av stemmedata."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Du bruker talekommandoer ved å trykke på mikrofonknappen eller skyve fingeren over tastaturet på skjermen."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Talekommandoer er en eksperimentell funksjon som bruker Googles nettverksbaserte talegjenkjenning."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Gå til innstillinger for tastatur for å slå av stemmedata."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Du bruker talekommandoer ved å trykke på mikrofonknappen eller skyve fingeren over tastaturet på skjermen."</string>
     <string name="voice_listening" msgid="467518160751321844">"Snakk nå"</string>
     <string name="voice_working" msgid="6666937792815731889">"Arbeider"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Aktiver brukertilbakemelding"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Ved å sende bruksstatistikk og programstopprapporter til Google automatisk, hjelper du oss med å gjøre redigeringsfunksjonen for denne inndatametoden enda bedre."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Trykk for å endre ord"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Du kan endre innskrevne ord ved å trykke på dem"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Du kan endre innskrevne ord ved å trykke på dem"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tastaturtema"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"tastatur"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"stemme"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-nl/config.xml b/java/res/values-nl/config.xml
new file mode 100644
index 0000000..419f196
--- /dev/null
+++ b/java/res/values-nl/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0,22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
index c907344..72ca39d 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Snelle oplossingen"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Hiermee worden veelvoorkomende typefouten gecorrigeerd"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Suggesties weergeven"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Voorgestelde woorden weergeven tijdens typen"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Auto-aanvullen"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"Gemarkeerd woord automatisch invoegen met spatiebalk en interpunctie"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Instellingscode weergeven"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatisch"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Altijd weergeven"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Auto-aanvullen"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Gemarkeerd woord automatisch invoegen met spatiebalk en interpunctie"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Uit"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Normaal"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Agressief"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Digram-suggesties"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Vorig woord gebruiken om suggestie te verbeteren"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Volgende"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Gereed"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Verzenden"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"Alt"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Meer"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Onderbr."</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Wacht"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Spraakinvoer"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Spraakinvoer wordt momenteel niet ondersteund in uw taal, maar is wel beschikbaar in het Engels."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Spraakinvoer is een experimentele functie met de spraakherkenning van het Google-netwerk."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Als u spraakinvoer wilt uitschakelen, gaat u naar de toetsenbordinstellingen."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Als u spraakinvoer gebruikt, drukt u op de microfoonknop of schuift u uw vinger over het schermtoetsenbord."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Spraakinvoer is een experimentele functie met de spraakherkenning van het Google-netwerk."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Als u spraakinvoer wilt uitschakelen, gaat u naar de toetsenbordinstellingen."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Als u spraakinvoer gebruikt, drukt u op de microfoonknop of schuift u uw vinger over het schermtoetsenbord."</string>
     <string name="voice_listening" msgid="467518160751321844">"Nu spreken"</string>
     <string name="voice_working" msgid="6666937792815731889">"Wordt uitgevoerd"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Gebruikersfeedback inschakelen."</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Help deze invoermethode te verbeteren door automatisch gebruiksstatistieken en crashmeldingen naar Google te verzenden."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Raak aan om woorden opnieuw te corrigeren"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"U kunt woorden opnieuw corrigeren door woorden aan te raken die u heeft getypt"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"U kunt woorden opnieuw corrigeren door woorden aan te raken die u heeft getypt"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Toetsenbordthema"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"toetsenbord"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"spraak"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-pl/config.xml b/java/res/values-pl/config.xml
new file mode 100644
index 0000000..419f196
--- /dev/null
+++ b/java/res/values-pl/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0,22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
index a2f429e..175e52f 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Szybkie poprawki"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Poprawia częste błędy wpisywania"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Pokaż sugestie"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Wyświetl sugerowane słowa podczas wpisywania"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Autouzupełnianie"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"Spacja i znaki przestankowe wstawiają wyróżnione słowo"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Pokaż klawisz ustawień"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatycznie"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Zawsze pokazuj"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Autouzupełnianie"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Spacja i znaki przestankowe wstawiają wyróżnione słowo"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Wyłączone"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Umiarkowane"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Agresywne"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Sugestie dla bigramów"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Używaj poprzedniego wyrazu, aby polepszyć sugestię"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Dalej"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Gotowe"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Wyślij"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Więcej"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Pauza"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Czekaj"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Wprowadzanie głosowe"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Wprowadzanie głosowe obecnie nie jest obsługiwane w Twoim języku, ale działa w języku angielskim."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Wprowadzanie głosowe to funkcja eksperymentalna wykorzystująca funkcję firmy Google umożliwiającą rozpoznawanie mowy przy użyciu sieci."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Aby wyłączyć wprowadzanie głosowe, przejdź do ustawień klawiatury."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Aby skorzystać z wprowadzania głosowego, naciśnij przycisk mikrofonu lub przesuń palcem po klawiaturze ekranowej."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Wprowadzanie głosowe to funkcja eksperymentalna wykorzystująca funkcję firmy Google umożliwiającą rozpoznawanie mowy przy użyciu sieci."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Aby wyłączyć wprowadzanie głosowe, przejdź do ustawień klawiatury."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Aby skorzystać z wprowadzania głosowego, naciśnij przycisk mikrofonu lub przesuń palcem po klawiaturze ekranowej."</string>
     <string name="voice_listening" msgid="467518160751321844">"Mów teraz"</string>
     <string name="voice_working" msgid="6666937792815731889">"W toku"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Włącz przesyłanie opinii użytkownika"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Pomóż ulepszyć edytor tej metody wprowadzania, automatycznie wysyłając do Google statystyki użycia i raporty o awariach."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Dotknij, aby ponownie poprawić słowa"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Możesz ponownie poprawiać wprowadzone słowa, dotykając ich"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Możesz ponownie poprawiać wprowadzone słowa, dotykając ich"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Motyw klawiatury"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"klawiatura"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"głosowe"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-pt-rPT/config.xml b/java/res/values-pt-rPT/config.xml
new file mode 100644
index 0000000..419f196
--- /dev/null
+++ b/java/res/values-pt-rPT/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0,22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index 01d96ed..f99485d 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Correcções rápidas"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corrige os erros de escrita comuns"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Mostrar sugestões"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Apresentar sugestões de palavras ao escrever"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Conclusão automática"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"A barra de espaços e a pontuação inserem automaticamente uma palavra realçada"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Mostrar tecla das definições"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automático"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Mostrar sempre"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Conclusão automática"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"A barra de espaços e a pontuação inserem automaticamente uma palavra realçada"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Desactivar"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Moderada"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Agressiva"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Sugestões Bigram"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Utilizar a palavra anterior para melhorar a sugestão"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Seguinte"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Feito"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Mais"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Esp."</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Entrada de voz"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Actualmente, a entrada de voz não é suportada para o seu idioma, mas funciona em inglês."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"A entrada de voz é uma funcionalidade experimental que utiliza o reconhecimento de voz em rede da Google."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Para desactivar a entrada de voz, aceda às definições do teclado."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Para utilizar a entrada de voz, prima o botão do microfone ou deslize o dedo no teclado do ecrã."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"A entrada de voz é uma funcionalidade experimental que utiliza o reconhecimento de voz em rede da Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Para desactivar a entrada de voz, aceda às definições do teclado."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Para utilizar a entrada de voz, prima o botão do microfone ou deslize o dedo no teclado do ecrã."</string>
     <string name="voice_listening" msgid="467518160751321844">"Falar agora"</string>
     <string name="voice_working" msgid="6666937792815731889">"A executar"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Activar comentários do utilizador"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Envie automaticamente estatísticas de utilização e relatórios de falhas para a Google e ajude-nos a melhor este editor de método de introdução."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tocar para voltar a corrigir palavras"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Pode voltar a corrigir palavras tocando naquelas que escreveu"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Pode voltar a corrigir palavras tocando naquelas que escreveu"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema do teclado"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"teclado"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"voz"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-pt/config.xml b/java/res/values-pt/config.xml
new file mode 100644
index 0000000..e0e3a8e
--- /dev/null
+++ b/java/res/values-pt/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0.22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index 0acaf25..8be591f 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Reparos rápidos"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Corrige erros comuns de digitação"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Mostrar sugestões"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Exibir sugestões de palavras durante a digitação"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Conclusão automática"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"Barra de espaço e pontuação inserem a palavra destacada"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Mostrar tecla de configurações"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automático"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Mostrar sempre"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Conclusão automática"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Barra de espaço e pontuação inserem a palavra destacada"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Desativado"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Moderado"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Agressivo"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Sugestões de bigrama"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Usar palavra anterior para melhorar a sugestão"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Avançar"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Feito"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Enviar"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Mais"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Esp."</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Entrada de voz"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"A entrada de voz não é suportada no momento para o seu idioma, mas funciona em inglês."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"A entrada de voz é um recurso experimental que usa o reconhecimento de fala de rede do Google."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Para desativar a entrada de voz, vá para as configurações do teclado."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Para usar a entrada de voz, pressione o botão com o microfone ou deslize o dedo sobre o teclado na tela."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"A entrada de voz é um recurso experimental que usa o reconhecimento de fala de rede do Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Para desativar a entrada de voz, vá para as configurações do teclado."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Para usar a entrada de voz, pressione o botão com o microfone ou deslize o dedo sobre o teclado na tela."</string>
     <string name="voice_listening" msgid="467518160751321844">"Fale agora"</string>
     <string name="voice_working" msgid="6666937792815731889">"Trabalhando"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Ativar comentário do usuário"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Ajude a melhorar este editor de método de entrada enviando automaticamente ao Google estatísticas de uso e relatórios de falhas."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Toque para corrigir novamente as palavras"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Você pode fazer novamente a correção tocando nas palavras digitadas"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Você pode fazer novamente a correção tocando nas palavras digitadas"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tema do teclado"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"teclado"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"voz"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-rm/config.xml b/java/res/values-rm/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-rm/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-rm/strings.xml b/java/res/values-rm/strings.xml
index 91dbf72..f7b54be 100644
--- a/java/res/values-rm/strings.xml
+++ b/java/res/values-rm/strings.xml
@@ -22,10 +22,11 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="english_ime_name" msgid="7252517407088836577">"Tastatura Android"</string>
     <string name="english_ime_settings" msgid="6661589557206947774">"Parameters da la tastatura Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
     <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrar cun smatgar in buttun"</string>
     <string name="sound_on_keypress" msgid="6093592297198243644">"Tun cun smatgar in buttun"</string>
-    <!-- no translation found for popup_on_keypress (123894815723512944) -->
-    <skip />
+    <string name="popup_on_keypress" msgid="123894815723512944">"Pop-up cun smatgar ina tasta"</string>
     <string name="hit_correction" msgid="4855351009261318389">"Curreger sbagls d\'endataziun"</string>
     <string name="hit_correction_summary" msgid="8761701873008070796">"Activar la correctura da sbagls d\'endataziun"</string>
     <string name="hit_correction_land" msgid="2567691684825205448">"Sbagls d\'endataziun en il format orizontal"</string>
@@ -44,45 +45,81 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Correcturas sveltas"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Curregia sbagls da tippar currents"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Mussar las propostas"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Mussar pleds proponids durant l\'endataziun"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
     <string name="auto_complete" msgid="1103196318775486023">"Cumplettaziun automatica"</string>
     <string name="auto_complete_summary" msgid="6113149638718274624">"Inserir auto. il pled marcà cun la tasta da vid/interpuncziun"</string>
-    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
     <skip />
-    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
     <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <string name="bigram_suggestion" msgid="1323347224043514969">"Propostas da tip bigram"</string>
+    <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Meglierar la proposta cun agid dal pled precedent"</string>
   <string-array name="prediction_modes">
     <item msgid="4870266572388153286">"Nagin"</item>
     <item msgid="1669461741568287396">"Simpel"</item>
     <item msgid="4894328801530136615">"Avanzà"</item>
   </string-array>
     <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Memorisà"</string>
-    <string name="tip_long_press" msgid="6101270866284343344">"Tegnair smatgà per mussar ils accents (à, é, etc.)"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"\"Tegnair smatgà per mussar ils accents (à, é, etc.)\""</string>
     <string name="tip_dismiss" msgid="7585579046862204381">"Smatgar ↶ per serrar la tastatura"</string>
     <string name="tip_access_symbols" msgid="6344098517525531652">"Acceder a cifras e simbols"</string>
     <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Smatgar ditg sin il pled dal tut a sanestra per l\'agiuntar al dicziunari"</string>
     <string name="touch_to_continue" msgid="7869803257948414531">"Tutgar quest commentari per cuntinuar »"</string>
-    <string name="touch_to_finish" msgid="7990196086480585789">"Tutgar qua, per serrar quest commentari e cumenzar a tippar!"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"\"Tutgar qua, per serrar quest commentari e cumenzar a tippar!\""</string>
     <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"La tastatura vegn adina averta sche Vus tutgais in champ da text."</b></string>
-    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Tegnai smatgà ina tasta per mussar ils segns spezials"\n"(ø, ö, ô, ó etc.)."</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501">"\""<b>"Tegnai smatgà ina tasta per mussar ils segns spezials"\n"(ø, ö, ô, ó etc.)."</b>"\""</string>
     <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Midai a numers e simbols cun tutgar quest buttun."</b></string>
     <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Turnai a letras cun smatgar danovamain quest buttun."</b></string>
-    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Tegnai smatgà quest buttun per midar ils parameters da tastatura, sco p. ex. la cumplettaziun automatica."</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128">"\""<b>"Tegnai smatgà quest buttun per midar ils parameters da tastatura, sco p. ex. la cumplettaziun automatica."</b>"\""</string>
     <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Empruvai!"</b></string>
     <string name="label_go_key" msgid="1635148082137219148">"Dai"</string>
     <string name="label_next_key" msgid="362972844525672568">"Vinavant"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Finì"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Trametter"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
     <string name="voice_warning_title" msgid="4419354150908395008">"Cumonds vocals"</string>
-    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Cumonds vocals en Vossa lingua na vegnan actualmain betg sustegnids, ma la funcziun è disponibla per englais."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Ils cumonds vocals èn ina funcziunalitad experimentala che utilisescha la renconuschientscha vocala da rait da Google."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Per deactivar ils cumonds vocals, avri ils parameters da tastatura."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Per utilisar ils cumonds vocals, smatgai il buttun dal microfon u stritgai cun il det sur la tastatura dal visur."</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"\"Cumonds vocals en Vossa lingua na vegnan actualmain betg sustegnids, ma la funcziun è disponibla per englais.\""</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Ils cumonds vocals èn ina funcziunalitad experimentala che utilisescha la renconuschientscha vocala da rait da Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"\"Per deactivar ils cumonds vocals, avri ils parameters da tastatura.\""</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"\"Per utilisar ils cumonds vocals, smatgai il buttun dal microfon u stritgai cun il det sur la tastatura dal visur.\""</string>
     <string name="voice_listening" msgid="467518160751321844">"Ussa discurrer"</string>
     <string name="voice_working" msgid="6666937792815731889">"Operaziun en progress"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -95,7 +132,7 @@
     <string name="voice_no_match" msgid="4285117547030179174">"Betg chattà correspundenzas"</string>
     <string name="voice_not_installed" msgid="5552450909753842415">"Betg installà la tschertga vocala"</string>
     <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Commentari:"</b>" Stritgai cun il det sur la tastatura per discurrer."</string>
-    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Commentari:"</b>" Empruvai la proxima giada d\'agiuntar segns d\'interpuncziun sco \"punct\", \"comma\" u \"segn da dumonda\" cun cumonds vocals."</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754">"\""<b>"Commentari:"</b>" Empruvai la proxima giada d\'agiuntar segns d\'interpuncziun sco \"\"punct\"\", \"\"comma\"\" u \"\"segn da dumonda\"\" cun cumonds vocals.\""</string>
     <string name="cancel" msgid="6830980399865683324">"Interrumper"</string>
     <string name="ok" msgid="7898366843681727667">"OK"</string>
     <string name="voice_input" msgid="2466640768843347841">"Cumonds vocals"</string>
@@ -112,7 +149,7 @@
     <string name="auto_submit" msgid="9151008027068358518">"Trametter automaticamain suenter il cumond vocal"</string>
     <string name="auto_submit_summary" msgid="4961875269610384226">"Smatgai sin la tasta enter sche Vus exequis ina tschertga u siglis al proxim champ."</string>
     <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Avrir la tastatura"\n</b></font><font size="3">\n</font>"Tutgai inqual champ da text."</string>
-    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Serrar la tastatura"\n</b></font><font size="3">\n</font>"Smatgai il buttun \"Enavos\"."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103">"\""<font size="17"><b>"Serrar la tastatura"\n</b></font><font size="3">\n</font>"Smatgai il buttun \"\"Enavos\"\".\""</string>
     <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Tutgar e tegnair smatgà in buttun per acceder a las opziuns"\n</b></font><font size="3">\n</font>"Accedi a segns d\'interpuncziun ed accents."</string>
     <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Parameters da tastatura"\n</b></font><font size="3">\n</font>"Tutgai e tegnai smatgà il buttun "<b>"?123"</b>"."</string>
     <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
@@ -120,16 +157,87 @@
     <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
     <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
     <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
     <string name="language_selection_title" msgid="1651299598555326750">"Linguas da cumonds vocals"</string>
     <string name="language_selection_summary" msgid="187110938289512256">"Stritgar cun il det sur la tasta da vid per midar la lingua"</string>
-    <string name="hint_add_to_dictionary" msgid="8058519710062071085">"← Tippar danovamain per memorisar"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Tippar danovamain per memorisar"</string>
     <string name="has_dictionary" msgid="6071847973466625007">"Dicziunari disponibel"</string>
-    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <string name="prefs_enable_log" msgid="6620424505072963557">"Activar il feedback da l\'utilisader"</string>
+    <string name="prefs_description_log" msgid="5827825607258246003">"Gidai a meglierar quest editur da la metoda d\'endataziun cun trametter automaticamain datas statisticas davart l\'utilisaziun e rapports da collaps a Google."</string>
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
     <skip />
-    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
     <skip />
-    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <string name="keyboard_layout" msgid="437433231038683666">"Design da la tastatura"</string>
+    <string name="subtype_mode_keyboard" msgid="2242090416595003881">"tastatura"</string>
+    <string name="subtype_mode_voice" msgid="4394113125441627771">"vusch"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
     <skip />
-    <!-- no translation found for prefs_debug_mode (3889340783846594980) -->
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
     <skip />
 </resources>
diff --git a/java/res/values-ro/config.xml b/java/res/values-ro/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-ro/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
new file mode 100644
index 0000000..659d84c
--- /dev/null
+++ b/java/res/values-ro/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Tastatură Android"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Setările tastaturii Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibrare la apăsarea tastei"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Sunet la apăsarea tastei"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Corectaţi erorile de dactilografiere"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Activaţi corectarea erorii de intrare"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Erori de introducere în modul peisaj"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Activaţi corectarea erorii de intrare"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Sugestii de cuvinte"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Corecţie automată a cuvântului anterior"</string>
+    <string name="prediction" msgid="466220283138359837">"Sugestii de cuvinte"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Setările sugestiei de cuvinte"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Activaţi completarea automată în timpul introducerii textului"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Completare automată"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Măriţi dimensiunea câmpului text"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Ascundeţi sugestiile de cuvinte în vizualizarea de tip peisaj"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Auto-capitalizare"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Doresc să se scrie cu majusculă începutul propoziţiilor"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Punctuaţie automată"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Remedieri rapide"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Corectează greşelile introduse frecvent"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Completare automată"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Bara de spaţiu şi punctuaţia inserează automat un cuvânt evidenţiat"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Niciunul"</item>
+    <item msgid="1669461741568287396">"De bază"</item>
+    <item msgid="4894328801530136615">"Avansat"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: salvat"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Ţineţi o tastă apăsată pentru a vedea accentele (ø, ö, etc.)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Apăsaţi tasta Înapoi ↶ pentru a închide oricând tastatura"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Accesaţi numere şi simboluri"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Apăsaţi şi ţineţi apăsat pe cuvântul cel mai din stânga, pentru a-l adăuga la dicţionar"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Atingeţi acest indiciu pentru a continua »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Atingeţi aici pentru a închide acest indiciu şi începeţi să introduceţi text!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Tastatura se deschide de fiecare dată când atingeţi un câmp text"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Atingeţi şi ţineţi apăsată o tastă pentru a vizualiza accentele"\n"(ø, ö, ô, ó etc.)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Comutaţi între numere şi simboluri atingând această tastă"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Reveniţi la litere prin atingerea acestei taste din nou"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Apăsaţi şi ţineţi apăsată această tastă pentru a schimba setările tastaturii, cum ar fi completarea automată"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Încercaţi!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Accesaţi"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Înainte"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Terminat"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Trimiteţi"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Intrare voce"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Intrarea vocală nu este acceptată în prezent pentru limba dvs., însă funcţionează în limba engleză."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Intrarea vocală este o funcţie experimentală ce utilizează recunoaşterea vocală în reţea oferită de Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Pentru a dezactiva intrarea vocală, accesaţi setările tastaturii."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Pentru a utiliza intrarea vocală, apăsaţi butonul de microfon sau glisaţi degetul de-a lungul tastaturii de pe ecran."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Vorbiţi acum"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Se analizează"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Eroare. Încercaţi din nou."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Conectare imposibilă"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Eroare, discurs prea lung."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Problemă audio"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Eroare de server"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Nu s-a auzit vorbirea"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Nicio potrivire"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Căutarea vocală nu este instalată"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Indiciu:"</b>" glisaţi de-a lungul tastaturii pentru a vorbi"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Indiciu:"</b>" data viitoare, încercaţi să rostiţi şi punctuaţia, cum ar fi „punct”, „virgulă”, sau „semn de întrebare”."</string>
+    <string name="cancel" msgid="6830980399865683324">"Anulaţi"</string>
+    <string name="ok" msgid="7898366843681727667">"OK"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Intrare voce"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"Pe tastatura principală"</item>
+    <item msgid="8529385602829095903">"Pe tastatura de simboluri"</item>
+    <item msgid="7283103513488381103">"Dezactivat"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Microfon pe tastatura principală"</item>
+    <item msgid="6907837061058876770">"Microfon pe tastatura de simboluri"</item>
+    <item msgid="3664304608587798036">"Intrarea vocală este dezactivată"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Trimitere automată după intrarea vocală"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Apăsaţi automat tasta Enter atunci când se face o căutare sau când se trece la câmpul următor."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Deschideţi tastatura"\n</b></font><font size="3">\n</font>"Atingeţi orice câmp de text."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Închideţi tastatura"\n</b></font><font size="3">\n</font>"Apăsaţi pe tasta Înapoi."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Atingeţi şi ţineţi apăsată o tastă pentru opţiuni"\n</b></font><font size="3">\n</font>"Accesaţi punctuaţia şi accentele."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Setările tastaturii"\n</b></font><font size="3">\n</font>"Atingeţi şi ţineţi apăsată tasta "<b>"?123"</b>"."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Selectaţi limba"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Glisaţi degetul pe bara de spaţiu pentru a schimba limba"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Apăsaţi din nou pentru a salva"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Dicţionar disponibil"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-ru/config.xml b/java/res/values-ru/config.xml
new file mode 100644
index 0000000..419f196
--- /dev/null
+++ b/java/res/values-ru/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0,22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index ae5e391..fe27d18 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Быстрое исправление"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Исправлять распространенные опечатки"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Предлагать варианты"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Предлагать варианты слов во время ввода"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Автозавершение"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"При нажатии пробела вставлять предложенное слово"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Показывать кнопку настроек"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Автоматически"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Всегда показывать"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Автозавершение"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"При нажатии пробела вставлять предложенное слово"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Выключено"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Умеренное"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Активное"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Биграммные подсказки"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Используйте предыдущее слово, чтобы исправить подсказку"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Далее"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Отправить"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"АБВ"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Еще"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Приостановить"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Подождите"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Голосовой ввод"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"В настоящее время функция голосового ввода не поддерживает ваш язык, но вы можете пользоваться ей на английском."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Голосовой ввод – экспериментальная функция на основе технологии сетевого распознавания речи от Google."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Функция голосового ввода отключается в настройках клавиатуры."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Чтобы использовать голосовой ввод, нажмите кнопку микрофона или проведите пальцем по экранной клавиатуре."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Голосовой ввод – экспериментальная функция на основе технологии сетевого распознавания речи от Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Функция голосового ввода отключается в настройках клавиатуры."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Чтобы использовать голосовой ввод, нажмите кнопку микрофона или проведите пальцем по экранной клавиатуре."</string>
     <string name="voice_listening" msgid="467518160751321844">"Говорите"</string>
     <string name="voice_working" msgid="6666937792815731889">"Выполняется обработка"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Включить отправку сведений"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Помогите усовершенствовать редактор способа ввода, разрешив отправку статистики и отчетов о сбоях в Google."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Исправление нажатием"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Нажмите на слово, чтобы исправить его"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Нажмите на слово, чтобы исправить его"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Вид клавиатуры"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"клавиатура"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"голосовой"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-sk/config.xml b/java/res/values-sk/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-sk/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
new file mode 100644
index 0000000..745e27e
--- /dev/null
+++ b/java/res/values-sk/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Klávesnica Android"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Nastavenia klávesnice Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Pri stlačení klávesu vibrovať"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Zvuk pri stlačení klávesu"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Opravovať preklepy"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Povoliť opravu chýb vstupu"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Chyby vstupu v zobrazení na šírku"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Povoliť opravu chýb vstupu"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Návrhy slov"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Automaticky opraviť predchádzajúce slovo"</string>
+    <string name="prediction" msgid="466220283138359837">"Návrhy slov"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Nastavenia návrhov slov"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Povoliť automatické dokončovanie pri písaní"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Automatické dokončovanie"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Zväčšiť textové pole"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Skryť návrhy slov v zobrazení na šírku"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Veľké písmená automaticky"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Začať vetu veľkým písmenom"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Automatická interpunkcia"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Rýchle opravy"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Opravuje najčastejšie chyby pri písaní"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Automatické dokončovanie"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Stlačením medzerníka alebo interpunkčného znamienka automaticky vložíte zvýraznené slovo."</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Žiadne"</item>
+    <item msgid="1669461741568287396">"Základné"</item>
+    <item msgid="4894328801530136615">"Rozšírené"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Uložené"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Podržaním klávesu zobrazíte diakritiku (á, ž atď.)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Stlačením klávesu Späť ↶ môžete klávesnicu kedykoľvek zavrieť."</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Prístup k číslam a symbolom"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Stlačením a podržaním slova úplne vľavo toto slovo pridáte do slovníka."</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Ak chcete pokračovať, dotknite sa tohto tipu »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Ak chcete tento tip zavrieť a začať písať, dotknite sa tu."</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Klávesnica sa otvorí vždy, keď sa dotknete textového poľa."</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Pridržaním klávesu zobrazíte diakritiku"\n"(ó, ø, ö, ô apod.)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Ak chcete prepnúť na režim zadávania číslic a symbolov, dotknite sa tohto klávesu."</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Ak chcete prejsť späť na zadávanie písmen, dotknite sa znova tohto klávesu."</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Pridržaním tohto klávesu zmeníte nastavenia klávesnice (napr. automatické dokončovanie)."</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Skúste si to."</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Hľadať"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Ďalej"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Hotovo"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Odoslať"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Hlasový vstup"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Pre váš jazyk aktuálne nie je hlasový vstup podporovaný, ale funguje v angličtine."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Hlasový vstup je experimentálna funkcia, ktorá využíva sieťové rozpoznanie reči spoločnosti Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Ak chcete vypnúť hlasový vstup, prejdite na nastavenia klávesnice."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Ak chcete použiť hlasový vstup, stlačte tlačidlo mikrofónu alebo prejdite prstom po klávesnici na obrazovke."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Hovorte"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Prebieha spracovanie"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Chyba. Skúste to znova."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Pripojenie sa nepodarilo."</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Chyba, reč je príliš dlhá."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Problém so zvukom"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Chyba servera"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Nebola zistená žiadna reč."</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Nenašli sa žiadne zhody"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Hlasové vyhľadávanie nie je nainštalované"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Tip:"</b>" Ak chcete aktivovať hlasový vstup, prejdite prstom po klávesnici."</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Tip:"</b>" Nabudúce skúste vysloviť interpunkciu, napríklad „bodka“, „čiarka“ alebo „otáznik“."</string>
+    <string name="cancel" msgid="6830980399865683324">"Zrušiť"</string>
+    <string name="ok" msgid="7898366843681727667">"OK"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Hlasový vstup"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"Na hlavnej klávesnici"</item>
+    <item msgid="8529385602829095903">"Na klávesnici so symbolmi"</item>
+    <item msgid="7283103513488381103">"Vypnuté"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Mikrofón na hlavnej klávesnici"</item>
+    <item msgid="6907837061058876770">"Mikrofón na klávesnici so symbolmi"</item>
+    <item msgid="3664304608587798036">"Hlasový vstup je zakázaný"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Po hlasovom vstupe automaticky odoslať"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Pri vyhľadávaní alebo prechode na ďalšie pole automaticky stlačiť kláves Enter."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Otvorte klávesnicu"\n</b></font><font size="3">\n</font>"Dotknite sa ľubovoľného textového poľa."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Zatvorte klávesnicu"\n</b></font><font size="3">\n</font>"Stlačte tlačidlo Späť."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Dotknutím a pridržaním klávesu zobrazíte možnosti"\n</b></font><font size="3">\n</font>"Prístup k interpunkčným znamienkam a diakritike."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Nastavenia klávesnice"\n</b></font><font size="3">\n</font>"Dotknite sa klávesu "<b>"?123"</b>" a podržte ho."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".sk"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".net"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".eu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Jazyky vstupu"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Jazyk môžete zmeniť posunutím prsta po medzerníku."</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Uložte slovo opätovným klepnutím"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"K dispozícii je slovník"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-sl/config.xml b/java/res/values-sl/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-sl/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
new file mode 100644
index 0000000..139a950
--- /dev/null
+++ b/java/res/values-sl/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Tipkovnica Android"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Nastavitve tipkovnice Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Vibriranje ob pritisku tipke"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Zvok ob pritisku tipke"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Popravljanje tipkarskih napak"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Omogoči popravljanje napak pri vnosu"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Napake pri vnosu v ležečem položaju"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Omogoči popravljanje napak pri vnosu"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Predlogi besed"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Samodejno popravi prejšnjo besedo"</string>
+    <string name="prediction" msgid="466220283138359837">"Predlogi besed"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Nastavitve za predlaganje besede"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Omogoči samodokončanje med tipkanjem"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Samodokončanje"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Povečaj velikost besedilnega polja"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Skrij predloge besed v ležečem pogledu"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Samodejne velike začetnice"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Napiši začetek stavka z veliko začetnico"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Samodejno vstavljanje ločil"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Hitri popravki"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Popravi pogoste tipkarske napake"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Samodokončanje"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Preslednica in ločila samodejno vnesejo označeno besedo"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Brez"</item>
+    <item msgid="1669461741568287396">"Osnovni"</item>
+    <item msgid="4894328801530136615">"Dodatno"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g>: shranjeno"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Držite tipko, da prikažete poudarke (ø, ö itd.)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Kadar koli lahko pritisnete tipko »Nazaj« ↶, da zaprete tipkovnico"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Dostop do številk in simbolov"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Če besedo želite dodati v slovar, jo pridržite"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Dotaknite se tega nasveta za nadaljevanje »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Dotaknite se tukaj, da zaprete nasvet in začnete tipkati!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Tipkovnice se odpre, kadar se dotaknete besedilnega polja"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Za ogled poudarkov pridržite tipko"\n"(ø, ö, ô, ó itd.)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Preklopite na številke in simbole z dotikom te tipke"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Na črke se vrnete, če se še enkrat dotaknete te tipke"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Pridržite to tipko, če želite spremeniti nastavitve tipkovnice, npr. samodokončanje"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Poskusite!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Pojdi"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Naprej"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Dokončano"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Pošlji"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Glasovni vnos"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Glasovni vnos trenutno ni podprt v vašem jeziku, deluje pa v angleščini."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Glasovni vnos je poskusna funkcija, ki uporablja Googlovo omrežno prepoznavanje govora."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Če želite izklopiti glasovni vnos, pojdite na nastavitve tipkovnice."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Če želite uporabiti glasovni vnos, pritisnite gumb z mikrofonom ali podrsajte s prstom po zaslonski tipkovnici."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Začnite govoriti"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Obdelava"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Napaka. Poskusite znova."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Povezava ni mogoča"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Napaka, preveč govora."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Težave z zvokom"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Napaka strežnika"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Govora se ne sliši"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Ni rezultatov"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Glasovno iskanje ni nameščeno"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Nasvet:"</b>" za govorjenje s prstom povlecite po tipkovnici"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Nasvet:"</b>" naslednjič poskusite ločila izgovoriti, npr. »pika«, »vejica« ali »vprašaj«."</string>
+    <string name="cancel" msgid="6830980399865683324">"Prekliči"</string>
+    <string name="ok" msgid="7898366843681727667">"V redu"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Glasovni vnos"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"Na glavni tipkovnici"</item>
+    <item msgid="8529385602829095903">"Na tipkovnici s simboli"</item>
+    <item msgid="7283103513488381103">"Izklopljeno"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Mikrofon na glavni tipkovnici"</item>
+    <item msgid="6907837061058876770">"Mikrofon na tipkovnici s simboli"</item>
+    <item msgid="3664304608587798036">"Glasovni vnos je onemogočen"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Samodejno pošlji po govoru"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Samodejno pritisni »Enter« pri iskanju ali prehodu na naslednje polje."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Odprite tipkovnico"\n</b></font><font size="3">\n</font>"Dotaknite se katerega koli besedilnega polja."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Zaprite tipkovnico"\n</b></font><font size="3">\n</font>"Pritisnite tipko »Nazaj«."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Pridržite tipko za ogled možnosti"\n</b></font><font size="3">\n</font>"Dostop do ločil in poudarkov."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Nastavitve "\n</b></font><font size="3">\n</font>"Pridržite tipko "<b>"?123"</b>"."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Jeziki vnosa"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Podrsajte s prstom po preslednici, da zamenjate jezik"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Znova tapnite, da shranite"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Slovar je na voljo"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-sr/config.xml b/java/res/values-sr/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-sr/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index 4da1c05..8694ec7 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
 /*
 **
 ** Copyright 2008, The Android Open Source Project
@@ -16,281 +16,236 @@
 ** 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">
-    <!-- Title for Latin keyboard  -->
-    <string name="english_ime_name">Андроидова тастатура</string>
-    <!-- Title for Latin keyboard settings activity / dialog -->
-    <string name="english_ime_settings">Подешавања андроидове тастатуре</string>
+ -->
 
-    <!-- Option to provide vibrate/haptic feedback on keypress -->
-    <string name="vibrate_on_keypress">Вибрације при притиску</string>
-    <!-- Option to play back sound on keypress in soft keyboard -->
-    <string name="sound_on_keypress">Звук при притиску</string>
-
-    <!-- Option to enable using nearby keys when correcting/predicting -->
-    <string name="hit_correction">Исправљање грешака</string>
-
-    <!-- Description for hit_correction  -->
-    <string name="hit_correction_summary">Исправљање грешака при уносу</string>
-
-    <!-- Option to enable using nearby keys when correcting/predicting in landscape-->
-    <string name="hit_correction_land">Грешке при водоравној оријентацији</string>
-
-    <!-- Description for hit_correction in landscape -->
-    <string name="hit_correction_land_summary">Исправљање грешака при уносу при
-        водоравном положају</string>
-
-    <!-- Option to automatically correct word on hitting space -->
-    <string name="auto_correction">Предлози речи</string>
-
-    <!-- Description for auto_correction -->
-    <string name="auto_correction_summary">Аутоматска исправка претходно унесене речи</string>
-
-    <!-- Option to enable text prediction -->
-    <string name="prediction">Предлози речи</string>
-    <!-- Category title for text prediction -->
-    <string name="prediction_category">Подешавања за предлоге речи</string>
-    <!-- Description for text prediction -->
-    <string name="prediction_summary">Укључи аутоматске наставке при уносу</string>
-
-    <!-- Dialog title for auto complete choices -->
-    <string name="auto_complete_dialog_title">Аутоматски наставци</string>
-
-    <!-- Option to enable text prediction in landscape -->
-    <string name="prediction_landscape">Увећан поље за унос текста</string>
-    <!-- Description for text prediction -->
-    <string name="prediction_landscape_summary">Сакриј предлоге речи при водоравном положају</string>
-
-    <!-- Option to enable auto capitalization of sentences -->
-    <string name="auto_cap">Аутоматска величина слова</string>
-    <!-- Description for auto cap -->
-    <string name="auto_cap_summary">Велико слово на почетку реченице</string>
-    <!-- Option to enable auto punctuate -->
-    <string name="auto_punctuate">Аутоматска интерпункција</string>
-    <!-- Description for auto punctuate -->
-    <string name="auto_punctuate_summary">Аутоматско постављање интерпункцијских знака при уносу.</string>
-
-    <!-- Option to enable quick fixes -->
-    <string name="quick_fixes">Брзе исправке</string>
-    <!-- Description for quick fixes -->
-    <string name="quick_fixes_summary">Аутоматска исправка честих грешака</string>
-
-    <!-- Option to enable showing suggestions -->
-    <string name="show_suggestions">Приказ предлога</string>
-    <!-- Description for show suggestions -->
-    <string name="show_suggestions_summary">Приказује предлоге речи током уноса</string>
-
-    <!-- Option to enable auto completion -->
-    <string name="auto_complete">Аутоматска допуна</string>
-    <!-- Description for auto completion -->
-    <string name="auto_complete_summary">Размакница и интерпункција аутоматски убацују означену реч.</string>
-
-    <!-- Array of prediction modes -->
-    <string-array name="prediction_modes">
-        <item>Искључено</item>
-        <item>Основно</item>
-        <item>Напредно</item>
-    </string-array>
-
-    <string-array name="prediction_modes_values" translatable="false">
-        <item>@string/prediction_none</item>
-        <item>@string/prediction_basic</item>
-        <item>@string/prediction_full</item>
-    </string-array>
-
-    <!-- Indicates that a word has been added to the dictionary -->
-    <string name="added_word"><xliff:g id="word">%s</xliff:g> : Saved</string>
-    <!-- Tip to long press on keys -->
-    <string name="tip_long_press">Дуги притисак на тастере открива проширене знаке (ø, ö, итд.)</string>
-    <!-- Tip to dismiss keyboard -->
-    <string name="tip_dismiss">Притисните тастер за назад \u21B6 како бисте затворили тастатуру</string>
-    <!-- Tip to press ?123 to access numbers and symbols -->
-    <string name="tip_access_symbols">Приступ бројевима и симболима</string>
-    <!-- Tip to long press on typed word to add to dictionary -->
-    <string name="tip_add_to_dictionary">Притисните и држите притиснуту реч са крајње леве стране
-        како бисте је додали у речник</string>
-
-    <!-- Instruction to touch the bubble to continue -->
-    <string name="touch_to_continue">Притисните овај подсетник да наставите »</string>
-
-    <!-- Instruction to touch the bubble to start typing -->
-    <string name="touch_to_finish">Притисните овде да бисте затворили подсетник и наставили унос!</string>
-
-    <!-- Tutorial tip 1 - The keyboard opens any time you touch a text field -->
-    <string name="tip_to_open_keyboard"><b>Тастатура се отвара кад год је потребно да унесете текст</b></string>
-
-    <!-- Tutorial tip 2 - Touch and hold a key to view accents (examples) -->
-    <string name="tip_to_view_accents"><b>Притисните и држите тастер како бисте видели проширене
-        знаке\n(„, ‟, итд.)</b>
-    </string>
-
-    <!-- Tutorial tip 3 - How to switch to number/symbol keyboard -->
-    <string name="tip_to_open_symbols"><b>Пребаците се на бројеве и симболе притиском на овај тастер
-        </b></string>
-
-    <!-- Tutorial tip 4 - How to switch back to alphabet keyboard -->
-    <string name="tip_to_close_symbols"><b>Вратите се назад на слова притиском на овај тастер</b></string>
-
-    <!-- Tutorial tip 5 - How to launch keyboard settings -->
-    <string name="tip_to_launch_settings"><b>Притисните и држите притиснут овај тастер да бисте променили
-        подешавања тастатуре, попут аутоматског настављања</b></string>
-
-    <!-- Tutorial tip 6 - Done with the tutorial -->
-    <string name="tip_to_start_typing"><b>Пробајте сами!</b></string>
-
-
-    <!-- Label for soft enter key when it performs GO action.  Must be short to fit on key! -->
-    <string name="label_go_key">Иди</string>
-    <!-- Label for soft enter key when it performs NEXT action.  Must be short to fit on key! -->
-    <string name="label_next_key">Даље</string>
-    <!-- Label for soft enter key when it performs DONE action.  Must be short to fit on key! -->
-    <string name="label_done_key">Крај</string>
-    <!-- Label for soft enter key when it performs SEND action.  Must be short to fit on key! -->
-    <string name="label_send_key">Шаљи</string>
-    <!-- Label for "switch to symbols" key.  Must be short to fit on key! -->
-    <string name="label_symbol_key">\?123</string>
-    <!-- Label for "switch to numeric" key.  Must be short to fit on key! -->
-    <string name="label_phone_key">123</string>
-    <!-- Label for "switch to alphabetic" key.  Must be short to fit on key! -->
-    <string name="label_alpha_key">АБВ</string>
-    <!-- Label for ALT modifier key.  Must be short to fit on key! -->
-    <string name="label_alt_key">ALT</string>
-
-    <!-- Voice related labels -->
-
-    <!-- Title of the warning dialog that shows when a user initiates voice input for
-         the first time. -->
-    <string name="voice_warning_title">Говорни унос</string>
-
-    <!-- Message that gets put at the top of the warning dialog if the user is attempting to use
-         voice input in a currently unsupported locale. Voice input will work for such a user,
-         but it will only recognize them in English. -->
-    <string name="voice_warning_locale_not_supported">Говорни унос није тренутно подржан на Вашем језику,
-       али ради на енглеском.</string>
-
-    <!-- Message of the warning dialog that shows when a user initiates voice input for
-         the first time, or turns it on in settings. -->
-    <string name="voice_warning_may_not_understand">Говорни унос је експериментална могућност која користи
-        Google-ово мрежно препознавање говора.</string>
-
-    <!-- An additional part of the warning dialog for voice input that only shows when the user
-         actually initiates voice input, rather than just turning it on in settings. -->
-    <string name="voice_warning_how_to_turn_off">Како бисте искључили говорни унос, изаберите подешавања
-        тастатуре.</string>
-
-    <!-- Message to show when user clicks the swiping hint (which says
-        "Swipe across keyboard to speak"). Also shown when enabling settings. -->
-    <string name="voice_hint_dialog_message">Како бисте укључили говорни унос, притисните дугме са сличицом
-        микрофона или превуците прстом преко целе дужине тастатуре.</string>
-
-    <!-- Short message to tell the user the system is ready for them to speak. -->
-    <string name="voice_listening">Говорите сада</string>
-
-    <!-- Short message shown after the user finishes speaking. -->
-    <string name="voice_working">Обрада је у току</string>
-
-    <!-- Short message shown before the user should speak. -->
-    <string name="voice_initializing"></string>
-
-    <!-- Short message shown when a generic error occurs. -->
-    <string name="voice_error">Грешка.  Молимо пробајте поново.</string>
-
-    <!-- Short message shown for a network error. -->
-    <string name="voice_network_error">Повезивање није успело</string>
-
-    <!-- Short message shown for a network error where the utterance was really long,
-         in which case we should suggest that the user speak less. -->
-    <string name="voice_too_much_speech">Грешка, говор је предугачак.</string>
-
-    <!-- Short message shown for an audio error. -->
-    <string name="voice_audio_error">Проблем са звуком</string>
-
-    <!-- Short message shown for an error with the voice server. -->
-    <string name="voice_server_error">Грешка на серверу</string>
-
-    <!-- Short message shown when no speech is heard. -->
-    <string name="voice_speech_timeout">Говор није снимљен</string>
-
-    <!-- Short message shown when the server couldn't parse any speech. -->
-    <string name="voice_no_match">Нема погодака</string>
-
-    <!-- Short message shown when the user initiates voice and voice
-        search is not installed. -->
-    <string name="voice_not_installed">Говорна претрага није инсталирана</string>
-
-    <!-- Short hint shown in candidate view to explain voice input. -->
-    <string name="voice_swipe_hint"><b>Савет:</b> Превуците прстом преко тастатуре а онда говорите.</string>
-
-    <!-- Short hint shown in candidate view to explain that user can speak punctuation. -->
-    <string name="voice_punctuation_hint"><b>Савет:</b> Следећи пут, изговорите назив интерпункције,
-        попут „тачка“, „запета“ или „знак питања“.</string>
-
-    <!-- Label on button to stop recognition. Must be short to fit on button. -->
-    <string name="cancel">Откажи</string>
-
-    <!-- Label on button when an error occurs -->
-    <string name="ok">У реду</string>
-
-    <!-- Preferences item for enabling speech input -->
-    <string name="voice_input">Говорни унос</string>
-
-    <!-- Array of Voice Input modes -->
-    <string-array name="voice_input_modes">
-        <item>На главној тастатури</item>
-        <item>На симболичкој тастатури</item>
-        <item>Искључен</item>
-    </string-array>
-
-    <string-array name="voice_input_modes_values" translatable="false">
-        <item>@string/voice_mode_main</item>
-        <item>@string/voice_mode_symbols</item>
-        <item>@string/voice_mode_off</item>
-    </string-array>
-
-    <!-- Array of Voice Input modes summary -->
-    <string-array name="voice_input_modes_summary">
-        <item>Микрофон на главној тастатури</item>
-        <item>Микрофон на симболичкој тастатури</item>
-        <item>Говорни унос је искључен</item>
-    </string-array>
-
-    <!-- Press the "enter" key after the user speaks. Option on settings.-->
-    <string name="auto_submit">Аутоматско слање по говорном уносу</string>
-
-    <!-- Press the "enter" key after the user speaks. Summary of option in settings.-->
-    <string name="auto_submit_summary">Дугме за претрагу се аутоматски притиска при претрази или преласку
-        на следеће поље за унос.</string>
-
-    <!-- IME Tutorial screen (ROMAN) --><skip />
-    <!-- appears above image showing the user to click on a TextView to show the IME -->
-    <string name="open_the_keyboard"><font size="17"><b>Отварање тастатуре\n</b></font><font size="3">\n</font>Touch any text field.</string>
-
-    <!-- appears above the image showing the back button used to close the keyboard -->
-    <string name="close_the_keyboard"><font size="17"><b>Затварање тастатуре\n</b></font><font size="3">\n</font>Press the Back key.</string>
-
-    <!-- appears above image showing how to use touch and hold -->
-    <string name="touch_and_hold"><font size="17"><b>Притисните \u0026 и држите пристиснут тастер за опције\n</b></font><font size="3">\n</font>Приступ акцентима и интерпункцији.</string>
-
-    <!-- appears above image showing how to access keyboard settings -->
-    <string name="keyboard_settings"><font size="17"><b>Подешавање тастатуре\n</b></font><font size="3">\n</font>Притисните \u0026 и држите тастер <b>\?123\</b>.</string>
-
-    <!-- popular web domains for the locale - most popular, displayed on the keyboard -->
-    <string name="popular_domain_0">".rs"</string>
-    <!-- popular web domains for the locale - item 1, displayed in the popup -->
-    <string name="popular_domain_1">".com"</string>
-    <!-- popular web domains for the locale - item 2, displayed in the popup -->
-    <string name="popular_domain_2">".net"</string>
-    <!-- popular web domains for the locale - item 3, displayed in the popup -->
-    <string name="popular_domain_3">".org"</string>
-    <!-- popular web domains for the locale - item 4, displayed in the popup -->
-    <string name="popular_domain_4">".edu"</string>
-
-    <!-- Title for input language selection screen -->
-    <string name="language_selection_title">Језици за унос</string>
-    <!-- Title summary for input language selection screen -->
-    <string name="language_selection_summary">Превуците прстом по размакници за промену језика</string>
-
-    <!-- Add to dictionary hint -->
-    <string name="hint_add_to_dictionary">\u2190 Притисните опет да бисте сачували</string>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Android тастатура"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Подешавања Android тастатуре"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Вибрирај на притисак тастера"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Звук на притисак тастера"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Исправи грешке у куцању"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Омогућавање исправљања грешака током уноса"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Грешке приликом уноса у положеном приказу"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Омогућавање исправљања грешака током уноса"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Предлагање речи"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Аутоматско исправљање претходне речи"</string>
+    <string name="prediction" msgid="466220283138359837">"Предлагање речи"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Подешавања за предлагање речи"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Омогућавање аутоматског довршавања током уноса текста"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Аутоматско довршавање"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Повећај величину поља за текст"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Скривање предложених речи у положеном приказу"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Аутоматски унос великих слова"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Унос великог слова на почетку реченице"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Аутоматска интерпункција"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Брзе исправке"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Исправља честе грешке у куцању"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Аутоматско довршавање"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Означена реч се аутоматски умеће када притиснете размак или знак интерпункције"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Ништа"</item>
+    <item msgid="1669461741568287396">"Основни"</item>
+    <item msgid="4894328801530136615">"Напредно"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Сачувано"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Држите тастер да бисте видели акценте (ø, ö итд.)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Притисните тастер „Назад“ ↶ у било ком тренутку да бисте затворили тастатуру"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Приступите бројевима и симболима"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Притисните и држите прву реч са леве стране да бисте је додали у речник"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Додирните овај савет да бисте наставили »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Додирните овде да бисте затворили овај савет и почели да уносите текст!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Тастатура се отвара сваки пут када додирнете поље за текст"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Додирните и држите тастер да бисте видели акценте"\n"(ø, ö, ô, ó, и тако даље)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Пређите на бројеве и симболе тако што ћете додирнути овај тастер"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Вратите се на слова тако што ћете поново додирнути овај тастер"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Додирните и држите овај тастер да бисте променили подешавања тастатуре, као што је аутоматско довршавање"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Пробајте!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Иди"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Следеће"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Пошаљи"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Гласовни унос"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Гласовни унос тренутно није подржан за ваш језик, али функционише на енглеском."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Гласовни унос је експериментална функција која користи Google-ово мрежно препознавање гласа."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Да бисте искључили гласовни унос, идите на подешавања тастатуре."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Да бисте користили гласовни унос, притисните дугме за микрофон или превуците прст преко тастатуре на екрану."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Говорите сада"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Обрада"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Грешка. Покушајте поново."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Повезивање није могуће"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Грешка, говорите предуго."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Проблем са звуком"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Грешка сервера"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Не чује се говор"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Нема подударања"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Гласовна претрага није инсталирана"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Савет:"</b>" Превуците прстом преко тастатуре за гласовни унос"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Савет:"</b>" Следећи пут покушајте да изговорите знакове интерпункције као што су „тачка“, „зарез“ или „знак питања“."</string>
+    <string name="cancel" msgid="6830980399865683324">"Откажи"</string>
+    <string name="ok" msgid="7898366843681727667">"Потврди"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Гласовни унос"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"На главној тастатури"</item>
+    <item msgid="8529385602829095903">"На тастатури са симболима"</item>
+    <item msgid="7283103513488381103">"Искључено"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Микрофон на главној тастатури"</item>
+    <item msgid="6907837061058876770">"Микрофон на тастатури са симболима"</item>
+    <item msgid="3664304608587798036">"Гласовни унос је онемогућен"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Аутоматски пошаљи после гласа"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Аутоматски притисак на enter приликом претраге или преласка на следеће поље."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Активирање тастатуре"\n</b></font><font size="3">\n</font>"Додирните било које поље за текст."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Затварање тастатуре"\n</b></font><font size="3">\n</font>"Притисните тастер „Назад“."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Додирните и држите тастер да би се приказале опције"\n</b></font><font size="3">\n</font>"Приступ знаковима интерпункције и акцентима."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Подешавања тастатуре"\n</b></font><font size="3">\n</font>"Додирните и држите тастер "<b>"?123"</b>"."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Језици за унос"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Превуците прст преко тастера за размак да бисте променили језик"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Додирните поново да бисте сачували"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Речник је доступан"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-sv/config.xml b/java/res/values-sv/config.xml
new file mode 100644
index 0000000..419f196
--- /dev/null
+++ b/java/res/values-sv/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0,22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-sv/donottranslate-altchars.xml b/java/res/values-sv/donottranslate-altchars.xml
index 4d26e6c..902a4c9 100644
--- a/java/res/values-sv/donottranslate-altchars.xml
+++ b/java/res/values-sv/donottranslate-altchars.xml
@@ -33,6 +33,8 @@
     <string name="alternates_for_z">źžż</string>
     <string name="alternates_for_l">ł</string>
     <string name="alternates_for_v">w</string>
-    <string name="alternates_for_a_umlaut">æ</string>
-    <string name="alternates_for_o_umlaut">øœ</string>
+    <string name="keylabel_for_scandinavia_row2_10">ö</string>
+    <string name="keylabel_for_scandinavia_row2_11">ä</string>
+    <string name="alternates_for_scandinavia_row2_10">øœ</string>
+    <string name="alternates_for_scandinavia_row2_11">æ</string>
 </resources>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
index 755ee05..46f9f9f 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Snabba lösningar"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Åtgärdar automatiskt vanliga misstag"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Visa förslag"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Visar ordförslag när du skriver"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Komplettera automatiskt"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"Blanksteg och punkt infogar automatiskt markerat ord"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Visa inställningsknapp"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Automatiskt"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Visa alltid"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Komplettera automatiskt"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Blanksteg och punkt infogar automatiskt markerat ord"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Av"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Måttlig"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Aggressiv"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigramförslag"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Förbättra förslaget med föregående ord"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"Nästa"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Färdig"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Skicka"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Mer"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tabb"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Pausa"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Vänta"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Röstindata"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Röstindata stöds inte på ditt språk än, men tjänsten fungerar på engelska."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Röstinmatning är en funktion på experimentstadiet som använder Googles nätverks taligenkänning."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Om du vill stänga av röstindata öppnar du inställningarna för tangentbordet."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Om du vill använda röstinmatning trycker du på mikrofonknappen eller drar fingret över tangentbordet på skärmen."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Röstinmatning är en funktion på experimentstadiet som använder Googles nätverks taligenkänning."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Om du vill stänga av röstindata öppnar du inställningarna för tangentbordet."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Om du vill använda röstinmatning trycker du på mikrofonknappen eller drar fingret över tangentbordet på skärmen."</string>
     <string name="voice_listening" msgid="467518160751321844">"Tala nu"</string>
     <string name="voice_working" msgid="6666937792815731889">"Fungerar"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Aktivera synpunkter från användare"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Du kan hjälpa till att förbättra inmatningsmetoden genom att automatiskt skicka användningsstatistik och felrapporter till Google."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Tryck om du vill korrigera om ord"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Du kan korrigera om ord genom att trycka på ord som du har skrivit"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Du kan korrigera om ord genom att trycka på ord som du har skrivit"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Tangentbordstema"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"tangentbord"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"röst"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-th/config.xml b/java/res/values-th/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-th/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
new file mode 100644
index 0000000..813ad6c
--- /dev/null
+++ b/java/res/values-th/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"แป้นพิมพ์ Android"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"การตั้งค่าแป้นพิมพ์ Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"สั่นเมื่อกดปุ่ม"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"ส่งเสียงเมื่อกดปุ่ม"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"แก้ไขข้อผิดพลาดในการพิมพ์"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"เปิดการใช้งานการแก้ไขข้อผิดพลาดในการป้อนข้อมูล"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"ข้อผิดพลาดในการป้อนข้อมูลแนวนอน"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"เปิดการใช้งานการแก้ไขข้อผิดพลาดในการป้อนข้อมูล"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"การแนะนำคำ"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"แก้ไขคำก่อนหน้าอัตโนมัติ"</string>
+    <string name="prediction" msgid="466220283138359837">"การแนะนำคำ"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"การตั้งค่าการแนะนำคำ"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"เปิดใช้งานการเติมคำอัตโนมัติขณะพิมพ์"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"เติมคำอัตโนมัติ"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"เพิ่มขนาดฟิลด์ข้อความ"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"ซ่อนการแนะนำคำในมุมมองแนวนอน"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"ปรับเป็นตัวพิมพ์ใหญ่อัตโนมัติ"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"ใช้ตัวพิมพ์ใหญ่เมื่อขึ้นต้นประโยค"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"ใส่เครื่องหมายวรรคตอนอัตโนมัติ"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"แก้ไขด่วน"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"แก้ไขข้อผิดพลาดในการพิมพ์ที่พบบ่อย"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"เติมคำอัตโนมัติ"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"ใช้แป้นเคาะวรรคและเครื่องหมายวรรคตอนเพื่อแทรกคำที่ไฮไลต์โดยอัตโนมัติ"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"ไม่มี"</item>
+    <item msgid="1669461741568287396">"พื้นฐาน"</item>
+    <item msgid="4894328801530136615">"ขั้นสูง"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : บันทึกแล้ว"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"กดปุ่มค้างไว้เพื่อดูการออกเสียง (ø, ö, ฯลฯ)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"กดปุ่ม ย้อนกลับ เพื่อปิดแป้นพิมพ์เมื่อใดก็ได้"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"เข้าถึงหมายเลขและสัญลักษณ์"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"กดคำซ้ายสุดค้างไว้เพื่อเพิ่มลงในพจนานุกรม"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"แตะคำแนะนำนี้เพื่อทำงานต่อ »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"แตะที่นี่เพื่อปิดคำแนะนำนี้และเริ่มพิมพ์!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"แป้นพิมพ์จะเปิดขึ้นเมื่อคุณแตะฟิลด์ข้อความ"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"แตะปุ่มค้างไว้เพื่อดูการออกเสียง"\n"(ø, ö, ô, ó และอื่นๆ)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"เปลี่ยนเป็นตัวเลขและสัญลักษณ์เมื่อแตะปุ่มนี้"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"กลับไปที่ตัวอักษรโดยการแตะปุ่มนี้อีกครั้ง"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"แตะปุ่มนี้ค้างไว้เพื่อเปลี่ยนการตั้งค่าแป้นพิมพ์ เช่น การเติมคำอัตโนมัติ"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"ลองดูสิ!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"ไป"</string>
+    <string name="label_next_key" msgid="362972844525672568">"ถัดไป"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"เสร็จสิ้น"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"ส่ง"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"การป้อนข้อมูลด้วยเสียง"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"ขณะนี้การป้อนข้อมูลด้วยเสียงยังไม่ได้รับการสนับสนุนในภาษาของคุณ แต่ใช้ได้ในภาษาอังกฤษ"</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"การป้อนข้อมูลด้วยเสียงเป็นคุณลักษณะทดลองที่ใช้การจดจำเสียงที่มีการสร้างเครือข่ายไว้ของ Google"</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"หากต้องการปิดการป้อนข้อมูลด้วยเสียง ไปที่การตั้งค่าแป้นพิมพ์"</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"หากต้องการใช้การป้อนข้อมูลด้วยเสียง กดปุ่มไมโครโฟนหรือเลื่อนนิ้วผ่านแป้นพิมพ์บนหน้าจอ"</string>
+    <string name="voice_listening" msgid="467518160751321844">"พูดได้เลย"</string>
+    <string name="voice_working" msgid="6666937792815731889">"กำลังทำงาน"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"ข้อผิดพลาด โปรดลองอีกครั้ง"</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"ไม่สามารถเชื่อมต่อได้"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"ข้อผิดพลาด คำพูดยาวเกินไป"</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"ปัญหาด้านเสียง"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"ข้อผิดพลาดของเซิร์ฟเวอร์"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"ไม่ได้ยินเสียง"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"ไม่พบรายการที่ตรงกัน"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"ไม่ได้ติดตั้ง Voice Search"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"คำแนะนำ:"</b>" กวาดผ่านแป้นพิมพ์เพื่อพูด"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"คำแนะนำ:"</b>" ครั้งต่อไป ให้ลองเอ่ยถึงเครื่องหมายวรรคตอน เช่น \"มหัพภาค\" \"จุลภาค\" หรือ \"เครื่องหมายคำถาม\""</string>
+    <string name="cancel" msgid="6830980399865683324">"ยกเลิก"</string>
+    <string name="ok" msgid="7898366843681727667">"ตกลง"</string>
+    <string name="voice_input" msgid="2466640768843347841">"การป้อนข้อมูลด้วยเสียง"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"บนแป้นพิมพ์หลัก"</item>
+    <item msgid="8529385602829095903">"บนแป้นพิมพ์สัญลักษณ์"</item>
+    <item msgid="7283103513488381103">"ปิด"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"ไมโครโฟนบนแป้นพิมพ์หลัก"</item>
+    <item msgid="6907837061058876770">"ไมโครโฟนบนแป้นพิมพ์สัญลักษณ์"</item>
+    <item msgid="3664304608587798036">"การป้อนข้อมูลด้วยเสียงถูกปิดการใช้งาน"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"ส่งอัตโนมัติหลังบันทึกเสียง"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"กด Enter อัตโนมัติเมื่อค้นหาหรือไปที่ฟิลด์ถัดไป"</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"เปิดแป้นพิมพ์"\n</b></font><font size="3">\n</font>"แตะฟิลด์ข้อความใดก็ได้"</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"ปิดแป้นพิมพ์"\n</b></font><font size="3">\n</font>"กดปุ่ม ย้อนกลับ"</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"แตะปุ่มค้างไว้เพื่อดูตัวเลือก "\n</b></font><font size="3">\n</font>"เข้าถึงเครื่องหมายวรรคตอนและการออกเสียง"</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"การตั้งค่าแป้นพิมพ์"\n</b></font><font size="3">\n</font>"แตะปุ่ม "<b>"?123"</b>"ค้างไว้"</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"ภาษาในการป้อนข้อมูล"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"เลื่อนนิ้วไปบนแป้นเคาะวรรคเพื่อเปลี่ยนภาษา"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← แตะอีกครั้งเพื่อบันทึก"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"มีพจนานุกรมให้ใช้งาน"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-tl/config.xml b/java/res/values-tl/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-tl/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
new file mode 100644
index 0000000..e069082
--- /dev/null
+++ b/java/res/values-tl/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Android keyboard"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Mga setting ng Android keyboard"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Mag-vibrate sa keypress"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Tunog sa keypress"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Itama ang mga error sa pag-type"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Paganahin ang pagtatama ng error sa pag-input"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Mga error sa pag-input ng landscape"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Paganahin ang pagtatama ng error sa pag-input"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Mga suhestiyon ng salita"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Awtomatikong itama ang nakaraang salita"</string>
+    <string name="prediction" msgid="466220283138359837">"Mga suhestiyon ng salita"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Mga setting ng suhestiyon ng salita"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Paganahin ang awtomatikong pagkumpleto habang nagta-type"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Awtomatikong pagkumpleto"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Taasan ang laki ng field ng teksto"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Itago ang mga suhestiyon ng salita sa lanscape na view"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Auto-capitalization"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"I-capitalize ang simula ng isang pangungusap"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"I-auto-punctuate"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Mga mabilisang pagsasaayos"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Itinatama ang mga karaniwang na-type na mali"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"I-auto-complete"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Awtomatikong ipinapasok ng spacebar at bantas ang naka-highlight na salita"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Wala"</item>
+    <item msgid="1669461741568287396">"Batayan"</item>
+    <item msgid="4894328801530136615">"Advanced"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Na-save"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Pinduting nang matagal ang isang key pababa upang makita ang mga accent (ø, ö, atbp.)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Pindutin ang key na bumalik ↶ upang isara ang keyboard anumang oras"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"I-access ang mga numero at simbolo"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Pindutin nang matagal ang salita sa kaliwang bahagi upang idagdag ito sa diksyunaryo"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Galawin ang pahiwatig na ito upang magpatuloy »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Galawin dito upang isara ang pahiwatig na ito at simulan ang pag-type!"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Nagbubukas ang keyboard anumang oras na galawin mo ang field ng teksto"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Galawin &amp; pinduting nang matagal ang isang key upang tingnan ang mga accent"\n"(ø, ö, ô, ó, at iba pa)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Lumipat sa mga numero at simbolo sa pamamagitan ng paggalaw sa key na "</b>" na ito"</string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Pumunta muli sa mga titik sa pamamagitan ng muling paggalaw sa key na ito"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Galawin &amp; pinduting nang matagal ang key na ito upang baguhin ang mga setting ng keyboard, tulad ng awtomatikong pagkumpleto"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Subukan ito!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Pumunta"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Susunod"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Tapos na"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Ipadala"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Pag-input ng boses"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Hindi kasalukuyang suportado ang pag-input ng boses para sa iyong wika, ngunit gumagana sa Ingles."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Ang pag-input ng boses ay isang tampok na pang-eksperimento na gumagamit ng naka-network na pagkilala sa pananalita ng Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Upang i-off ang pag-input ng boses, pumunta sa mga setting ng keyboard."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Upang gumamit ng pag-input ng boses, pindutin ang pindutang microphone o i-slide ang iyong daliri sa screen keyboard."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Magsalita ngayon"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Nagtatrabaho"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Error. Pakisubukang muli."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Hindi makakonekta"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Error, masyadong maraming pananalita."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Problema sa audio"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Error sa server"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Walang narinig na pananalita"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Walang nakitang mga tugma"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Hindi naka-install ang paghahanap ng boses"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Pahiwatig:"</b>" Mag-swipe sa keyboard upang magsalita"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Pahiwatig:"</b>" Sa susunod, subukang magsalita ng bantas tulad ng \"tuldok\", \"kuwit\", o \"tandang pananong\"."</string>
+    <string name="cancel" msgid="6830980399865683324">"Kanselahin"</string>
+    <string name="ok" msgid="7898366843681727667">"OK"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Pag-input ng boses"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"I-on ang pangunahing keyboard"</item>
+    <item msgid="8529385602829095903">"Sa mga simbolo ng keyboard"</item>
+    <item msgid="7283103513488381103">"Naka-off"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Mic sa pangunahing keyboard"</item>
+    <item msgid="6907837061058876770">"Mic sa keyboard ng mga simbolo"</item>
+    <item msgid="3664304608587798036">"Hindi pinagana ang pag-input ng boses"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Awtomatikong isumite pagkatapos ng boses"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Awtomatikong pindutin ang enter kapag naghahanap o pupunta sa susunod na field."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Buksan ang keyboard"\n</b></font><font size="3">\n</font>"Galawin ang kahit anong field ng teksto."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Isara ang keyboard"\n</b></font><font size="3">\n</font>"Pindutin ang key na Bumalik."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Galawin &amp; pinduting nang matagal ang isang key para sa mga pagpipilian"\n</b></font><font size="3">\n</font>"I-access ang bantas at mga accent."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Mga setting ng keyboard"\n</b></font><font size="3">\n</font>"Galawin &amp; pindutin nang matagal ang "<b>"?123"</b>" na key."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Mag-input ng mga wika"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"I-slide ang daliri sa spacebar upang palitan ang wika"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Tapikin muli upang i-save"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Available ang diksyunaryo"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-tr/config.xml b/java/res/values-tr/config.xml
new file mode 100644
index 0000000..419f196
--- /dev/null
+++ b/java/res/values-tr/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0,22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index 599ddb2..3b7c1b8 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"Hızlı onarımlar"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"Yaygın olarak yapılan yazım hatalarını düzeltir"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"Önerileri göster"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"Yazarken önerilen kelimeleri görüntüle"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"Otomatik tamamla"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"Boşluk tuşu ve noktalama vurgulanan kelimeyi otomatik ekler"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"Ayarları göster tuşu"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"Otomatik"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"Her zaman göster"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Otomatik tamamla"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Boşluk tuşu ve noktalama vurgulanan kelimeyi otomatik ekler"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"Kapalı"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"Tutarlı"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"Agresif"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"Bigram Önerileri"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"Öneriyi geliştirmek için önceki kelimeyi kullanın"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"İleri"</string>
     <string name="label_done_key" msgid="2441578748772529288">"Bitti"</string>
     <string name="label_send_key" msgid="2815056534433717444">"Gönder"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"Diğer"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Sekm"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"Durkl"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"Bekle"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"Ses girişi"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Ses girişi, şu anda sizin diliniz için desteklenmiyor ama İngilizce dilinde kullanılabilir."</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"Ses girişi, Google\'ın ağ bağlantılı ses tanıma işlevini kullanan deneysel bir özelliktir."</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"Ses girişini kapatmak için klavye ayarlarına gidin."</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"Ses girişini kullanmak için mikrofon düğmesine basın veya parmağınızı dokunmatik klavye üzerinde kaydırın."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Ses girişi, Google\'ın ağ bağlantılı ses tanıma işlevini kullanan deneysel bir özelliktir."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Ses girişini kapatmak için klavye ayarlarına gidin."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Ses girişini kullanmak için mikrofon düğmesine basın veya parmağınızı dokunmatik klavye üzerinde kaydırın."</string>
     <string name="voice_listening" msgid="467518160751321844">"Şimdi konuşun"</string>
     <string name="voice_working" msgid="6666937792815731889">"Çalışıyor"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"Kullanıcı geri bildirimini etkinleştir"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"Kullanım istatistiklerini ve kilitlenme raporlarını Google\'a otomatik olarak göndererek bu giriş yöntemi düzenleyicisinin iyileştirilmesine yardımcı olun."</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"Kelimeleri düzeltmek için dokunun"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"Yazdığınız kelimelere dokunarak kelimelerde düzeltme yapabilirsiniz"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"Yazdığınız kelimelere dokunarak kelimelerde düzeltme yapabilirsiniz"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"Klavye Teması"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"klavye"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"ses"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-uk/config.xml b/java/res/values-uk/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-uk/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
new file mode 100644
index 0000000..b7b8fb8
--- /dev/null
+++ b/java/res/values-uk/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Клавіатура Android"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Налашт-ня клавіат. Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Вібр при натиску клав."</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Звук при натиску клав."</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Виправ. помилки вводу"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Увімкн. виправл. помилок вводу"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Помилки альбомного вводу"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Увімкн. виправл. помилок вводу"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Пропозиції слів"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Автоматично виправляти попереднє слово"</string>
+    <string name="prediction" msgid="466220283138359837">"Пропозиції слів"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Налашт-ня пропозицій слів"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Увімкн. автозаповнення при вводі"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Автозаповнення"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Збільш. розмір текст. поля"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Сховати пропозиції слів в альбом. режимі"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Авто викор. вел. літер"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Поч. писати речення з великої літери"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Авто пунктуація"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Шв. виправлення"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Виправляє поширені помилки"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Автозаповнення"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Пробіл і пунктуація автоматично вставляє виділене слово"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Немає"</item>
+    <item msgid="1669461741568287396">"Базовий"</item>
+    <item msgid="4894328801530136615">"Розшир."</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : збережено"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Утр. клав. натис., щоб див. нагол. (ø, ö, тощо)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Натисн. клавішу назад ↶, щоб будь-коли закрити клавіат."</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Доступ до цифр і символів"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Натисн. і утримуйте ліве крайнє слово, щоб додати його до словн."</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Натис. цю підказку для продовж.»"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Натисн. тут, щоб закрити цю підказку і почати ввод."</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Клавіатура відривається при торканні текстового поля"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Натис. і утрим. клавішу для перегл. наголосів"\n"(ø, ö, ô, ó тощо)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Перемк. до цифр і символів, натиснувши цю кнопку "</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Поверніться до літер, знову натиснувши цю клавішу"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Натис. і утрим. клавішу, щоб змін. налашт-ння клавіат., такі як автозапов."</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Спробуйте!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Іти"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Далі"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Готово"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Надісл."</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Голос. ввід"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Голос. ввід наразі не підтрим. для вашої мови, але можна користуватися англійською."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Голос. ввід є експеремент. ф-цією, яка викор. мережеве розпізнавання голосу Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Щоб вимкн. голос ввід, йдіть до налашт-нь клавіатури."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Щоб викор. голос. ввід, натисніть кнопку мікрофона або пересуньте палець на екранній клавіатурі."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Диктуйте"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Працює"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Помилка. Спробуйте ще раз."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Неможл. під\'єднатися"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Помилка. Забагато продикт."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Проблема з аудіо"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Помилка сервера"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Не чути диктув."</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Збігів не знайдено"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Голос. пошук не встановлено"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Підк:"</b>" горт. на клавіат., щоб продикт."</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Підказка:"</b>" наступного разу продикт. знаки пункт. такі як \"крапка\", \"кома\" чи \"знак пит\"."</string>
+    <string name="cancel" msgid="6830980399865683324">"Скасувати"</string>
+    <string name="ok" msgid="7898366843681727667">"OK"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Голос. ввід"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"На осн. клавіатурі"</item>
+    <item msgid="8529385602829095903">"Символьна клавіатура"</item>
+    <item msgid="7283103513488381103">"Вимк."</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Miкр. на осн. клавіатурі"</item>
+    <item msgid="6907837061058876770">"Miкр. на символ. клавіатурі"</item>
+    <item msgid="3664304608587798036">"Голос. ввід вимкнуто"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Авто подав. після гол. пош."</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Автомат. натиск. enter під час пошуку або переходу до наступного поля."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Відкр. клавіатуру"\n</b></font><font size="3">\n</font>"Натисн. якесь текст. поле."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Закрити клавіатуру"\n</b></font><font size="3">\n</font>"Натисн. клавішу Назад."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Натис.і утрим. клавішк для отрим. парам."\n</b></font><font size="3">\n</font>"Доступ до пункт. та наголос."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Налашт-ння клавіатури"\n</b></font><font size="3">\n</font>"Натисн. і утрим. клавішу "<b>"?123"</b></string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Мови вводу"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Переміст. палець на пробіл, щоб змін. мову"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Натисн. ще, щоб збер."</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Словник доступний"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-vi/config.xml b/java/res/values-vi/config.xml
new file mode 100644
index 0000000..00d5e4c
--- /dev/null
+++ b/java/res/values-vi/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for auto_complete_threshold_values:1 (1149464960325799386) -->
+    <!-- no translation found for auto_complete_threshold_values:2 (7684739510048377673) -->
+</resources>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
new file mode 100644
index 0000000..c549f21
--- /dev/null
+++ b/java/res/values-vi/strings.xml
@@ -0,0 +1,251 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2008, 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"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="english_ime_name" msgid="7252517407088836577">"Bàn phím Android"</string>
+    <string name="english_ime_settings" msgid="6661589557206947774">"Cài đặt bàn phím Android"</string>
+    <!-- no translation found for english_ime_input_options (3909945612939668554) -->
+    <skip />
+    <string name="vibrate_on_keypress" msgid="5258079494276955460">"Rung khi nhấn phím"</string>
+    <string name="sound_on_keypress" msgid="6093592297198243644">"Âm thanh khi nhấn phím"</string>
+    <!-- no translation found for popup_on_keypress (123894815723512944) -->
+    <skip />
+    <string name="hit_correction" msgid="4855351009261318389">"Sửa lỗi đánh máy"</string>
+    <string name="hit_correction_summary" msgid="8761701873008070796">"Bật sửa lỗi nhập"</string>
+    <string name="hit_correction_land" msgid="2567691684825205448">"Lỗi nhập theo khổ ngang"</string>
+    <string name="hit_correction_land_summary" msgid="4076803842198368328">"Bật sửa lỗi nhập"</string>
+    <string name="auto_correction" msgid="7911639788808958255">"Đề xuất từ"</string>
+    <string name="auto_correction_summary" msgid="6881047311475758267">"Tự động sửa từ trước đó"</string>
+    <string name="prediction" msgid="466220283138359837">"Đề xuất từ"</string>
+    <string name="prediction_category" msgid="7027100625580696660">"Cài đặt đề xuất từ"</string>
+    <string name="prediction_summary" msgid="459788228830873110">"Bật tự động hoàn tất khi nhập"</string>
+    <string name="auto_complete_dialog_title" msgid="2172048590607201920">"Tự động hoàn tất"</string>
+    <string name="prediction_landscape" msgid="4874601565593216183">"Tăng kích cỡ trường văn bản"</string>
+    <string name="prediction_landscape_summary" msgid="6736551095997839472">"Ẩn đề xuất từ trong chế độ xem ngang"</string>
+    <string name="auto_cap" msgid="1719746674854628252">"Tự động viết hoa"</string>
+    <string name="auto_cap_summary" msgid="3260681697600786825">"Viết hoa chữ cái đầu câu"</string>
+    <string name="auto_punctuate" msgid="7276672334264521751">"Tự động chấm câu"</string>
+    <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
+    <string name="quick_fixes" msgid="5353213327680897927">"Sửa nhanh"</string>
+    <string name="quick_fixes_summary" msgid="3405028402510332373">"Sửa lỗi nhập thông thường"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
+    <!-- no translation found for prefs_settings_key (4623341240804046498) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_auto_name (2993460277873684680) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_show_name (3047567041784760575) -->
+    <skip />
+    <!-- no translation found for settings_key_mode_always_hide_name (7833948046716923994) -->
+    <skip />
+    <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
+    <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
+    <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"Tự động hoàn tất"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"Dấu cách và dấu câu tự động chèn vào từ được đánh dấu"</string>
+    <!-- no translation found for auto_completion_threshold_mode_off (8100705925921970219) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_modest (1639075698991437157) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_mode_aggeressive (1153130653281397959) -->
+    <skip />
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
+    <!-- no translation found for bigram_suggestion (1323347224043514969) -->
+    <skip />
+    <!-- no translation found for bigram_suggestion_summary (4383845146070101531) -->
+    <skip />
+  <string-array name="prediction_modes">
+    <item msgid="4870266572388153286">"Không"</item>
+    <item msgid="1669461741568287396">"Cơ bản"</item>
+    <item msgid="4894328801530136615">"Nâng cao"</item>
+  </string-array>
+    <string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Đã lưu"</string>
+    <string name="tip_long_press" msgid="6101270866284343344">"Giữ phím xuống để xem dấu trọng âm (ø, ö, v.v...)"</string>
+    <string name="tip_dismiss" msgid="7585579046862204381">"Nhấn phím quay lại ↶ để đóng bàn phím bất kỳ lúc nào"</string>
+    <string name="tip_access_symbols" msgid="6344098517525531652">"Truy cập các số và ký hiệu"</string>
+    <string name="tip_add_to_dictionary" msgid="1487293888469227817">"Nhấn và giữ từ ngoài cùng bên trái để thêm từ đó vào từ điển"</string>
+    <string name="touch_to_continue" msgid="7869803257948414531">"Chạm vào gợi ý này để tiếp tục »"</string>
+    <string name="touch_to_finish" msgid="7990196086480585789">"Chạm vào đây để đóng gợi ý này và bắt đầu nhập"</string>
+    <string name="tip_to_open_keyboard" msgid="6821200275486950452"><b>"Bàn phím mở ra bất cứ khi nào bạn chạm vào trường văn bản"</b></string>
+    <string name="tip_to_view_accents" msgid="5433158573693308501"><b>"Chạm &amp; giữ phím để xem dấu trọng âm"\n"(ø, ö, ô, ó, v.v...)"</b></string>
+    <string name="tip_to_open_symbols" msgid="7345139325622444880"><b>"Chuyển sang số và ký hiệu bằng cách chạm vào phím này"</b></string>
+    <string name="tip_to_close_symbols" msgid="5227724217206927185"><b>"Quay lại các chữ cái bằng cách chạm vào phím này lần nữa"</b></string>
+    <string name="tip_to_launch_settings" msgid="8402961128983196128"><b>"Chạm &amp; giữ phím này để thay đổi cài đặt bàn phím, như tự động hoàn tất"</b></string>
+    <string name="tip_to_start_typing" msgid="7213843601369174313"><b>"Hãy dùng thử!"</b></string>
+    <string name="label_go_key" msgid="1635148082137219148">"Đến"</string>
+    <string name="label_next_key" msgid="362972844525672568">"Tiếp theo"</string>
+    <string name="label_done_key" msgid="2441578748772529288">"Xong"</string>
+    <string name="label_send_key" msgid="2815056534433717444">"Gửi"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
+    <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
+    <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <!-- no translation found for label_more_key (3760239494604948502) -->
+    <skip />
+    <!-- no translation found for label_tab_key (6532779603382157482) -->
+    <skip />
+    <!-- no translation found for label_pause_key (181098308428035340) -->
+    <skip />
+    <!-- no translation found for label_wait_key (6402152600878093134) -->
+    <skip />
+    <string name="voice_warning_title" msgid="4419354150908395008">"Nhập liệu bằng giọng nói"</string>
+    <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"Nhập liệu bằng giọng nói hiện không được hỗ trợ cho ngôn ngữ của bạn nhưng hoạt động với ngôn ngữ tiếng Anh."</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"Nhập liệu bằng giọng nói là tính năng thử nghiệm sử dụng nhận dạng tiếng nói được kết nối mạng của Google."</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"Để tắt nhập liệu bằng giọng nói, đi tới cài đặt bàn phím."</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"Để sử dụng nhập liệu bằng giọng nói, hãy nhấn nút micrô hoặc trượt ngón tay trên bàn phím ảo."</string>
+    <string name="voice_listening" msgid="467518160751321844">"Xin mời nói"</string>
+    <string name="voice_working" msgid="6666937792815731889">"Đang hoạt động"</string>
+    <string name="voice_initializing" msgid="661962047129906646"></string>
+    <string name="voice_error" msgid="5140896300312186162">"Lỗi. Vui lòng thử lại."</string>
+    <string name="voice_network_error" msgid="6649556447401862563">"Không thể kết nối"</string>
+    <string name="voice_too_much_speech" msgid="5746973620134227376">"Lỗi, quá nhiều câu thoại."</string>
+    <string name="voice_audio_error" msgid="5072707727016414454">"Sự cố âm thanh"</string>
+    <string name="voice_server_error" msgid="7807129913977261644">"Lỗi máy chủ"</string>
+    <string name="voice_speech_timeout" msgid="8461817525075498795">"Không nghe thấy tiếng nói nào"</string>
+    <string name="voice_no_match" msgid="4285117547030179174">"Không tìm thấy kết quả phù hợp"</string>
+    <string name="voice_not_installed" msgid="5552450909753842415">"Tìm kiếm bằng giọng nói chưa được cài đặt"</string>
+    <string name="voice_swipe_hint" msgid="6943546180310682021"><b>"Gợi ý:"</b>" Trượt qua bàn phím để nói"</string>
+    <string name="voice_punctuation_hint" msgid="1611389463237317754"><b>"Gợi ý:"</b>" Lần tới, thử nói dấu câu như \"dấu chấm\", \"dấu phẩy\" hoặc \"dấu hỏi\"."</string>
+    <string name="cancel" msgid="6830980399865683324">"Huỷ"</string>
+    <string name="ok" msgid="7898366843681727667">"OK"</string>
+    <string name="voice_input" msgid="2466640768843347841">"Nhập liệu bằng giọng nói"</string>
+  <string-array name="voice_input_modes">
+    <item msgid="1349082139076086774">"Trên bàn phím chính"</item>
+    <item msgid="8529385602829095903">"Trên bàn phím có biểu tượng"</item>
+    <item msgid="7283103513488381103">"Tắt"</item>
+  </string-array>
+  <string-array name="voice_input_modes_summary">
+    <item msgid="554248625705084903">"Micrô trên bàn phím chính"</item>
+    <item msgid="6907837061058876770">"Micrô trên bàn phím có biểu tượng"</item>
+    <item msgid="3664304608587798036">"Nhập liệu bằng giọng nói đã bị vô hiệu hoá"</item>
+  </string-array>
+    <string name="auto_submit" msgid="9151008027068358518">"Tự động gửi sau thoại"</string>
+    <string name="auto_submit_summary" msgid="4961875269610384226">"Tự đông nhấn enter khi tìm kiếm hoặc đi tới trường tiếp theo."</string>
+    <string name="open_the_keyboard" msgid="2215920976029260466"><font size="17"><b>"Mở bàn phím"\n</b></font><font size="3">\n</font>"Chạm vào bất kỳ trường văn bản nào."</string>
+    <string name="close_the_keyboard" msgid="6251022259044940103"><font size="17"><b>"Đóng bàn phím"\n</b></font><font size="3">\n</font>"Nhấn phím Quay lại."</string>
+    <string name="touch_and_hold" msgid="6154166367273010534"><font size="17"><b>"Chạm &amp; giữ phím cho các tuỳ chọn"\n</b></font><font size="3">\n</font>"Truy cập dấu câu và dấu trọng âm."</string>
+    <string name="keyboard_settings" msgid="4585753477617374032"><font size="17"><b>"Cài đặt bàn phím"\n</b></font><font size="3">\n</font>"Chạm &amp; giữ phím "<b>"?123"</b>"."</string>
+    <string name="popular_domain_0" msgid="3745279225122472969">".com"</string>
+    <string name="popular_domain_1" msgid="1370572248164278467">".net"</string>
+    <string name="popular_domain_2" msgid="3036812463748402878">".org"</string>
+    <string name="popular_domain_3" msgid="8718639560809452028">".gov"</string>
+    <string name="popular_domain_4" msgid="35359437471311470">".edu"</string>
+    <!-- no translation found for selectInputMethod (315076553378705821) -->
+    <skip />
+    <string name="language_selection_title" msgid="1651299598555326750">"Ngôn ngữ nhập"</string>
+    <string name="language_selection_summary" msgid="187110938289512256">"Trượt ngón tay trên phím cách để thay đổi ngôn ngữ"</string>
+    <!-- outdated translation 8058519710062071085 -->     <string name="hint_add_to_dictionary" msgid="9006292060636342317">"← Nhấn lại để lưu"</string>
+    <string name="has_dictionary" msgid="6071847973466625007">"Có sẵn từ điển"</string>
+    <!-- no translation found for prefs_enable_log (6620424505072963557) -->
+    <skip />
+    <!-- no translation found for prefs_description_log (5827825607258246003) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection (4588408906649533582) -->
+    <skip />
+    <!-- no translation found for prefs_enable_recorrection_summary (5082041365862396329) -->
+    <skip />
+    <!-- no translation found for keyboard_layout (437433231038683666) -->
+    <skip />
+    <!-- no translation found for subtype_mode_keyboard (2242090416595003881) -->
+    <skip />
+    <!-- no translation found for subtype_mode_voice (4394113125441627771) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
+</resources>
diff --git a/java/res/values-xlarge-land/dimens.xml b/java/res/values-xlarge-land/dimens.xml
new file mode 100644
index 0000000..45d6dfa
--- /dev/null
+++ b/java/res/values-xlarge-land/dimens.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<resources>
+    <dimen name="key_label_text_size">18dip</dimen>
+    <!-- left or right padding of label alignment -->
+    <dimen name="key_label_horizontal_alignment_padding">18dip</dimen>
+</resources>
diff --git a/java/res/values-xlarge/bools.xml b/java/res/values-xlarge/bools.xml
new file mode 100644
index 0000000..8c68d9d
--- /dev/null
+++ b/java/res/values-xlarge/bools.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<resources>
+    <!-- Whether or not Popup on key press is enabled by default -->
+    <bool name="default_popup_preview">false</bool>
+    <bool name="config_enable_show_settings_key_option">false</bool>
+    <bool name="config_enable_show_voice_key_option">false</bool>
+</resources>
diff --git a/java/res/values-xlarge/dimens.xml b/java/res/values-xlarge/dimens.xml
new file mode 100644
index 0000000..ecf8709
--- /dev/null
+++ b/java/res/values-xlarge/dimens.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<resources>
+    <!-- key_height + key_bottom_gap = popup_key_height -->
+    <dimen name="key_height">13.0mm</dimen>
+    <dimen name="key_bottom_gap">1.5mm</dimen>
+    <dimen name="key_horizontal_gap">2.0mm</dimen>
+    <dimen name="popup_key_height">13.0mm</dimen>
+    <dimen name="keyboard_top_padding">1.0mm</dimen>
+    <dimen name="keyboard_bottom_padding">1.0mm</dimen>
+    <!-- key_height x 1.0 -->
+    <dimen name="key_preview_height">13.0mm</dimen>
+    <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
+    <!-- popup_key_height x 1.2 -->
+    <dimen name="mini_keyboard_slide_allowance">15.6mm</dimen>
+    <!-- popup_key_height x -1.0 -->
+    <dimen name="mini_keyboard_vertical_correction">-13.0mm</dimen>
+
+    <dimen name="key_letter_size">24dip</dimen>
+    <dimen name="key_label_text_size">14dip</dimen>
+    <dimen name="key_preview_text_size_large">24dip</dimen>
+    <!-- left or right padding of label alignment -->
+    <dimen name="key_label_horizontal_alignment_padding">4dip</dimen>
+
+    <dimen name="candidate_strip_height">46dip</dimen>
+</resources>
diff --git a/java/res/values-xlarge/donottranslate.xml b/java/res/values-xlarge/donottranslate.xml
new file mode 100644
index 0000000..6f4e9b1
--- /dev/null
+++ b/java/res/values-xlarge/donottranslate.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!--  Default value of the visibility of the suggestion strip -->
+    <string name="prefs_suggestion_visibility_default_value" translatable="false">1</string>
+</resources>
diff --git a/java/res/values-zh-rCN/config.xml b/java/res/values-zh-rCN/config.xml
new file mode 100644
index 0000000..e0e3a8e
--- /dev/null
+++ b/java/res/values-zh-rCN/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0.22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index 7a4bcea..5ad059c 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"快速纠正"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"纠正常见的输入错误"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"显示建议"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"输入时启用联想提示"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"自动填写"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"按空格键和标点符号时自动插入突出显示的字词"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"显示设置键"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"自动"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"始终显示"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"自动填写"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"按空格键和标点符号时自动插入突出显示的字词"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"关闭"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"部分"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"全部"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"双连词建议"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"使用以前的字词改进建议"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"下一步"</string>
     <string name="label_done_key" msgid="2441578748772529288">"完成"</string>
     <string name="label_send_key" msgid="2815056534433717444">"发送"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"更多"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"暂停"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"等待"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"语音输入"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"语音输入功能当前还不支持您的语言,您只能输入英语语音。"</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"语音输入是一项试验性的功能,它采用了 Google 的网络语音识别功能。"</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"要关闭语音输入功能,请转至键盘设置。"</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"要使用语音输入,请按麦克风按钮或者在屏幕键盘上滑动手指。"</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"语音输入是一项试验性的功能,它采用了 Google 的网络语音识别功能。"</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"要关闭语音输入功能,请转至键盘设置。"</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"要使用语音输入,请按麦克风按钮或者在屏幕键盘上滑动手指。"</string>
     <string name="voice_listening" msgid="467518160751321844">"请开始说话"</string>
     <string name="voice_working" msgid="6666937792815731889">"正在处理"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"启用用户反馈"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"自动向 Google 发送使用情况统计信息和崩溃报告,帮助改进该输入法编辑器。"</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"触摸即可更正字词"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"您可以触摸已键入的字词,对其进行更正"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"您可以触摸已键入的字词,对其进行更正"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"键盘主题"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"键盘"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"语音"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values-zh-rTW/config.xml b/java/res/values-zh-rTW/config.xml
new file mode 100644
index 0000000..e0e3a8e
--- /dev/null
+++ b/java/res/values-zh-rTW/config.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="auto_complete_threshold_values">
+    <item msgid="3320983138663712864"></item>
+    <item msgid="1149464960325799386">"0.22"</item>
+    <item msgid="7684739510048377673">"0"</item>
+  </string-array>
+</resources>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index cbd0796..5465d86 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -44,10 +44,16 @@
     <string name="auto_punctuate_summary" msgid="6589441565817502132"></string>
     <string name="quick_fixes" msgid="5353213327680897927">"快速修正"</string>
     <string name="quick_fixes_summary" msgid="3405028402510332373">"修正一般打字錯誤"</string>
-    <string name="show_suggestions" msgid="507074425254289133">"顯示建議"</string>
-    <string name="show_suggestions_summary" msgid="1989672863935759654">"打字時顯示建議字詞"</string>
-    <string name="auto_complete" msgid="1103196318775486023">"自動完成"</string>
-    <string name="auto_complete_summary" msgid="6113149638718274624">"在反白顯示的字詞處自動插入空白鍵和標點符號鍵盤"</string>
+    <!-- no translation found for prefs_show_suggestions (3377105182950417159) -->
+    <skip />
+    <!-- no translation found for prefs_show_suggestions_summary (1583132279498502825) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_name (3219916594067551303) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_show_only_portrait_name (3551821800439659812) -->
+    <skip />
+    <!-- no translation found for prefs_suggestion_visibility_hide_name (6309143926422234673) -->
+    <skip />
     <string name="prefs_settings_key" msgid="4623341240804046498">"顯示設定金鑰"</string>
     <string name="settings_key_mode_auto_name" msgid="2993460277873684680">"自動"</string>
     <string name="settings_key_mode_always_show_name" msgid="3047567041784760575">"永遠顯示"</string>
@@ -55,6 +61,14 @@
     <!-- no translation found for settings_key_modes:0 (8549888726962891527) -->
     <!-- no translation found for settings_key_modes:1 (881280041213210923) -->
     <!-- no translation found for settings_key_modes:2 (7317310620171067848) -->
+    <string name="auto_complete" msgid="1103196318775486023">"自動完成"</string>
+    <string name="auto_complete_summary" msgid="6113149638718274624">"在反白顯示的字詞處自動插入空白鍵和標點符號鍵盤"</string>
+    <string name="auto_completion_threshold_mode_off" msgid="8100705925921970219">"關閉"</string>
+    <string name="auto_completion_threshold_mode_modest" msgid="1639075698991437157">"普通模式"</string>
+    <string name="auto_completion_threshold_mode_aggeressive" msgid="1153130653281397959">"加強模式"</string>
+    <!-- no translation found for auto_completion_threshold_modes:0 (3772724687113374811) -->
+    <!-- no translation found for auto_completion_threshold_modes:1 (7483119907292449051) -->
+    <!-- no translation found for auto_completion_threshold_modes:2 (532410375228539727) -->
     <string name="bigram_suggestion" msgid="1323347224043514969">"雙連詞建議"</string>
     <string name="bigram_suggestion_summary" msgid="4383845146070101531">"根據前一個字詞自動找出更適合的建議"</string>
   <string-array name="prediction_modes">
@@ -79,15 +93,21 @@
     <string name="label_next_key" msgid="362972844525672568">"繼續"</string>
     <string name="label_done_key" msgid="2441578748772529288">"完成"</string>
     <string name="label_send_key" msgid="2815056534433717444">"傳送"</string>
-    <string name="label_symbol_key" msgid="6175820506864489453">"?123"</string>
+    <!-- no translation found for label_to_symbol_key (8516904117128967293) -->
+    <skip />
     <string name="label_phone_key" msgid="4275497665515080551">"123"</string>
-    <string name="label_alpha_key" msgid="8864943487292437456">"ABC"</string>
+    <!-- no translation found for label_to_alpha_key (4793983863798817523) -->
+    <skip />
     <string name="label_alt_key" msgid="2846315350346694811">"ALT"</string>
+    <string name="label_more_key" msgid="3760239494604948502">"更多"</string>
+    <string name="label_tab_key" msgid="6532779603382157482">"Tab"</string>
+    <string name="label_pause_key" msgid="181098308428035340">"暫停"</string>
+    <string name="label_wait_key" msgid="6402152600878093134">"等候"</string>
     <string name="voice_warning_title" msgid="4419354150908395008">"語音輸入"</string>
     <string name="voice_warning_locale_not_supported" msgid="637923019716442333">"語音輸入目前不支援您的語言,但是可以辨識英文。"</string>
-    <string name="voice_warning_may_not_understand" msgid="4611518823070986445">"語音輸入這項實驗功能運用了 Google 的網路語音辨識系統。"</string>
-    <string name="voice_warning_how_to_turn_off" msgid="5652369578498701761">"請前往鍵盤設定來關閉語音輸入。"</string>
-    <string name="voice_hint_dialog_message" msgid="6892342981545727994">"如要使用語音輸入,按下 [麥克風] 按鈕,或將手指滑過螢幕小鍵盤即可。"</string>
+    <!-- outdated translation 4611518823070986445 -->     <string name="voice_warning_may_not_understand" msgid="5596289095878251072">"語音輸入這項實驗功能運用了 Google 的網路語音辨識系統。"</string>
+    <!-- outdated translation 5652369578498701761 -->     <string name="voice_warning_how_to_turn_off" msgid="3190378129944934856">"請前往鍵盤設定來關閉語音輸入。"</string>
+    <!-- outdated translation 6892342981545727994 -->     <string name="voice_hint_dialog_message" msgid="1420686286820661548">"如要使用語音輸入,按下 [麥克風] 按鈕,或將手指滑過螢幕小鍵盤即可。"</string>
     <string name="voice_listening" msgid="467518160751321844">"請說話"</string>
     <string name="voice_working" msgid="6666937792815731889">"辨識中"</string>
     <string name="voice_initializing" msgid="661962047129906646"></string>
@@ -133,8 +153,76 @@
     <string name="prefs_enable_log" msgid="6620424505072963557">"啟用使用者意見回饋"</string>
     <string name="prefs_description_log" msgid="5827825607258246003">"自動將使用統計資料和當機報告傳送給 Google,協助改善這個輸入法編輯器。"</string>
     <!-- outdated translation 5809974560359283818 -->     <string name="prefs_enable_recorrection" msgid="4588408906649533582">"輕觸即可重新修正字詞"</string>
-    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="1056068922330206170">"只要輕觸您所輸入的字詞,即可重新予以修正"</string>
+    <!-- outdated translation 5037231665897435902 -->     <string name="prefs_enable_recorrection_summary" msgid="5082041365862396329">"只要輕觸您所輸入的字詞,即可重新予以修正"</string>
     <string name="keyboard_layout" msgid="437433231038683666">"鍵盤主題"</string>
     <string name="subtype_mode_keyboard" msgid="2242090416595003881">"鍵盤"</string>
     <string name="subtype_mode_voice" msgid="4394113125441627771">"語音"</string>
+    <!-- no translation found for subtype_mode_cs_keyboard (1141718931112377586) -->
+    <skip />
+    <!-- no translation found for subtype_mode_da_keyboard (1243570804427922104) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_keyboard (5111274665584117449) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_keyboard (2979257184475020604) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_keyboard (2339748210942078577) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_keyboard (1775125478866113148) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_US_keyboard (6418688989436457122) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_keyboard (8016515336759761014) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CA_keyboard (2628517247158376263) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_CH_keyboard (6742806653181621228) -->
+    <skip />
+    <!-- no translation found for subtype_mode_it_keyboard (2281078537437195027) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nb_keyboard (1175783216100212360) -->
+    <skip />
+    <!-- no translation found for subtype_mode_nl_keyboard (5090278083256037936) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_keyboard (1383995915064277943) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sr_keyboard (5019440799612208168) -->
+    <skip />
+    <!-- no translation found for subtype_mode_sv_keyboard (4933838139861753401) -->
+    <skip />
+    <!-- no translation found for subtype_mode_cs_voice (157536957128878726) -->
+    <skip />
+    <!-- no translation found for subtype_mode_de_voice (309350321180102217) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_AU_voice (1103892562629586486) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_GB_voice (3773764031764533262) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_IN_voice (4834879535045820293) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_NZ_voice (2739391364469645636) -->
+    <skip />
+    <!-- no translation found for subtype_mode_en_US_voice (1582519352222847297) -->
+    <skip />
+    <!-- no translation found for subtype_mode_es_voice (1323473601346507487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_fr_voice (4675914209337824269) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ja_voice (6604859132669646367) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ko_voice (4890391190762324561) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pl_voice (2076196021014840487) -->
+    <skip />
+    <!-- no translation found for subtype_mode_pt_voice (8036522712795994397) -->
+    <skip />
+    <!-- no translation found for subtype_mode_ru_voice (8034596947963787529) -->
+    <skip />
+    <!-- no translation found for subtype_mode_tr_voice (3402067436761140005) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_CN_voice (3154514897179707124) -->
+    <skip />
+    <!-- no translation found for subtype_mode_zh_TW_voice (1524137359275360490) -->
+    <skip />
+    <!-- no translation found for prefs_usability_study_mode (6937813623647419810) -->
+    <skip />
 </resources>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 995373e..4fc5351 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -16,7 +16,7 @@
 
 <resources>
 
-    <declare-styleable name="LatinKeyboardBaseView">
+    <declare-styleable name="KeyboardView">
         <!-- Default KeyboardView style. -->
         <attr name="keyboardViewStyle" format="reference" />
 
@@ -25,8 +25,8 @@
              checkable+checked+pressed. -->
         <attr name="keyBackground" format="reference" />
 
-        <!-- Size of the text for character keys. -->
-        <attr name="keyTextSize" format="dimension" />
+        <!-- Size of the text for one letter character keys. -->
+        <attr name="keyLetterSize" format="dimension" />
 
         <!-- Size of the text for custom keys with some text and no icon. -->
         <attr name="labelTextSize" format="dimension" />
@@ -34,6 +34,9 @@
         <!-- Color to use for the label in a key. -->
         <attr name="keyTextColor" format="color" />
 
+        <!-- Color to use for the label in a key when in disabled state. -->
+        <attr name="keyTextColorDisabled" format="color" />
+
         <!-- Layout resource for key press feedback.-->
         <attr name="keyPreviewLayout" format="reference" />
 
@@ -56,17 +59,124 @@
         <attr name="shadowRadius" format="float" />
         <attr name="backgroundDimAmount" format="float" />
 
-        <attr name="keyTextStyle">
-            <flag name="normal" value="0" />
-            <flag name="bold" value="1" />
-            <flag name="italic" value="2" />
+        <attr name="keyLetterStyle">
+            <!-- This should be aligned with Typeface.NORMAL etc. -->
+            <enum name="normal" value="0" />
+            <enum name="bold" value="1" />
+            <enum name="italic" value="2" />
+            <enum name="boldItalic" value="3" />
         </attr>
 
-        <attr name="symbolColorScheme">
-            <flag name="white" value="0" />
-            <flag name="black" value="1" />
+        <attr name="colorScheme">
+            <!-- This should be aligned with KeyboardView.COLOR_SCHEME_* -->
+            <enum name="white" value="0" />
+            <enum name="black" value="1" />
         </attr>
 
     </declare-styleable>
 
+    <declare-styleable name="Keyboard">
+        <!-- Default width of a key, in pixels or percentage of display width. -->
+        <attr name="keyWidth" format="dimension|fraction" />
+        <!-- Default height of a key, in pixels or percentage of display width. -->
+        <attr name="keyHeight" format="dimension|fraction" />
+        <!-- Default horizontal gap between keys. -->
+        <attr name="horizontalGap" format="dimension|fraction" />
+        <!-- Default vertical gap between rows of keys. -->
+        <attr name="verticalGap" format="dimension|fraction" />
+    </declare-styleable>
+
+    <declare-styleable name="Keyboard_Key">
+        <!-- The unicode value or comma-separated values that this key outputs. -->
+        <attr name="codes" format="integer|string" />
+        <!-- The XML keyboard layout of any popup keyboard. -->
+        <attr name="popupKeyboard" format="reference" />
+        <!-- The characters to display in the popup keyboard. -->
+        <attr name="popupCharacters" format="string" />
+        <!-- Key edge flags. -->
+        <attr name="keyEdgeFlags">
+            <!-- Key is anchored to the left of the keyboard. -->
+            <flag name="left" value="1" />
+            <!-- Key is anchored to the right of the keyboard. -->
+            <flag name="right" value="2" />
+        </attr>
+        <!-- Whether this is a modifier key such as Alt or Shift. -->
+        <attr name="isModifier" format="boolean" />
+        <!-- Whether this is a toggle key. -->
+        <attr name="isSticky" format="boolean" />
+        <!-- Whether long-pressing on this key will make it repeat. -->
+        <attr name="isRepeatable" format="boolean" />
+        <!-- The icon to show in the popup preview. -->
+        <attr name="iconPreview" format="reference" />
+        <!-- The string of characters to output when this key is pressed. -->
+        <attr name="keyOutputText" format="string" />
+        <!-- The label to display on the key. -->
+        <attr name="keyLabel" format="string" />
+        <!-- The key label option -->
+        <attr name="keyLabelOption">
+            <!-- This should be aligned with KeyboardView.KEY_LABEL_OPTION_* -->
+            <flag name="alignLeft" value="1" />
+            <flag name="alignRight" value="2" />
+            <flag name="alignBottom" value="8" />
+            <flag name="fontNormal" value="16" />
+        </attr>
+        <!-- The unicode that this key generates in manual temporary upper case mode. -->
+        <attr name="manualTemporaryUpperCaseCode" format="integer" />
+        <!-- The icon to display on the key instead of the label. -->
+        <attr name="keyIcon" format="reference" />
+        <!-- The hint icon to display on the key in conjunction with the label -->
+        <attr name="keyHintIcon" format="reference" />
+        <!-- The hint icon to display on the key when keyboard is in manual temporary upper case
+             mode. -->
+        <attr name="manualTemporaryUpperCaseHintIcon" format="reference" />
+        <!-- The key style to specify a set of key attributes defined by <key_style/> -->
+        <attr name="keyStyle" format="string" />
+        <!-- Shift key icon for shifted state -->
+        <attr name="shiftedIcon" format="reference" />
+    </declare-styleable>
+
+    <declare-styleable name="Keyboard_Row">
+        <!-- Row edge flags. -->
+        <attr name="rowEdgeFlags">
+            <!-- Row is anchored to the top of the keyboard. -->
+            <flag name="top" value="4" />
+            <!-- Row is anchored to the bottom of the keyboard. -->
+            <flag name="bottom" value="8" />
+        </attr>
+    </declare-styleable>
+
+    <declare-styleable name="Keyboard_Include">
+        <attr name="keyboardLayout" format="reference" />
+    </declare-styleable>
+
+    <declare-styleable name="Keyboard_Case">
+        <!-- This should be aligned with KeyboardId.MODE_* -->
+        <attr name="mode">
+            <enum name="text" value="0" />
+            <enum name="url" value="1" />
+            <enum name="email" value="2" />
+            <enum name="im" value="3" />
+            <enum name="web" value="4" />
+            <enum name="phone" value="5" />
+        </attr>
+        <attr name="hasSettingsKey" format="string" />
+        <attr name="voiceKeyEnabled" format="string" />
+        <attr name="hasVoiceKey" format="string" />
+        <attr name="imeOptions">
+            <!-- This should be aligned with EditorInfo.IME_ACTION_* -->
+            <flag name="actionUnspecified" value="0" />
+            <flag name="actionNone" value="1" />
+            <flag name="actionGo" value="2" />
+            <flag name="actionSearch" value="3" />
+            <flag name="actionSend" value="4" />
+            <flag name="actionNext" value="5" />
+            <flag name="actionDone" value="6" />
+            <flag name="actionPrevious" value="7" />
+        </attr>
+    </declare-styleable>
+
+    <declare-styleable name="Keyboard_KeyStyle">
+        <attr name="styleName" format="string" />
+        <attr name="parentStyle" format="string" />
+    </declare-styleable>
 </resources>
diff --git a/java/res/values/bools.xml b/java/res/values/bools.xml
index 5a24e4c..2be9545 100644
--- a/java/res/values/bools.xml
+++ b/java/res/values/bools.xml
@@ -30,4 +30,6 @@
     <bool name="default_popup_preview">true</bool>
     <bool name="default_recorrection_enabled">true</bool>
     <bool name="config_long_press_comma_for_settings_enabled">true</bool>
+    <bool name="config_enable_show_settings_key_option">true</bool>
+    <bool name="config_enable_show_voice_key_option">true</bool>
 </resources>
diff --git a/java/res/values/config.xml b/java/res/values/config.xml
index edb6cd8..456d9ad 100644
--- a/java/res/values/config.xml
+++ b/java/res/values/config.xml
@@ -27,6 +27,19 @@
     <integer name="config_mini_keyboard_fadeout_anim_time">100</integer>
     <integer name="config_delay_before_key_repeat_start">400</integer>
     <integer name="config_key_repeat_interval">50</integer>
+    <integer name="config_keyboard_grid_width">32</integer>
+    <integer name="config_keyboard_grid_height">16</integer>
     <integer name="config_long_press_key_timeout">400</integer>
+    <integer name="config_long_press_shift_key_timeout">1200</integer>
     <integer name="config_multi_tap_key_timeout">800</integer>
+    <string-array name="auto_complete_threshold_values">
+        <!-- Off, When auto completing setting is Off, this value is not used. -->
+        <item></item>
+        <!-- Modest : Suggestion whose normalized score is greater than this value
+             will be subject to auto-completion. -->
+        <item>0.22</item>
+        <!-- Aggressive : Suggestion whose normalized score is greater than this value
+             will be subject to auto-completion. -->
+        <item>0</item>
+    </string-array>
 </resources>
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 0c3b6ad..3839ff0 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -22,29 +22,36 @@
     <!-- key_height + key_bottom_gap = popup_key_height -->
     <dimen name="key_height">0.290in</dimen>
     <dimen name="key_bottom_gap">0.035in</dimen>
+    <dimen name="key_horizontal_gap">0.000in</dimen>
     <dimen name="popup_key_height">0.325in</dimen>
+    <dimen name="keyboard_top_padding">0.00in</dimen>
     <dimen name="keyboard_bottom_padding">0.06in</dimen>
-    <dimen name="bubble_pointer_offset">22dip</dimen>
+    <!-- key_preview_text_size_large x 2 -->
+    <dimen name="key_preview_height">80sp</dimen>
+    <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
+    <!-- popup_key_height x 1.2 -->
+    <dimen name="mini_keyboard_slide_allowance">0.390in</dimen>
+    <!-- popup_key_height x -1.0 -->
+    <dimen name="mini_keyboard_vertical_correction">-0.325in</dimen>
+
+    <dimen name="key_letter_size">0.13in</dimen>
+    <dimen name="key_label_text_size">0.083in</dimen>
+    <dimen name="key_preview_text_size_large">40sp</dimen>
+    <!-- left or right padding of label alignment -->
+    <dimen name="key_label_horizontal_alignment_padding">0.13in</dimen>
+    <dimen name="key_preview_offset">0.000in</dimen>
+    <!-- We use "inch", not "dip" because this value tries dealing with physical distance related
+         to user's finger. -->
+    <dimen name="keyboard_vertical_correction">-0.05in</dimen>
+
     <dimen name="candidate_strip_height">42dip</dimen>
     <dimen name="candidate_strip_fading_edge_length">63dip</dimen>
     <dimen name="spacebar_vertical_correction">4dip</dimen>
     <!-- If the screen height in landscape is larger than the below value, then the keyboard
          will not go into extract (fullscreen) mode. -->
     <dimen name="max_height_for_fullscreen">2.5in</dimen>
-    <dimen name="key_text_size">0.13in</dimen>
-    <dimen name="key_label_text_size">0.083in</dimen>
-    <dimen name="key_preview_text_size_large">40sp</dimen>
-    <dimen name="key_preview_offset">0.000in</dimen>
-    <!-- key_preview_text_size_large x 2 -->
-    <dimen name="key_preview_height">80sp</dimen>
-    <!-- Amount of allowance for selecting keys in a mini popup keyboard by sliding finger. -->
-    <!-- popup_key_height x 1.7 -->
-    <dimen name="mini_keyboard_slide_allowance">0.553in</dimen>
-    <!-- popup_key_height x 1.0 -->
-    <dimen name="mini_keyboard_vertical_correction">-0.325in</dimen>
+    <dimen name="bubble_pointer_offset">22dip</dimen>
+
     <dimen name="key_hysteresis_distance">0.05in</dimen>
-    <!-- We use "inch", not "dip" because this value tries dealing with physical distance related
-         to user's finger. -->
-    <dimen name="keyboard_vertical_correction">-0.05in</dimen>
     <dimen name="candidate_min_touchable_width">0.3in</dimen>
 </resources>
diff --git a/java/res/values/donottranslate-altchars.xml b/java/res/values/donottranslate-altchars.xml
index bba7282..41c498e 100644
--- a/java/res/values/donottranslate-altchars.xml
+++ b/java/res/values/donottranslate-altchars.xml
@@ -37,10 +37,10 @@
     <string name="alternates_for_g"></string>
     <string name="alternates_for_p">0</string>
     <string name="alternates_for_v"></string>
-    <string name="alternates_for_ae"></string>
-    <string name="alternates_for_oe"></string>
+    <string name="keylabel_for_scandinavia_row2_10"></string>
+    <string name="keylabel_for_scandinavia_row2_11"></string>
+    <string name="alternates_for_scandinavia_row2_10"></string>
+    <string name="alternates_for_scandinavia_row2_11"></string>
     <string name="alternates_for_cyrillic_e"></string>
     <string name="alternates_for_cyrillic_soft_sign"></string>
-    <string name="alternates_for_a_umlaut"></string>
-    <string name="alternates_for_o_umlaut"></string>
 </resources>
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index 9366099..453e188 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -23,7 +23,7 @@
     <!-- Symbols that are sentence separators, for purposes of making it hug the last sentence. -->
     <string name="sentence_separators">.,!?)</string>
     <!-- Symbols that are suggested between words -->
-    <string name="suggested_punctuations">!?,\u0022\u0027:()-/@_</string>
+    <string name="suggested_punctuations">!?,\u0022\u0027:();-/@_</string>
 
     <!-- Option values to show/hide the settings key in onscreen keyboard -->
     <!-- Automatically decide to show or hide the settings key -->
@@ -32,4 +32,39 @@
     <string name="settings_key_mode_always_show" translatable="false">1</string>
     <!-- Always hide the settings key -->
     <string name="settings_key_mode_always_hide" translatable="false">2</string>
+
+    <!--  Always show the suggestion strip -->
+    <string name="prefs_suggestion_visibility_show_value" translatable="false">0</string>
+    <!--  Show the suggestion strip only on portrait mode -->
+    <string name="prefs_suggestion_visibility_show_only_portrait_value" translatable="false">1</string>
+    <!--  Always hide the suggestion strip -->
+    <string name="prefs_suggestion_visibility_hide_value" translatable="false">2</string>
+    <!--  Default value of the visibility of the suggestion strip -->
+    <string name="prefs_suggestion_visibility_default_value" translatable="false">0</string>
+
+    <!-- Keyboard theme names -->
+    <string name="layout_basic" translatable="false">Basic</string>
+    <string name="layout_high_contrast" translatable="false">Basic (High Contrast)</string>
+    <string name="layout_stone_bold"  translatable="false">Stone (bold)</string>
+    <string name="layout_stone_normal"  translatable="false">Stone (normal)</string>
+    <string name="layout_gingerbread"  translatable="false">Gingerbread</string>
+    <string name="layout_honeycomb"  translatable="false">Honeycomb</string>
+
+    <!-- For keyboard theme switcher dialog -->
+    <string-array name="keyboard_layout_modes" translatable="false">
+        <item>@string/layout_basic</item>
+        <item>@string/layout_high_contrast</item>
+        <item>@string/layout_stone_normal</item>
+        <item>@string/layout_stone_bold</item>
+        <item>@string/layout_gingerbread</item>
+        <item>@string/layout_honeycomb</item>
+    </string-array>
+    <string-array name="keyboard_layout_modes_values" translatable="false">
+        <item>0</item>
+        <item>1</item>
+        <item>2</item>
+        <item>3</item>
+        <item>4</item>
+        <item>5</item>
+    </string-array>
 </resources>
diff --git a/java/res/values/keycodes.xml b/java/res/values/keycodes.xml
index c5d5b3c..6c18cb4 100644
--- a/java/res/values/keycodes.xml
+++ b/java/res/values/keycodes.xml
@@ -19,14 +19,13 @@
 -->
 
 <resources>
+    <!-- These code should be aligned with Keyboard.CODE_*. -->
     <integer name="key_tab">9</integer>
     <integer name="key_return">10</integer>
     <integer name="key_space">32</integer>
     <integer name="key_shift">-1</integer>
-    <integer name="key_symbol">-2</integer>
+    <integer name="key_switch_alpha_symbol">-2</integer>
     <integer name="key_delete">-5</integer>
-    <!-- Keycode for F1 (function) key. This one switches between language switch & comma/.com -->
     <integer name="key_settings">-100</integer>
     <integer name="key_voice">-102</integer>
-    <integer name="key_f1">-103</integer>
 </resources>
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 6644d22..da315df 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -31,7 +31,7 @@
     <!-- Option to play back sound on keypress in soft keyboard -->
     <string name="sound_on_keypress">Sound on keypress</string>
 
-    <!-- Option to pop up the character with a larger font above soft keyboard -->
+    <!-- Option to control whether or not to show a popup with a larger font on each key press. -->
     <string name="popup_on_keypress">Popup on keypress</string>
 
     <!-- Option to enable using nearby keys when correcting/predicting -->
@@ -82,15 +82,24 @@
     <string name="quick_fixes_summary">Corrects commonly typed mistakes</string>
     
     <!-- Option to enable showing suggestions -->
-    <string name="show_suggestions">Show suggestions</string>
+    <string name="prefs_show_suggestions">Show suggestions</string>
     <!-- Description for show suggestions -->
-    <string name="show_suggestions_summary">Display suggested words while typing</string>
-    
-    <!-- Option to enable auto completion -->
-    <string name="auto_complete">Auto-complete</string>
-    <!-- Description for auto completion -->
-    <string name="auto_complete_summary">Spacebar and punctuation automatically insert highlighted word</string>
-    
+    <string name="prefs_show_suggestions_summary">Display suggested words while typing</string>
+    <!--  Option to show/hide the suggestion strip -->
+    <string-array name="prefs_suggestion_visibility_values" translatable="false">
+       <item>@string/prefs_suggestion_visibility_show_value</item>
+       <item>@string/prefs_suggestion_visibility_show_only_portrait_value</item>
+       <item>@string/prefs_suggestion_visibility_hide_value</item>
+    </string-array>
+    <string name="prefs_suggestion_visibility_show_name">Always show</string>
+    <string name="prefs_suggestion_visibility_show_only_portrait_name">Show on portrait mode</string>
+    <string name="prefs_suggestion_visibility_hide_name">Always hide</string>
+    <string-array name="prefs_suggestion_visibilities" translatable="false">
+       <item>@string/prefs_suggestion_visibility_show_name</item>
+       <item>@string/prefs_suggestion_visibility_show_only_portrait_name</item>
+       <item>@string/prefs_suggestion_visibility_hide_name</item>
+    </string-array>
+
     <!-- Option to show/hide the settings key -->
     <string name="prefs_settings_key">Show settings key</string>
     <!-- Array of the settings key mode values -->
@@ -112,6 +121,31 @@
         <item>@string/settings_key_mode_always_hide_name</item>
     </string-array>
 
+    <!-- Option to decide the auto completion threshold score -->
+    <!-- Option to enable auto completion -->
+    <string name="auto_complete">Auto-complete</string>
+    <!-- Description for auto completion -->
+    <string name="auto_complete_summary">Spacebar and punctuation automatically insert highlighted word</string>
+    <string name="auto_completion_threshold_mode_value_off" translatable="false">0</string>
+    <string name="auto_completion_threshold_mode_value_modest" translatable="false">1</string>
+    <string name="auto_completion_threshold_mode_value_aggeressive" translatable="false">2</string>
+    <string-array name="auto_completion_threshold_mode_values" translatable="false">
+      <item>@string/auto_completion_threshold_mode_value_off</item>
+      <item>@string/auto_completion_threshold_mode_value_modest</item>
+      <item>@string/auto_completion_threshold_mode_value_aggeressive</item>
+    </string-array>
+    <!-- Option to disable auto completion. -->
+    <string name="auto_completion_threshold_mode_off">Off</string>
+    <!-- Option to use modest auto completion. -->
+    <string name="auto_completion_threshold_mode_modest">Modest</string>
+    <!-- Option to use aggressive auto completion. -->
+    <string name="auto_completion_threshold_mode_aggeressive">Aggressive</string>
+    <string-array name="auto_completion_threshold_modes">
+      <item>@string/auto_completion_threshold_mode_off</item>
+      <item>@string/auto_completion_threshold_mode_modest</item>
+      <item>@string/auto_completion_threshold_mode_aggeressive</item>
+    </string-array>
+
     <!-- Option to enable bigram completion -->
     <string name="bigram_suggestion">Bigram Suggestions</string>
     <!-- Description for auto completion -->
@@ -184,14 +218,22 @@
     <string name="label_done_key">Done</string>
     <!-- Label for soft enter key when it performs SEND action.  Must be short to fit on key! -->
     <string name="label_send_key">Send</string>
-    <!-- Label for "switch to symbols" key.  Must be short to fit on key! -->
-    <string name="label_symbol_key">\?123</string>
-    <!-- Label for "switch to numeric" key.  Must be short to fit on key! -->
+    <!-- Label for "switch to symbols" key.  Must be short to fit on key! [CHAR LIMIT=4] -->
+    <string name="label_to_symbol_key">\?123</string>
+    <!-- Label for "switch to numeric" key.  Must be short to fit on key! [CHAR LIMIT=4] -->
     <string name="label_phone_key">123</string>
     <!-- Label for "switch to alphabetic" key.  Must be short to fit on key! -->
-    <string name="label_alpha_key">ABC</string>
+    <string name="label_to_alpha_key">ABC</string>
     <!-- Label for ALT modifier key.  Must be short to fit on key! -->
     <string name="label_alt_key">ALT</string>
+    <!-- Label for Shift modifier key of symbol keyboard.  Must be short to fit on key! -->
+    <string name="label_more_key">More</string>
+    <!-- Label for "Tab" key.  Must be short to fit on key! [CHAR LIMIT=4]-->
+    <string name="label_tab_key">Tab</string>
+    <!-- Label for "Pause" key of phone number keyboard.  Must be short to fit on key! [CHAR LIMIT=5] -->
+    <string name="label_pause_key">Pause</string>
+    <!-- Label for "Wait" key of phone number keyboard.  Must be short to fit on key! [CHAR LIMIT=5]-->
+    <string name="label_wait_key">Wait</string>
 
     <!-- Voice related labels -->
 
@@ -206,15 +248,15 @@
     
     <!-- Message of the warning dialog that shows when a user initiates voice input for
          the first time, or turns it on in settings. -->
-    <string name="voice_warning_may_not_understand">Voice input is an experimental feature using Google\'s networked speech recognition.</string>
+    <string name="voice_warning_may_not_understand">Voice input uses Google\'s speech recognition. <a href="http://m.google.com/privacy">The Mobile Privacy Policy</a> applies.</string>
     
     <!-- An additional part of the warning dialog for voice input that only shows when the user
          actually initiates voice input, rather than just turning it on in settings. -->
-    <string name="voice_warning_how_to_turn_off">To turn off voice input, go to keyboard settings.</string>
-    
-    <!-- Message to show when user clicks the swiping hint (which says
-        "Swipe across keyboard to speak"). Also shown when enabling settings. -->
-    <string name="voice_hint_dialog_message">To use voice input, press the microphone button or slide your finger across the on-screen keyboard.</string>
+    <string name="voice_warning_how_to_turn_off">To turn off voice input, go to input method settings.</string>
+
+    <!-- Message to show when user enables the voice input settings (which says
+        "Press the microphone button"). -->
+    <string name="voice_hint_dialog_message">To use voice input, press the microphone button.</string>
     
     <!-- Short message to tell the user the system is ready for them to speak. -->
     <string name="voice_listening">Speak now</string>
@@ -344,36 +386,51 @@
     <!-- Preferences item for enabling to correct suggestions by touching words you have typed -->
     <string name="prefs_enable_recorrection">Touch to correct words</string>
     <!-- The summary for the preferences item for enabling to correct suggestions by touching words you have typed -->
-    <string name="prefs_enable_recorrection_summary">Touch entered words to correct them</string>
+    <string name="prefs_enable_recorrection_summary">Touch entered words to correct them, only when suggestions are visible</string>
 
     <!-- Description for keyboard theme switcher -->
     <string name="keyboard_layout">Keyboard Theme</string>
-    <string name="layout_basic" translatable="false">Basic</string>
-    <string name="layout_high_contrast" translatable="false">Basic (High Contrast)</string>
-    <string name="layout_stone_bold"  translatable="false">Stone (bold)</string>
-    <string name="layout_stone_normal"  translatable="false">Stone (normal)</string>
-    <string name="layout_gingerbread"  translatable="false">Gingerbread</string>
-
-    <string-array name="keyboard_layout_modes" translatable="false">
-        <item>@string/layout_basic</item>
-        <item>@string/layout_high_contrast</item>
-        <item>@string/layout_stone_normal</item>
-        <item>@string/layout_stone_bold</item>
-        <item>@string/layout_gingerbread</item>
-    </string-array>
-
-    <string-array name="keyboard_layout_modes_values" translatable="false">
-        <item>0</item>
-        <item>1</item>
-        <item>2</item>
-        <item>3</item>
-        <item>4</item>
-    </string-array>
 
     <string name="subtype_mode_keyboard">keyboard</string>
     <string name="subtype_mode_voice">voice</string>
+    <string name="subtype_mode_cs_keyboard">Czech Keyboard</string>
+    <string name="subtype_mode_da_keyboard">Danish Keyboard</string>
+    <string name="subtype_mode_de_keyboard">German Keyboard</string>
+    <string name="subtype_mode_en_GB_keyboard">English (United Kingdom) Keyboard</string>
+    <string name="subtype_mode_en_US_keyboard">English (United States) Keyboard</string>
+    <string name="subtype_mode_es_keyboard">Spanish Keyboard</string>
+    <string name="subtype_mode_es_US_keyboard">Spanish (United States) Keyboard</string>
+    <string name="subtype_mode_fr_keyboard">French Keyboard</string>
+    <string name="subtype_mode_fr_CA_keyboard">French (Canada) Keyboard</string>
+    <string name="subtype_mode_fr_CH_keyboard">French (Switzerland) Keyboard</string>
+    <string name="subtype_mode_it_keyboard">Italian Keyboard</string>
+    <string name="subtype_mode_nb_keyboard">Norwegian Keyboard</string>
+    <string name="subtype_mode_nl_keyboard">Dutch Keyboard</string>
+    <string name="subtype_mode_ru_keyboard">Russian Keyboard</string>
+    <string name="subtype_mode_sr_keyboard">Serbian Keyboard</string>
+    <string name="subtype_mode_sv_keyboard">Swedish Keyboard</string>
+
+    <string name="subtype_mode_cs_voice">Czech Voice</string>
+    <string name="subtype_mode_de_voice">German Voice</string>
+    <string name="subtype_mode_en_AU_voice">English (Australia) Voice</string>
+    <string name="subtype_mode_en_GB_voice">English (United Kingdom) Voice</string>
+    <string name="subtype_mode_en_IN_voice">English (India) Voice</string>
+    <string name="subtype_mode_en_NZ_voice">English (New Zealand) Voice</string>
+    <string name="subtype_mode_en_US_voice">English (United States) Voice</string>
+    <string name="subtype_mode_es_voice">Spanish Voice</string>
+    <string name="subtype_mode_fr_voice">French Voice</string>
+    <string name="subtype_mode_ja_voice">Japanese Voice</string>
+    <string name="subtype_mode_ko_voice">Korean Voice</string>
+    <string name="subtype_mode_pl_voice">Polish Voice</string>
+    <string name="subtype_mode_pt_voice">Portuguese Voice</string>
+    <string name="subtype_mode_ru_voice">Russian Voice</string>
+    <string name="subtype_mode_tr_voice">Turkish Voice</string>
+    <string name="subtype_mode_zh_CN_voice">Chinese (China) Voice</string>
+    <string name="subtype_mode_zh_TW_voice">Chinese (Taiwan) Voice</string>
 
     <!-- Title for Latin keyboard debug settings activity / dialog -->
     <string name="english_ime_debug_settings" translatable="false">Android keyboard Debug settings</string>
     <string name="prefs_debug_mode" translatable="false">Debug Mode</string>
+    <!-- Title of an option for usability study mode -->
+    <string name="prefs_usability_study_mode">Usability Study Mode</string>
 </resources>
diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml
index 0372b07..130714f 100644
--- a/java/res/values/styles.xml
+++ b/java/res/values/styles.xml
@@ -15,12 +15,14 @@
 -->
 
 <resources>
-    <style name="LatinKeyboardBaseView">
+    <style name="KeyboardView">
         <item name="android:background">@drawable/keyboard_background</item>
 
         <item name="keyBackground">@drawable/btn_keyboard_key</item>
-        <item name="keyTextSize">@dimen/key_text_size</item>
+        <item name="keyLetterSize">@dimen/key_letter_size</item>
+        <item name="keyLetterStyle">normal</item>
         <item name="keyTextColor">#FFFFFFFF</item>
+        <item name="keyTextColorDisabled">#FFFFFFFF</item>
         <item name="keyPreviewLayout">@layout/key_preview</item>
         <item name="keyPreviewOffset">@dimen/key_preview_offset</item>
         <item name="keyPreviewHeight">@dimen/key_preview_height</item>
@@ -31,7 +33,7 @@
         <item name="shadowColor">#BB000000</item>
         <item name="shadowRadius">2.75</item>
         <item name="backgroundDimAmount">0.5</item>
-        <item name="symbolColorScheme">white</item>
+        <item name="colorScheme">white</item>
     </style>
     <style name="KeyPreviewAnimation">
         <item name="android:windowEnterAnimation">@anim/key_preview_fadein</item>
diff --git a/java/res/xml-da-xlarge/kbd_qwerty.xml b/java/res/xml-da-xlarge/kbd_qwerty.xml
new file mode 100644
index 0000000..3170b08
--- /dev/null
+++ b/java/res/xml-da-xlarge/kbd_qwerty.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<!--
+    Danish Keyboard Layout
+
+    Just a copy of the Norwegian layout, with æ/ø switched.
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_rows_scandinavia" />
+</Keyboard>
diff --git a/java/res/xml-da/kbd_qwerty.xml b/java/res/xml-da/kbd_qwerty.xml
index b7b1b17..ac30b00 100644
--- a/java/res/xml-da/kbd_qwerty.xml
+++ b/java/res/xml-da/kbd_qwerty.xml
@@ -25,512 +25,12 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="9.09%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="9.09%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="q"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_q"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="w"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_w" />
-        <Key
-            android:keyLabel="e"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_e" />
-        <Key
-            android:keyLabel="r"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_r" />
-        <Key
-            android:keyLabel="t"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_t" />
-        <Key
-            android:keyLabel="y"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_y" />
-        <Key
-            android:keyLabel="u"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_u" />
-        <Key
-            android:keyLabel="i"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_i" />
-        <Key
-            android:keyLabel="o"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_o" />
-        <Key
-            android:keyLabel="p"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_p" />
-        <Key
-            android:keyLabel="å"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="a"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="s"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_s" />
-        <Key
-            android:keyLabel="d"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_d" />
-        <Key
-            android:keyLabel="f" />
-        <Key
-            android:keyLabel="g"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_g" />
-        <Key
-            android:keyLabel="h" />
-        <Key
-            android:keyLabel="j" />
-        <Key
-            android:keyLabel="k" />
-        <Key
-            android:keyLabel="l"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_l" />
-        <Key
-            android:keyLabel="æ"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_ae" />
-        <Key
-            android:keyLabel="ø"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_oe"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyWidth="10%p"
-    >
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_keyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="z"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_z" />
-        <Key
-            android:keyLabel="x" />
-        <Key
-            android:keyLabel="c"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_c" />
-        <Key
-            android:keyLabel="v"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_v" />
-        <Key
-            android:keyLabel="b" />
-        <Key
-            android:keyLabel="n"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_n" />
-        <Key
-            android:keyLabel="m" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_rows_scandinavia" />
 </Keyboard>
diff --git a/java/res/xml-da/kbd_qwerty_black.xml b/java/res/xml-da/kbd_qwerty_black.xml
deleted file mode 100644
index 3fb4acd..0000000
--- a/java/res/xml-da/kbd_qwerty_black.xml
+++ /dev/null
@@ -1,478 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<!--
-    Danish Keyboard Layout
-
-    Just a copy of the Norwegian layout, with æ/ø switched.
--->
-
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="9.09%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="q"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_q"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="w"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_w" />
-        <Key
-            android:keyLabel="e"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_e" />
-        <Key
-            android:keyLabel="r"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_r" />
-        <Key
-            android:keyLabel="t"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_t" />
-        <Key
-            android:keyLabel="y"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_y" />
-        <Key
-            android:keyLabel="u"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_u" />
-        <Key
-            android:keyLabel="i"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_i" />
-        <Key
-            android:keyLabel="o"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_o" />
-        <Key
-            android:keyLabel="p"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_p" />
-        <Key
-            android:keyLabel="å"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="a"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="s"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_s" />
-        <Key
-            android:keyLabel="d"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_d" />
-        <Key
-            android:keyLabel="f" />
-        <Key
-            android:keyLabel="g"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_g" />
-        <Key
-            android:keyLabel="h" />
-        <Key
-            android:keyLabel="j" />
-        <Key
-            android:keyLabel="k" />
-        <Key
-            android:keyLabel="l"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_l" />
-        <Key
-            android:keyLabel="æ"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_ae" />
-        <Key
-            android:keyLabel="ø"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_oe"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyWidth="10%p"
-    >
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_bkeyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="z"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_z" />
-        <Key
-            android:keyLabel="x" />
-        <Key
-            android:keyLabel="c"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_c" />
-        <Key
-            android:keyLabel="v"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_v" />
-        <Key
-            android:keyLabel="b" />
-        <Key
-            android:keyLabel="n"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_n" />
-        <Key
-            android:keyLabel="m" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml-de-xlarge/kbd_qwerty.xml b/java/res/xml-de-xlarge/kbd_qwerty.xml
new file mode 100644
index 0000000..8e8e692
--- /dev/null
+++ b/java/res/xml-de-xlarge/kbd_qwerty.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwertz_rows" />
+</Keyboard>
diff --git a/java/res/xml-de/kbd_qwerty.xml b/java/res/xml-de/kbd_qwerty.xml
index 6f34b45..8e8e692 100644
--- a/java/res/xml-de/kbd_qwerty.xml
+++ b/java/res/xml-de/kbd_qwerty.xml
@@ -19,497 +19,12 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="q"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_q"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="w"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_w" />
-        <Key
-            android:keyLabel="e"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_e" />
-        <Key
-            android:keyLabel="r"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_r" />
-        <Key
-            android:keyLabel="t"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_t" />
-        <Key
-            android:keyLabel="z"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_z" />
-        <Key
-            android:keyLabel="u"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_u" />
-        <Key
-            android:keyLabel="i"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_i" />
-        <Key
-            android:keyLabel="o"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_o" />
-        <Key
-            android:keyLabel="p"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="a"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a"
-            android:horizontalGap="5%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="s"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_s" />
-        <Key
-            android:keyLabel="d"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_d" />
-        <Key
-            android:keyLabel="f" />
-        <Key
-            android:keyLabel="g"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_g" />
-        <Key
-            android:keyLabel="h" />
-        <Key
-            android:keyLabel="j" />
-        <Key
-            android:keyLabel="k" />
-        <Key
-            android:keyLabel="l"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_l"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_keyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="y"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_y" />
-        <Key
-            android:keyLabel="x" />
-        <Key
-            android:keyLabel="c"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_c" />
-        <Key
-            android:keyLabel="v"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_v" />
-        <Key
-            android:keyLabel="b" />
-        <Key
-            android:keyLabel="n"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_n" />
-        <Key
-            android:keyLabel="m" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwertz_rows" />
 </Keyboard>
diff --git a/java/res/xml-de/kbd_qwerty_black.xml b/java/res/xml-de/kbd_qwerty_black.xml
deleted file mode 100644
index 8335370..0000000
--- a/java/res/xml-de/kbd_qwerty_black.xml
+++ /dev/null
@@ -1,457 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="q"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_q"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="w"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_w" />
-        <Key
-            android:keyLabel="e"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_e" />
-        <Key
-            android:keyLabel="r"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_r" />
-        <Key
-            android:keyLabel="t"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_t" />
-        <Key
-            android:keyLabel="z"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_z" />
-        <Key
-            android:keyLabel="u"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_u" />
-        <Key
-            android:keyLabel="i"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_i" />
-        <Key
-            android:keyLabel="o"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_o" />
-        <Key
-            android:keyLabel="p"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="a"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a"
-            android:horizontalGap="5%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="s"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_s" />
-        <Key
-            android:keyLabel="d"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_d" />
-        <Key
-            android:keyLabel="f" />
-        <Key
-            android:keyLabel="g"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_g" />
-        <Key
-            android:keyLabel="h" />
-        <Key
-            android:keyLabel="j" />
-        <Key
-            android:keyLabel="k" />
-        <Key
-            android:keyLabel="l"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_l"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_bkeyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="y"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_y" />
-        <Key
-            android:keyLabel="x" />
-        <Key
-            android:keyLabel="c"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_c" />
-        <Key
-            android:keyLabel="v"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_v" />
-        <Key
-            android:keyLabel="b" />
-        <Key
-            android:keyLabel="n"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_n" />
-        <Key
-            android:keyLabel="m" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="/" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="\@" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:keyLabel="/" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:keyLabel="\@" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml-fr-rCA-xlarge/kbd_qwerty.xml b/java/res/xml-fr-rCA-xlarge/kbd_qwerty.xml
new file mode 100644
index 0000000..42f1515
--- /dev/null
+++ b/java/res/xml-fr-rCA-xlarge/kbd_qwerty.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_rows" />
+</Keyboard>
diff --git a/java/res/xml-fr-rCA/kbd_qwerty.xml b/java/res/xml-fr-rCA/kbd_qwerty.xml
new file mode 100644
index 0000000..42f1515
--- /dev/null
+++ b/java/res/xml-fr-rCA/kbd_qwerty.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_rows" />
+</Keyboard>
diff --git a/java/res/xml-fr-rCH-xlarge/kbd_qwerty.xml b/java/res/xml-fr-rCH-xlarge/kbd_qwerty.xml
new file mode 100644
index 0000000..8e8e692
--- /dev/null
+++ b/java/res/xml-fr-rCH-xlarge/kbd_qwerty.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwertz_rows" />
+</Keyboard>
diff --git a/java/res/xml-fr-rCH/kbd_qwerty.xml b/java/res/xml-fr-rCH/kbd_qwerty.xml
new file mode 100644
index 0000000..8e8e692
--- /dev/null
+++ b/java/res/xml-fr-rCH/kbd_qwerty.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwertz_rows" />
+</Keyboard>
diff --git a/java/res/xml-fr-xlarge/kbd_qwerty.xml b/java/res/xml-fr-xlarge/kbd_qwerty.xml
new file mode 100644
index 0000000..8d68a55
--- /dev/null
+++ b/java/res/xml-fr-xlarge/kbd_qwerty.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_azerty_rows" />
+</Keyboard>
diff --git a/java/res/xml-fr/kbd_qwerty.xml b/java/res/xml-fr/kbd_qwerty.xml
index 9a2c75d..8d68a55 100644
--- a/java/res/xml-fr/kbd_qwerty.xml
+++ b/java/res/xml-fr/kbd_qwerty.xml
@@ -19,498 +19,12 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="a"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="z"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_z" />
-        <Key
-            android:keyLabel="e"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_e" />
-        <Key
-            android:keyLabel="r"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_r" />
-        <Key
-            android:keyLabel="t"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_t" />
-        <Key
-            android:keyLabel="y"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_y" />
-        <Key
-            android:keyLabel="u"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_u" />
-        <Key
-            android:keyLabel="i"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_i" />
-        <Key
-            android:keyLabel="o"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_o" />
-        <Key
-            android:keyLabel="p"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="q"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_q"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="s"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_s" />
-        <Key
-            android:keyLabel="d"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_d" />
-        <Key
-            android:keyLabel="f" />
-        <Key
-            android:keyLabel="g"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_g" />
-        <Key
-            android:keyLabel="h" />
-        <Key
-            android:keyLabel="j" />
-        <Key
-            android:keyLabel="k" />
-        <Key
-            android:keyLabel="l"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_l" />
-        <Key
-            android:keyLabel="m"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_keyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="w"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_w" />
-        <Key
-            android:keyLabel="x" />
-        <Key
-            android:keyLabel="c"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_c" />
-        <Key
-            android:keyLabel="v"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_v" />
-        <Key
-            android:keyLabel="b" />
-        <Key
-            android:keyLabel="n"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_n" />
-        <Key
-            android:keyLabel="\'" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_azerty_rows" />
 </Keyboard>
diff --git a/java/res/xml-fr/kbd_qwerty_black.xml b/java/res/xml-fr/kbd_qwerty_black.xml
deleted file mode 100644
index f11c4a0..0000000
--- a/java/res/xml-fr/kbd_qwerty_black.xml
+++ /dev/null
@@ -1,458 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="a"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="z"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_z" />
-        <Key
-            android:keyLabel="e"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_e" />
-        <Key
-            android:keyLabel="r"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_r" />
-        <Key
-            android:keyLabel="t"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_t" />
-        <Key
-            android:keyLabel="y"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_y" />
-        <Key
-            android:keyLabel="u"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_u" />
-        <Key
-            android:keyLabel="i"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_i" />
-        <Key
-            android:keyLabel="o"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_o" />
-        <Key
-            android:keyLabel="p"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="q"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_q"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="s"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_s" />
-        <Key
-            android:keyLabel="d"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_d" />
-        <Key
-            android:keyLabel="f" />
-        <Key
-            android:keyLabel="g"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_g" />
-        <Key
-            android:keyLabel="h" />
-        <Key
-            android:keyLabel="j" />
-        <Key
-            android:keyLabel="k" />
-        <Key
-            android:keyLabel="l"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_l" />
-        <Key
-            android:keyLabel="m"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_bkeyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="w"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_w" />
-        <Key
-            android:keyLabel="x" />
-        <Key
-            android:keyLabel="c"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_c" />
-        <Key
-            android:keyLabel="v"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_v" />
-        <Key
-            android:keyLabel="b" />
-        <Key
-            android:keyLabel="n"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_n" />
-        <Key
-            android:keyLabel="\'" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml-iw/kbd_qwerty.xml b/java/res/xml-iw/kbd_qwerty.xml
index 5d8338a..514f935 100644
--- a/java/res/xml-iw/kbd_qwerty.xml
+++ b/java/res/xml-iw/kbd_qwerty.xml
@@ -19,456 +19,90 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
     <Row
-        android:rowEdgeFlags="top"
+        latin:rowEdgeFlags="top"
     >
+        <Spacer
+            latin:horizontalGap="5%p" />
         <Key
-            android:keyLabel="ק"
-            android:horizontalGap="5%p"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="ק"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="ר" />
+            latin:keyLabel="ר" />
         <Key
-            android:keyLabel="א" />
+            latin:keyLabel="א" />
         <Key
-            android:keyLabel="ט" />
+            latin:keyLabel="ט" />
         <Key
-            android:keyLabel="ו" />
+            latin:keyLabel="ו" />
         <Key
-            android:keyLabel="ן" />
+            latin:keyLabel="ן" />
         <Key
-            android:keyLabel="ם" />
+            latin:keyLabel="ם" />
         <Key
-            android:keyLabel="פ" />
+            latin:keyLabel="פ" />
+        <Spacer
+            latin:horizontalGap="1.25%p" />
         <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="13.75%p"
-            android:isModifier="true"
-            android:horizontalGap="1.25%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="13.75%p"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row>
         <Key
-            android:keyLabel="ש"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="ש"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="ד" />
+            latin:keyLabel="ד" />
         <Key
-            android:keyLabel="ג" />
+            latin:keyLabel="ג" />
         <Key
-            android:keyLabel="כ" />
+            latin:keyLabel="כ" />
         <Key
-            android:keyLabel="ע" />
+            latin:keyLabel="ע" />
         <Key
-            android:keyLabel="י" />
+            latin:keyLabel="י" />
         <Key
-            android:keyLabel="ח" />
+            latin:keyLabel="ח" />
         <Key
-            android:keyLabel="ל" />
+            latin:keyLabel="ל" />
         <Key
-            android:keyLabel="ך" />
+            latin:keyLabel="ך" />
         <Key
-            android:keyLabel="ף"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="ף"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row>
+        <Spacer
+            latin:horizontalGap="5%p" />
         <Key
-            android:keyLabel="ז"
-            android:horizontalGap="5%p"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="ז"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="ס" />
+            latin:keyLabel="ס" />
         <Key
-            android:keyLabel="ב" />
+            latin:keyLabel="ב" />
         <Key
-            android:keyLabel="ה" />
+            latin:keyLabel="ה" />
         <Key
-            android:keyLabel="נ" />
+            latin:keyLabel="נ" />
         <Key
-            android:keyLabel="מ" />
+            latin:keyLabel="מ" />
         <Key
-            android:keyLabel="צ" />
+            latin:keyLabel="צ" />
         <Key
-            android:keyLabel="ת" />
+            latin:keyLabel="ת" />
         <Key
-            android:keyLabel="ץ"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="ץ"
+            latin:keyEdgeFlags="right" />
     </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
+    <include latin:keyboardLayout="@xml/kbd_qwerty_row4" />
 </Keyboard>
diff --git a/java/res/xml-iw/kbd_qwerty_black.xml b/java/res/xml-iw/kbd_qwerty_black.xml
deleted file mode 100644
index eee6dc1..0000000
--- a/java/res/xml-iw/kbd_qwerty_black.xml
+++ /dev/null
@@ -1,416 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="ק"
-            android:horizontalGap="5%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="ר" />
-        <Key
-            android:keyLabel="א" />
-        <Key
-            android:keyLabel="ט" />
-        <Key
-            android:keyLabel="ו" />
-        <Key
-            android:keyLabel="ן" />
-        <Key
-            android:keyLabel="ם" />
-        <Key
-            android:keyLabel="פ" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="13.75%p"
-            android:horizontalGap="1.25%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="ש"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="ד" />
-        <Key
-            android:keyLabel="ג" />
-        <Key
-            android:keyLabel="כ" />
-        <Key
-            android:keyLabel="ע" />
-        <Key
-            android:keyLabel="י" />
-        <Key
-            android:keyLabel="ח" />
-        <Key
-            android:keyLabel="ל" />
-        <Key
-            android:keyLabel="ך" />
-        <Key
-            android:keyLabel="ף"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="ז"
-            android:horizontalGap="5%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="ס" />
-        <Key
-            android:keyLabel="ב" />
-        <Key
-            android:keyLabel="ה" />
-        <Key
-            android:keyLabel="נ" />
-        <Key
-            android:keyLabel="מ" />
-        <Key
-            android:keyLabel="צ" />
-        <Key
-            android:keyLabel="ת" />
-        <Key
-            android:keyLabel="ץ"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml-nb-xlarge/kbd_qwerty.xml b/java/res/xml-nb-xlarge/kbd_qwerty.xml
new file mode 100644
index 0000000..b137b58
--- /dev/null
+++ b/java/res/xml-nb-xlarge/kbd_qwerty.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<!--
+    Norwegian Keyboard Layout
+
+    Just a copy of the Swedish layout, with ä/æ and ö/ø switched.
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_rows_scandinavia" />
+</Keyboard>
diff --git a/java/res/xml-nb/kbd_qwerty.xml b/java/res/xml-nb/kbd_qwerty.xml
index 14071d7..fe33e53 100644
--- a/java/res/xml-nb/kbd_qwerty.xml
+++ b/java/res/xml-nb/kbd_qwerty.xml
@@ -25,512 +25,12 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="9.09%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="9.09%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="q"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_q"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="w"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_w" />
-        <Key
-            android:keyLabel="e"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_e" />
-        <Key
-            android:keyLabel="r"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_r" />
-        <Key
-            android:keyLabel="t"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_t" />
-        <Key
-            android:keyLabel="y"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_y" />
-        <Key
-            android:keyLabel="u"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_u" />
-        <Key
-            android:keyLabel="i"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_i" />
-        <Key
-            android:keyLabel="o"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_o" />
-        <Key
-            android:keyLabel="p"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_p" />
-        <Key
-            android:keyLabel="å"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="a"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="s"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_s" />
-        <Key
-            android:keyLabel="d"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_d" />
-        <Key
-            android:keyLabel="f" />
-        <Key
-            android:keyLabel="g"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_g" />
-        <Key
-            android:keyLabel="h" />
-        <Key
-            android:keyLabel="j" />
-        <Key
-            android:keyLabel="k" />
-        <Key
-            android:keyLabel="l"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_l" />
-        <Key
-            android:keyLabel="ø"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_oe" />
-        <Key
-            android:keyLabel="æ"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_ae"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyWidth="10%p"
-    >
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_keyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="z"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_z" />
-        <Key
-            android:keyLabel="x" />
-        <Key
-            android:keyLabel="c"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_c" />
-        <Key
-            android:keyLabel="v"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_v" />
-        <Key
-            android:keyLabel="b" />
-        <Key
-            android:keyLabel="n"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_n" />
-        <Key
-            android:keyLabel="m" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_rows_scandinavia" />
 </Keyboard>
diff --git a/java/res/xml-nb/kbd_qwerty_black.xml b/java/res/xml-nb/kbd_qwerty_black.xml
deleted file mode 100644
index d90313a..0000000
--- a/java/res/xml-nb/kbd_qwerty_black.xml
+++ /dev/null
@@ -1,478 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<!--
-    Norwegian Keyboard Layout
-
-    Just a copy of the Swedish layout, with ä/æ and ö/ø switched.
--->
-
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="9.09%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="q"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_q"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="w"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_w" />
-        <Key
-            android:keyLabel="e"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_e" />
-        <Key
-            android:keyLabel="r"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_r" />
-        <Key
-            android:keyLabel="t"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_t" />
-        <Key
-            android:keyLabel="y"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_y" />
-        <Key
-            android:keyLabel="u"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_u" />
-        <Key
-            android:keyLabel="i"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_i" />
-        <Key
-            android:keyLabel="o"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_o" />
-        <Key
-            android:keyLabel="p"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_p" />
-        <Key
-            android:keyLabel="å"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="a"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="s"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_s" />
-        <Key
-            android:keyLabel="d"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_d" />
-        <Key
-            android:keyLabel="f" />
-        <Key
-            android:keyLabel="g"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_g" />
-        <Key
-            android:keyLabel="h" />
-        <Key
-            android:keyLabel="j" />
-        <Key
-            android:keyLabel="k" />
-        <Key
-            android:keyLabel="l"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_l" />
-        <Key
-            android:keyLabel="ø"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_oe" />
-        <Key
-            android:keyLabel="æ"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_ae"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyWidth="10%p"
-    >
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_bkeyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="z"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_z" />
-        <Key
-            android:keyLabel="x" />
-        <Key
-            android:keyLabel="c"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_c" />
-        <Key
-            android:keyLabel="v"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_v" />
-        <Key
-            android:keyLabel="b" />
-        <Key
-            android:keyLabel="n"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_n" />
-        <Key
-            android:keyLabel="m" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml-ru-xlarge/kbd_qwerty.xml b/java/res/xml-ru-xlarge/kbd_qwerty.xml
new file mode 100644
index 0000000..fef0421
--- /dev/null
+++ b/java/res/xml-ru-xlarge/kbd_qwerty.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="9.091%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <!-- This row is intentionally not marked as a top row -->
+    <Row
+        latin:keyWidth="7.520%p"
+    >
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="й"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="1" />
+        <Key
+            latin:keyLabel="ц"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="2" />
+        <Key
+            latin:keyLabel="у"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="3" />
+        <Key
+            latin:keyLabel="к"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="4" />
+        <Key
+            latin:keyLabel="е"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_cyrillic_e" />
+        <Key
+            latin:keyLabel="н"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="6" />
+        <Key
+            latin:keyLabel="г"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="7" />
+        <Key
+            latin:keyLabel="ш"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="8" />
+        <Key
+            latin:keyLabel="щ"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="9" />
+        <Key
+            latin:keyLabel="з"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="0" />
+        <Key
+            latin:keyLabel="х" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="7.520%p"
+    >
+        <Key
+            latin:keyStyle="toSymbolKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="ф" />
+        <Key
+            latin:keyLabel="ы" />
+        <Key
+            latin:keyLabel="в" />
+        <Key
+            latin:keyLabel="а" />
+        <Key
+            latin:keyLabel="п" />
+        <Key
+            latin:keyLabel="р" />
+        <Key
+            latin:keyLabel="о" />
+        <Key
+            latin:keyLabel="л" />
+        <Key
+            latin:keyLabel="д" />
+        <Key
+            latin:keyLabel="ж" />
+        <Key
+            latin:keyLabel="э" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="8.042%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="15.192%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="я" />
+        <Key
+            latin:keyLabel="ч" />
+        <Key
+            latin:keyLabel="с" />
+        <Key
+            latin:keyLabel="м" />
+        <Key
+            latin:keyLabel="и" />
+        <Key
+            latin:keyLabel="т" />
+        <Key
+            latin:keyLabel="ь"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_cyrillic_soft_sign" />
+        <Key
+            latin:keyLabel="б" />
+        <Key
+            latin:keyLabel="ю" />
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="12.530%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</Keyboard>
diff --git a/java/res/xml-ru/kbd_qwerty.xml b/java/res/xml-ru/kbd_qwerty.xml
index c0b98ba..d5744c9 100644
--- a/java/res/xml-ru/kbd_qwerty.xml
+++ b/java/res/xml-ru/kbd_qwerty.xml
@@ -19,496 +19,134 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="9.09%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="9.091%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
     <Row
-        android:rowEdgeFlags="top"
+        latin:rowEdgeFlags="top"
     >
         <Key
-            android:keyLabel="й"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="1"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="й"
+            latin:keyHintIcon="@drawable/keyboard_hint_1"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="1"
+            latin:keyWidth="8.75%p"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="ц"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="2" />
+            latin:keyLabel="ц"
+            latin:keyHintIcon="@drawable/keyboard_hint_2"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="2" />
         <Key
-            android:keyLabel="у"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="3" />
+            latin:keyLabel="у"
+            latin:keyHintIcon="@drawable/keyboard_hint_3"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="3" />
         <Key
-            android:keyLabel="к"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="4" />
+            latin:keyLabel="к"
+            latin:keyHintIcon="@drawable/keyboard_hint_4"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="4" />
         <Key
-            android:keyLabel="е"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_cyrillic_e" />
+            latin:keyLabel="е"
+            latin:keyHintIcon="@drawable/keyboard_hint_5"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_cyrillic_e" />
         <Key
-            android:keyLabel="н"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="6" />
+            latin:keyLabel="н"
+            latin:keyHintIcon="@drawable/keyboard_hint_6"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="6" />
         <Key
-            android:keyLabel="г"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="7" />
+            latin:keyLabel="г"
+            latin:keyHintIcon="@drawable/keyboard_hint_7"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="7" />
         <Key
-            android:keyLabel="ш"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="8" />
+            latin:keyLabel="ш"
+            latin:keyHintIcon="@drawable/keyboard_hint_8"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="8" />
         <Key
-            android:keyLabel="щ"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="9" />
+            latin:keyLabel="щ"
+            latin:keyHintIcon="@drawable/keyboard_hint_9"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="9" />
         <Key
-            android:keyLabel="з"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="0" />
+            latin:keyLabel="з"
+            latin:keyHintIcon="@drawable/keyboard_hint_0"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="0" />
         <Key
-            android:keyLabel="х"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="х"
+            latin:keyWidth="8.75%p"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row>
         <Key
-            android:keyLabel="ф"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="ф"
+            latin:keyWidth="8.75%p"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="ы" />
+            latin:keyLabel="ы" />
         <Key
-            android:keyLabel="в" />
+            latin:keyLabel="в" />
         <Key
-            android:keyLabel="а" />
+            latin:keyLabel="а" />
         <Key
-            android:keyLabel="п" />
+            latin:keyLabel="п" />
         <Key
-            android:keyLabel="р" />
+            latin:keyLabel="р" />
         <Key
-            android:keyLabel="о" />
+            latin:keyLabel="о" />
         <Key
-            android:keyLabel="л" />
+            latin:keyLabel="л" />
         <Key
-            android:keyLabel="д" />
+            latin:keyLabel="д" />
         <Key
-            android:keyLabel="ж" />
+            latin:keyLabel="ж" />
         <Key
-            android:keyLabel="э"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="э"
+            latin:keyWidth="8.75%p"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row
-        android:keyWidth="8.5%p"
+        latin:keyWidth="8.5%p"
     >
         <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_keyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="11.75%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="11.75%p"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="я" />
+            latin:keyLabel="я" />
         <Key
-            android:keyLabel="ч" />
+            latin:keyLabel="ч" />
         <Key
-            android:keyLabel="с" />
+            latin:keyLabel="с" />
         <Key
-            android:keyLabel="м" />
+            latin:keyLabel="м" />
         <Key
-            android:keyLabel="и" />
+            latin:keyLabel="и" />
         <Key
-            android:keyLabel="т" />
+            latin:keyLabel="т" />
         <Key
-            android:keyLabel="ь"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_cyrillic_soft_sign" />
+            latin:keyLabel="ь"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_cyrillic_soft_sign" />
         <Key
-            android:keyLabel="б" />
+            latin:keyLabel="б" />
         <Key
-            android:keyLabel="ю" />
+            latin:keyLabel="ю" />
         <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="11.75%p"
-            android:isModifier="true"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="11.75%p"
+            latin:keyEdgeFlags="right" />
     </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row4" />
 </Keyboard>
diff --git a/java/res/xml-ru/kbd_qwerty_black.xml b/java/res/xml-ru/kbd_qwerty_black.xml
deleted file mode 100644
index 94a450c..0000000
--- a/java/res/xml-ru/kbd_qwerty_black.xml
+++ /dev/null
@@ -1,456 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="9.09%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="й"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="1"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="ц"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="2" />
-        <Key
-            android:keyLabel="у"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="3" />
-        <Key
-            android:keyLabel="к"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="4" />
-        <Key
-            android:keyLabel="е"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_cyrillic_e" />
-        <Key
-            android:keyLabel="н"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="6" />
-        <Key
-            android:keyLabel="г"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="7" />
-        <Key
-            android:keyLabel="ш"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="8" />
-        <Key
-            android:keyLabel="щ"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="9" />
-        <Key
-            android:keyLabel="з"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="0" />
-        <Key
-            android:keyLabel="х"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="ф"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="ы" />
-        <Key
-            android:keyLabel="в" />
-        <Key
-            android:keyLabel="а" />
-        <Key
-            android:keyLabel="п" />
-        <Key
-            android:keyLabel="р" />
-        <Key
-            android:keyLabel="о" />
-        <Key
-            android:keyLabel="л" />
-        <Key
-            android:keyLabel="д" />
-        <Key
-            android:keyLabel="ж" />
-        <Key
-            android:keyLabel="э"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyWidth="8.5%p"
-    >
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_bkeyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="11.75%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="я" />
-        <Key
-            android:keyLabel="ч" />
-        <Key
-            android:keyLabel="с" />
-        <Key
-            android:keyLabel="м" />
-        <Key
-            android:keyLabel="и" />
-        <Key
-            android:keyLabel="т" />
-        <Key
-            android:keyLabel="ь"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_cyrillic_soft_sign" />
-        <Key
-            android:keyLabel="б" />
-        <Key
-            android:keyLabel="ю" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="11.75%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml-sr-xlarge/kbd_qwerty.xml b/java/res/xml-sr-xlarge/kbd_qwerty.xml
new file mode 100644
index 0000000..297d726
--- /dev/null
+++ b/java/res/xml-sr-xlarge/kbd_qwerty.xml
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<!-- Serbian keyboard layout, based on the X11 layout for Serbian -->
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="9.09%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <!-- This row is intentionally not marked as a top row -->
+    <Row
+        latin:keyWidth="7.520%p"
+    >
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="љ"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="1" />
+        <Key
+            latin:keyLabel="њ"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="2" />
+        <Key
+            latin:keyLabel="е"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="3" />
+        <Key
+            latin:keyLabel="р"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="4" />
+        <Key
+            latin:keyLabel="т"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="5" />
+        <Key
+            latin:keyLabel="з"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="6" />
+        <Key
+            latin:keyLabel="у"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="7" />
+        <Key
+            latin:keyLabel="и"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="8" />
+        <Key
+            latin:keyLabel="о"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="9" />
+        <Key
+            latin:keyLabel="п"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="0" />
+        <Key
+            latin:keyLabel="ш" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="7.520%p"
+    >
+        <Key
+            latin:keyStyle="toSymbolKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="а" />
+        <Key
+            latin:keyLabel="с" />
+        <Key
+            latin:keyLabel="д" />
+        <Key
+            latin:keyLabel="ф" />
+        <Key
+            latin:keyLabel="г" />
+        <Key
+            latin:keyLabel="х" />
+        <Key
+            latin:keyLabel="ј" />
+        <Key
+            latin:keyLabel="к" />
+        <Key
+            latin:keyLabel="л" />
+        <Key
+            latin:keyLabel="ч" />
+        <Key
+            latin:keyLabel="ћ" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="7.520%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="12.400%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="ђ" />
+        <Key
+            latin:keyLabel="ж" />
+        <Key
+            latin:keyLabel="џ" />
+        <Key
+            latin:keyLabel="ц" />
+        <Key
+            latin:keyLabel="в" />
+        <Key
+            latin:keyLabel="б" />
+        <Key
+            latin:keyLabel="н" />
+        <Key
+            latin:keyLabel="м" />
+        <Key
+            latin:keyLabel=","
+            latin:manualTemporaryUpperCaseCode="33"
+            latin:keyHintIcon="@drawable/key_hint_exclamation_holo"
+            latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_exclamation_large_holo"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="!" />
+        <Key
+            latin:keyLabel="."
+            latin:manualTemporaryUpperCaseCode="63"
+            latin:keyHintIcon="@drawable/key_hint_question_holo"
+            latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_question_large_holo"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="\?" />
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="12.400%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</Keyboard>
diff --git a/java/res/xml-sr/kbd_qwerty.xml b/java/res/xml-sr/kbd_qwerty.xml
index 464c74f..279b040 100644
--- a/java/res/xml-sr/kbd_qwerty.xml
+++ b/java/res/xml-sr/kbd_qwerty.xml
@@ -20,488 +20,128 @@
 
 <!-- Serbian keyboard layout, based on the X11 layout for Serbian -->
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="9.09%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="9.09%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
     <Row
-        android:rowEdgeFlags="top"
+        latin:rowEdgeFlags="top"
     >
         <Key
-            android:keyLabel="љ"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="1"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="љ"
+            latin:keyHintIcon="@drawable/keyboard_hint_1"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="1"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="њ"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="2" />
+            latin:keyLabel="њ"
+            latin:keyHintIcon="@drawable/keyboard_hint_2"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="2" />
         <Key
-            android:keyLabel="е"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="3" />
+            latin:keyLabel="е"
+            latin:keyHintIcon="@drawable/keyboard_hint_3"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="3" />
         <Key
-            android:keyLabel="р"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="4" />
+            latin:keyLabel="р"
+            latin:keyHintIcon="@drawable/keyboard_hint_4"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="4" />
         <Key
-            android:keyLabel="т"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="5" />
+            latin:keyLabel="т"
+            latin:keyHintIcon="@drawable/keyboard_hint_5"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="5" />
         <Key
-            android:keyLabel="з"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="6" />
+            latin:keyLabel="з"
+            latin:keyHintIcon="@drawable/keyboard_hint_6"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="6" />
         <Key
-            android:keyLabel="у"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="7" />
+            latin:keyLabel="у"
+            latin:keyHintIcon="@drawable/keyboard_hint_7"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="7" />
         <Key
-            android:keyLabel="и"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="8" />
+            latin:keyLabel="и"
+            latin:keyHintIcon="@drawable/keyboard_hint_8"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="8" />
         <Key
-            android:keyLabel="о"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="9" />
+            latin:keyLabel="о"
+            latin:keyHintIcon="@drawable/keyboard_hint_9"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="9" />
         <Key
-            android:keyLabel="п"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="0" />
+            latin:keyLabel="п"
+            latin:keyHintIcon="@drawable/keyboard_hint_0"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="0" />
         <Key
-            android:keyLabel="ш"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="а"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="с" />
-        <Key
-            android:keyLabel="д" />
-        <Key
-            android:keyLabel="ф" />
-        <Key
-            android:keyLabel="г" />
-        <Key
-            android:keyLabel="х" />
-        <Key
-            android:keyLabel="ј" />
-        <Key
-            android:keyLabel="к" />
-        <Key
-            android:keyLabel="л" />
-        <Key
-            android:keyLabel="ч" />
-        <Key
-            android:keyLabel="ћ" />
-        <Key
-            android:keyLabel="ђ"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="ш"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row
-        android:keyWidth="8.5%p"
+        latin:keyWidth="8.333%p"
     >
         <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_keyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="11.75%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="а"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="ж" />
+            latin:keyLabel="с" />
         <Key
-            android:keyLabel="џ" />
+            latin:keyLabel="д" />
         <Key
-            android:keyLabel="ц" />
+            latin:keyLabel="ф" />
         <Key
-            android:keyLabel="в" />
+            latin:keyLabel="г" />
         <Key
-            android:keyLabel="б" />
+            latin:keyLabel="х" />
         <Key
-            android:keyLabel="н" />
+            latin:keyLabel="ј" />
         <Key
-            android:keyLabel="м" />
+            latin:keyLabel="к" />
         <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="11.75%p"
-            android:isModifier="true"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="л" />
+        <Key
+            latin:keyLabel="ч" />
+        <Key
+            latin:keyLabel="ћ" />
+        <Key
+            latin:keyLabel="ђ"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
+        latin:keyWidth="8.5%p"
     >
         <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="11.75%p"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
+            latin:keyLabel="ж" />
         <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
+            latin:keyLabel="џ" />
         <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
+            latin:keyLabel="ц" />
         <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="в" />
+        <Key
+            latin:keyLabel="б" />
+        <Key
+            latin:keyLabel="н" />
+        <Key
+            latin:keyLabel="м" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="11.75%p"
+            latin:keyEdgeFlags="right" />
     </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row4" />
 </Keyboard>
diff --git a/java/res/xml-sr/kbd_qwerty_black.xml b/java/res/xml-sr/kbd_qwerty_black.xml
deleted file mode 100644
index 2ffa240..0000000
--- a/java/res/xml-sr/kbd_qwerty_black.xml
+++ /dev/null
@@ -1,449 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<!-- Serbian keyboard layout, based on the X11 layout for Serbian -->
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="9.09%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="љ"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="1"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="њ"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="2" />
-        <Key
-            android:keyLabel="е"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="3" />
-        <Key
-            android:keyLabel="р"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="4" />
-        <Key
-            android:keyLabel="т"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="5" />
-        <Key
-            android:keyLabel="з"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="6" />
-        <Key
-            android:keyLabel="у"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="7" />
-        <Key
-            android:keyLabel="и"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="8" />
-        <Key
-            android:keyLabel="о"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="9" />
-        <Key
-            android:keyLabel="п"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="0" />
-        <Key
-            android:keyLabel="ш"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="а"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="с" />
-        <Key
-            android:keyLabel="д" />
-        <Key
-            android:keyLabel="ф" />
-        <Key
-            android:keyLabel="г" />
-        <Key
-            android:keyLabel="х" />
-        <Key
-            android:keyLabel="ј" />
-        <Key
-            android:keyLabel="к" />
-        <Key
-            android:keyLabel="л" />
-        <Key
-            android:keyLabel="ч" />
-        <Key
-            android:keyLabel="ћ" />
-        <Key
-            android:keyLabel="ђ"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyWidth="8.5%p"
-    >
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_bkeyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="11.75%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="ж" />
-        <Key
-            android:keyLabel="џ" />
-        <Key
-            android:keyLabel="ц" />
-        <Key
-            android:keyLabel="в" />
-        <Key
-            android:keyLabel="б" />
-        <Key
-            android:keyLabel="н" />
-        <Key
-            android:keyLabel="м" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="11.75%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml-sv-xlarge/kbd_qwerty.xml b/java/res/xml-sv-xlarge/kbd_qwerty.xml
new file mode 100644
index 0000000..80d9453
--- /dev/null
+++ b/java/res/xml-sv-xlarge/kbd_qwerty.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<!--
+    Swedish Keyboard Layout
+
+    Key positioning: Svensk standard SS 66 22 41
+    Foreign letters: Svenska skrivregler (2:a uppl.) §302
+    Local additions: ۧ
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_rows_scandinavia" />
+</Keyboard>
diff --git a/java/res/xml-sv/kbd_qwerty.xml b/java/res/xml-sv/kbd_qwerty.xml
index 0fc80a3..464a463 100644
--- a/java/res/xml-sv/kbd_qwerty.xml
+++ b/java/res/xml-sv/kbd_qwerty.xml
@@ -27,511 +27,12 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="9.09%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="9.09%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="q"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_q"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="w"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_w" />
-        <Key
-            android:keyLabel="e"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_e" />
-        <Key
-            android:keyLabel="r"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_r" />
-        <Key
-            android:keyLabel="t"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_t" />
-        <Key
-            android:keyLabel="y"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_y" />
-        <Key
-            android:keyLabel="u"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_u" />
-        <Key
-            android:keyLabel="i"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_i" />
-        <Key
-            android:keyLabel="o"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_o" />
-        <Key
-            android:keyLabel="p"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_p" />
-        <Key
-            android:keyLabel="å"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="a"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="s"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_s" />
-        <Key
-            android:keyLabel="d"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_d" />
-        <Key
-            android:keyLabel="f" />
-        <Key
-            android:keyLabel="g"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_g" />
-        <Key
-            android:keyLabel="h" />
-        <Key
-            android:keyLabel="j" />
-        <Key
-            android:keyLabel="k" />
-        <Key
-            android:keyLabel="l"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_l" />
-        <Key
-            android:keyLabel="ö"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_o_umlaut" />
-        <Key
-            android:keyLabel="ä"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a_umlaut"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyWidth="10%p"
-    >
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_keyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="z"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_z" />
-        <Key
-            android:keyLabel="x" />
-        <Key
-            android:keyLabel="c"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_c" />
-        <Key
-            android:keyLabel="v"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_v" />
-        <Key
-            android:keyLabel="b" />
-        <Key
-            android:keyLabel="n"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_n" />
-        <Key
-            android:keyLabel="m" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_rows_scandinavia" />
 </Keyboard>
diff --git a/java/res/xml-sv/kbd_qwerty_black.xml b/java/res/xml-sv/kbd_qwerty_black.xml
deleted file mode 100644
index d03fb77..0000000
--- a/java/res/xml-sv/kbd_qwerty_black.xml
+++ /dev/null
@@ -1,480 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<!--
-    Swedish Keyboard Layout
-
-    Key positioning: Svensk standard SS 66 22 41
-    Foreign letters: Svenska skrivregler (2:a uppl.) §302
-    Local additions: ۧ
--->
-
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="9.09%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="q"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_q"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="w"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_w" />
-        <Key
-            android:keyLabel="e"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_e" />
-        <Key
-            android:keyLabel="r"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_r" />
-        <Key
-            android:keyLabel="t"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_t" />
-        <Key
-            android:keyLabel="y"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_y" />
-        <Key
-            android:keyLabel="u"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_u" />
-        <Key
-            android:keyLabel="i"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_i" />
-        <Key
-            android:keyLabel="o"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_o" />
-        <Key
-            android:keyLabel="p"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_p" />
-        <Key
-            android:keyLabel="å"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="a"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="s"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_s" />
-        <Key
-            android:keyLabel="d"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_d" />
-        <Key
-            android:keyLabel="f" />
-        <Key
-            android:keyLabel="g"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_g" />
-        <Key
-            android:keyLabel="h" />
-        <Key
-            android:keyLabel="j" />
-        <Key
-            android:keyLabel="k" />
-        <Key
-            android:keyLabel="l"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_l" />
-        <Key
-            android:keyLabel="ö"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_o_umlaut" />
-        <Key
-            android:keyLabel="ä"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a_umlaut"
-            android:keyWidth="8.75%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyWidth="10%p"
-    >
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_bkeyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="z"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_z" />
-        <Key
-            android:keyLabel="x" />
-        <Key
-            android:keyLabel="c"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_c" />
-        <Key
-            android:keyLabel="v"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_v" />
-        <Key
-            android:keyLabel="b" />
-        <Key
-            android:keyLabel="n"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_n" />
-        <Key
-            android:keyLabel="m" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:keyWidth="10%p"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml-xlarge-land/kbd_popup_template.xml b/java/res/xml-xlarge-land/kbd_popup_template.xml
new file mode 100644
index 0000000..fd348f2
--- /dev/null
+++ b/java/res/xml-xlarge-land/kbd_popup_template.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="3.5%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
+    >
+</Keyboard>
diff --git a/java/res/xml-xlarge-land/popup_domains.xml b/java/res/xml-xlarge-land/popup_domains.xml
new file mode 100644
index 0000000..deedba4
--- /dev/null
+++ b/java/res/xml-xlarge-land/popup_domains.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="4.0%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
+>
+    <Row
+        latin:rowEdgeFlags="top|bottom"
+    >
+        <Key
+            latin:keyLabel="@string/popular_domain_1"
+            latin:keyOutputText="@string/popular_domain_1"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="@string/popular_domain_2"
+            latin:keyOutputText="@string/popular_domain_2" />
+        <Key
+            latin:keyLabel="@string/popular_domain_3"
+            latin:keyOutputText="@string/popular_domain_3" />
+        <Key
+            latin:keyLabel="@string/popular_domain_4"
+            latin:keyOutputText="@string/popular_domain_4"
+            latin:keyEdgeFlags="right" />
+    </Row>
+</Keyboard>
diff --git a/java/res/xml-xlarge-land/popup_smileys.xml b/java/res/xml-xlarge-land/popup_smileys.xml
new file mode 100644
index 0000000..e882a50
--- /dev/null
+++ b/java/res/xml-xlarge-land/popup_smileys.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="4.0%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
+>
+    <Row
+        latin:rowEdgeFlags="top"
+    >
+        <Key
+            latin:keyLabel=":-)"
+            latin:keyOutputText=":-) "
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel=":-("
+            latin:keyOutputText=":-( " />
+        <Key
+            latin:keyLabel=";-)"
+            latin:keyOutputText=";-) " />
+        <Key
+            latin:keyLabel=":-P"
+            latin:keyOutputText=":-P " />
+        <Key
+            latin:keyLabel="=-O"
+            latin:keyOutputText="=-O "
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyLabel=":-*"
+            latin:keyOutputText=":-* "
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel=":O"
+            latin:keyOutputText=":O " />
+        <Key
+            latin:keyLabel="B-)"
+            latin:keyOutputText="B-) " />
+        <Key
+            latin:keyLabel=":-$"
+            latin:keyOutputText=":-$ " />
+        <Key
+            latin:keyLabel=":-!"
+            latin:keyOutputText=":-! "
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:rowEdgeFlags="bottom"
+    >
+        <Key
+            latin:keyLabel=":-["
+            latin:keyOutputText=":-[ "
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="O:-)"
+            latin:keyOutputText="O:-) " />
+        <Key
+            latin:keyLabel=":-\\"
+            latin:keyOutputText=":-\\ " />
+        <Key
+            latin:keyLabel=":'("
+            latin:keyOutputText=":'( " />
+        <Key
+            latin:keyLabel=":-D"
+            latin:keyOutputText=":-D "
+            latin:keyEdgeFlags="right" />
+    </Row>
+</Keyboard>
diff --git a/java/res/xml-xlarge/kbd_azerty_rows.xml b/java/res/xml-xlarge/kbd_azerty_rows.xml
new file mode 100644
index 0000000..b68e214
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_azerty_rows.xml
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <Row
+        latin:keyWidth="8.272%p"
+    >
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="a"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_a" />
+        <Key
+            latin:keyLabel="z"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_z" />
+        <Key
+            latin:keyLabel="e"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_e" />
+        <Key
+            latin:keyLabel="r"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_r" />
+        <Key
+            latin:keyLabel="t"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_t" />
+        <Key
+            latin:keyLabel="y"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_y" />
+        <Key
+            latin:keyLabel="u"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_u" />
+        <Key
+            latin:keyLabel="i"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_i" />
+        <Key
+            latin:keyLabel="o"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_o" />
+        <Key
+            latin:keyLabel="p"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_p" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="8.157%p"
+    >
+        <Key
+            latin:keyStyle="toSymbolKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="10.167%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="q"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_q" />
+        <Key
+            latin:keyLabel="s"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_s" />
+        <Key
+            latin:keyLabel="d"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_d" />
+        <Key
+            latin:keyLabel="f" />
+        <Key
+            latin:keyLabel="g"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_g" />
+        <Key
+            latin:keyLabel="h" />
+        <Key
+            latin:keyLabel="j" />
+        <Key
+            latin:keyLabel="k" />
+        <Key
+            latin:keyLabel="l"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_l" />
+        <Key
+            latin:keyLabel="m"
+            latin:keyEdgeFlags="right" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="8.593%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="8.042%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="15.192%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="w"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_w" />
+        <Key
+            latin:keyLabel="x" />
+        <Key
+            latin:keyLabel="c"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_c" />
+        <Key
+            latin:keyLabel="v"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_v" />
+        <Key
+            latin:keyLabel="b" />
+        <Key
+            latin:keyLabel="n"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_n" />
+        <Key
+            latin:keyLabel="\'"
+            latin:manualTemporaryUpperCaseCode="58"
+            latin:keyHintIcon="@drawable/key_hint_colon_holo"
+            latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_colon_large_holo"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters=":" />
+        <switch>
+            <case
+                latin:mode="email"
+            >
+                <Key
+                    latin:keyLabel="," />
+                <Key
+                    latin:keyLabel="." />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel=","
+                    latin:manualTemporaryUpperCaseCode="33"
+                    latin:keyHintIcon="@drawable/key_hint_exclamation_holo"
+                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_exclamation_large_holo"
+                    latin:popupKeyboard="@xml/kbd_popup_template"
+                    latin:popupCharacters="!" />
+                <Key
+                    latin:keyLabel="."
+                    latin:manualTemporaryUpperCaseCode="63"
+                    latin:keyHintIcon="@drawable/key_hint_question_holo"
+                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_question_large_holo"
+                    latin:popupKeyboard="@xml/kbd_popup_template"
+                    latin:popupCharacters="\?" />
+            </default>
+        </switch>
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="12.530%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</merge>
diff --git a/java/res/xml-xlarge/kbd_key_styles.xml b/java/res/xml-xlarge/kbd_key_styles.xml
new file mode 100644
index 0000000..60455a6
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_key_styles.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <!-- Functional key styles -->
+    <switch>
+        <case
+            latin:colorScheme="white"
+        >
+            <key-style
+                latin:styleName="functionalKeyStyle"
+                latin:isModifier="true" />
+            <key-style
+                latin:styleName="shiftKeyStyle"
+                latin:codes="@integer/key_shift"
+                latin:keyIcon="@drawable/sym_keyboard_shift_holo"
+                latin:shiftedIcon="@drawable/sym_keyboard_shift_locked_holo"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_shift"
+                latin:parentStyle="functionalKeyStyle"
+                latin:isSticky="true" />
+            <key-style
+                latin:styleName="deleteKeyStyle"
+                latin:codes="@integer/key_delete"
+                latin:keyIcon="@drawable/sym_keyboard_delete_holo"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_delete"
+                latin:parentStyle="functionalKeyStyle"
+                latin:isRepeatable="true" />
+            <key-style
+                latin:styleName="returnKeyStyle"
+                latin:codes="@integer/key_return"
+                latin:keyIcon="@drawable/sym_keyboard_return_holo"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_return"
+                latin:parentStyle="functionalKeyStyle" />
+            1
+            <key-style
+                latin:styleName="spaceKeyStyle"
+                latin:codes="@integer/key_space"
+                latin:keyIcon="@drawable/sym_keyboard_space_holo"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_space"
+                latin:parentStyle="functionalKeyStyle" />
+            <key-style
+                latin:styleName="nonSpecialBackgroundSpaceKeyStyle"
+                latin:codes="@integer/key_space"
+                latin:keyIcon="@drawable/sym_keyboard_space_holo"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
+            <key-style
+                latin:styleName="smileyKeyStyle"
+                latin:codes="0"
+                latin:keyIcon="@drawable/sym_keyboard_smiley_holo"
+                latin:keyOutputText=";-) "
+                latin:keyHintIcon="@drawable/hint_popup_holo"
+                latin:popupKeyboard="@xml/popup_smileys" />
+        </case>
+        <case
+            latin:colorScheme="black"
+        >
+            <key-style
+                latin:styleName="functionalKeyStyle" />
+            <key-style
+                latin:styleName="shiftKeyStyle"
+                latin:codes="@integer/key_shift"
+                latin:keyIcon="@drawable/sym_bkeyboard_shift"
+                latin:shiftedIcon="@drawable/sym_bkeyboard_shift_locked"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_shift"
+                latin:parentStyle="functionalKeyStyle"
+                latin:isSticky="true" />
+            <key-style
+                latin:styleName="deleteKeyStyle"
+                latin:codes="@integer/key_delete"
+                latin:keyIcon="@drawable/sym_bkeyboard_delete"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_delete"
+                latin:parentStyle="functionalKeyStyle"
+                latin:isRepeatable="true" />
+            <key-style
+                latin:styleName="returnKeyStyle"
+                latin:codes="@integer/key_return"
+                latin:keyIcon="@drawable/sym_bkeyboard_return"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_return"
+                latin:parentStyle="functionalKeyStyle" />
+            <key-style
+                latin:styleName="spaceKeyStyle"
+                latin:codes="@integer/key_space"
+                latin:keyIcon="@drawable/sym_bkeyboard_space"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_space"
+                latin:parentStyle="functionalKeyStyle" />
+            <key-style
+                latin:styleName="nonSpecialBackgroundSpaceKeyStyle"
+                latin:codes="@integer/key_space"
+                latin:keyIcon="@drawable/sym_bkeyboard_space"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
+            <key-style
+                latin:styleName="smileyKeyStyle"
+                latin:keyLabel=";-)"
+                latin:keyOutputText=";-) "
+                latin:keyHintIcon="@drawable/hint_popup_holo"
+                latin:popupKeyboard="@xml/popup_smileys" />
+        </case>
+    </switch>
+    <key-style
+        latin:styleName="tabKeyStyle"
+        latin:codes="@integer/key_tab"
+        latin:keyLabel="@string/label_tab_key"
+        latin:keyLabelOption="fontNormal"
+        latin:parentStyle="functionalKeyStyle" />
+    <key-style
+        latin:styleName="toSymbolKeyStyle"
+        latin:codes="@integer/key_switch_alpha_symbol"
+        latin:keyLabel="@string/label_to_symbol_key"
+        latin:keyLabelOption="fontNormal"
+        latin:parentStyle="functionalKeyStyle" />
+    <key-style
+        latin:styleName="toAlphaKeyStyle"
+        latin:codes="@integer/key_switch_alpha_symbol"
+        latin:keyLabel="@string/label_to_alpha_key"
+        latin:keyLabelOption="fontNormal"
+        latin:parentStyle="functionalKeyStyle" />
+    <key-style
+        latin:styleName="moreKeyStyle"
+        latin:codes="@integer/key_shift"
+        latin:keyLabel="@string/label_more_key"
+        latin:keyLabelOption="fontNormal"
+        latin:parentStyle="functionalKeyStyle"
+        latin:isSticky="true" />
+    <key-style
+        latin:styleName="comKeyStyle"
+        latin:keyLabel=".com"
+        latin:keyLabelOption="fontNormal"
+        latin:keyOutputText=".com"
+        latin:keyHintIcon="@drawable/hint_popup_holo"
+        latin:popupKeyboard="@xml/popup_domains" />
+</merge>
diff --git a/java/res/xml-xlarge/kbd_number.xml b/java/res/xml-xlarge/kbd_number.xml
new file mode 100644
index 0000000..f5f4fbc
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_number.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="11.949%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <!-- This row is intentionally not marked as a top row -->
+    <Row>
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyEdgeFlags="left" />
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:keyLabel="-"
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:keyLabel="+"
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:keyLabel="."
+            latin:keyWidth="8.042%p" />
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:keyLabel="1" />
+        <Key
+            latin:keyLabel="2" />
+        <Key
+            latin:keyLabel="3" />
+        <Spacer
+            latin:horizontalGap="9.360%p" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.804%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row>
+        <Spacer
+            latin:horizontalGap="16.406%p" />
+        <Key
+            latin:keyLabel="*"
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:keyLabel="/"
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:keyLabel=","
+            latin:keyWidth="8.042%p" />
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:keyLabel="4" />
+        <Key
+            latin:keyLabel="5" />
+        <Key
+            latin:keyLabel="6" />
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="14.706%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row>
+        <!-- There is an empty area bellow the "More" key and left of the "(" key.  To ignore
+             the touch event on the area, "(" is intentionally not marked as a left edge key. -->
+        <Spacer
+            latin:horizontalGap="16.406%p" />
+        <Key
+            latin:keyLabel="("
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:keyLabel=")"
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:keyLabel="="
+            latin:keyWidth="8.042%p" />
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:keyLabel="7" />
+        <Key
+            latin:keyLabel="8" />
+        <Key
+            latin:keyLabel="9" />
+        <!-- There is an empty area bellow the "Enter" key and right of the "9" key.  To ignore
+             the touch event on the area, "9" is intentionally not marked as a right edge key. -->
+    </Row>
+    <!-- This row is intentionally not marked as a bottom row -->
+    <Row>
+        <!-- There is an empty area bellow the "More" key and left of the "space" key.  To ignore
+             the touch event on the area, "space" is intentionally not marked as a left edge key. -->
+        <Spacer
+            latin:horizontalGap="16.406%p" />
+        <Key
+            latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
+            latin:keyWidth="24.127%p" />
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:keyLabel="*" />
+        <Key
+            latin:keyLabel="0" />
+        <Key
+            latin:keyLabel="#" />
+        <!-- There is an empty area bellow the "Enter" key and right of the "#" key.  To ignore
+             the touch event on the area, "#" is intentionally not marked as a right edge key. -->
+    </Row>
+</Keyboard>
diff --git a/java/res/xml-xlarge/kbd_numkey_styles.xml b/java/res/xml-xlarge/kbd_numkey_styles.xml
new file mode 100644
index 0000000..adf45a8
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_numkey_styles.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <switch>
+        <case
+            latin:colorScheme="white"
+        >
+            <key-style
+                latin:styleName="num0KeyStyle"
+                latin:codes="48"
+                latin:keyIcon="@drawable/sym_keyboard_num0_holo" />
+            <key-style
+                latin:styleName="num1KeyStyle"
+                latin:codes="49"
+                latin:keyIcon="@drawable/sym_keyboard_num1_holo" />
+            <key-style
+                latin:styleName="num2KeyStyle"
+                latin:codes="50"
+                latin:keyIcon="@drawable/sym_keyboard_num2_holo" />
+            <key-style
+                latin:styleName="num3KeyStyle"
+                latin:codes="51"
+                latin:keyIcon="@drawable/sym_keyboard_num3_holo" />
+            <key-style
+                latin:styleName="num4KeyStyle"
+                latin:codes="52"
+                latin:keyIcon="@drawable/sym_keyboard_num4_holo" />
+            <key-style
+                latin:styleName="num5KeyStyle"
+                latin:codes="53"
+                latin:keyIcon="@drawable/sym_keyboard_num5_holo" />
+            <key-style
+                latin:styleName="num6KeyStyle"
+                latin:codes="54"
+                latin:keyIcon="@drawable/sym_keyboard_num6_holo" />
+            <key-style
+                latin:styleName="num7KeyStyle"
+                latin:codes="55"
+                latin:keyIcon="@drawable/sym_keyboard_num7_holo" />
+            <key-style
+                latin:styleName="num8KeyStyle"
+                latin:codes="56"
+                latin:keyIcon="@drawable/sym_keyboard_num8_holo" />
+            <key-style
+                latin:styleName="num9KeyStyle"
+                latin:codes="57"
+                latin:keyIcon="@drawable/sym_keyboard_num9_holo" />
+            <key-style
+                latin:styleName="numStarKeyStyle"
+                latin:codes="42"
+                latin:keyIcon="@drawable/sym_keyboard_numbstar_holo" />
+            <key-style
+                latin:styleName="numPoundKeyStyle"
+                latin:codes="35"
+                latin:keyIcon="@drawable/sym_keyboard_numbpound_holo" />
+            <key-style
+                latin:styleName="numAltKeyStyle"
+                latin:codes="@integer/key_switch_alpha_symbol"
+                latin:keyIcon="@drawable/sym_keyboard_numalt"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_numalt" />
+            <key-style
+                latin:styleName="numSpaceKeyStyle"
+                latin:codes="@integer/key_space"
+                latin:keyIcon="@drawable/sym_keyboard_space_holo"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
+        </case>
+        <case
+            latin:colorScheme="black"
+        >
+            <key-style
+                latin:styleName="num0KeyStyle"
+                latin:codes="48"
+                latin:keyIcon="@drawable/sym_bkeyboard_num0" />
+            <key-style
+                latin:styleName="num1KeyStyle"
+                latin:codes="49"
+                latin:keyIcon="@drawable/sym_bkeyboard_num1" />
+            <key-style
+                latin:styleName="num2KeyStyle"
+                latin:codes="50"
+                latin:keyIcon="@drawable/sym_bkeyboard_num2" />
+            <key-style
+                latin:styleName="num3KeyStyle"
+                latin:codes="51"
+                latin:keyIcon="@drawable/sym_bkeyboard_num3" />
+            <key-style
+                latin:styleName="num4KeyStyle"
+                latin:codes="52"
+                latin:keyIcon="@drawable/sym_bkeyboard_num4" />
+            <key-style
+                latin:styleName="num5KeyStyle"
+                latin:codes="53"
+                latin:keyIcon="@drawable/sym_bkeyboard_num5" />
+            <key-style
+                latin:styleName="num6KeyStyle"
+                latin:codes="54"
+                latin:keyIcon="@drawable/sym_bkeyboard_num6" />
+            <key-style
+                latin:styleName="num7KeyStyle"
+                latin:codes="55"
+                latin:keyIcon="@drawable/sym_bkeyboard_num7" />
+            <key-style
+                latin:styleName="num8KeyStyle"
+                latin:codes="56"
+                latin:keyIcon="@drawable/sym_bkeyboard_num8" />
+            <key-style
+                latin:styleName="num9KeyStyle"
+                latin:codes="57"
+                latin:keyIcon="@drawable/sym_bkeyboard_num9" />
+            <key-style
+                latin:styleName="numStarKeyStyle"
+                latin:codes="42"
+                latin:keyIcon="@drawable/sym_bkeyboard_numstar" />
+            <key-style
+                latin:styleName="numPoundKeyStyle"
+                latin:codes="35"
+                latin:keyIcon="@drawable/sym_bkeyboard_numpound" />
+            <key-style
+                latin:styleName="numAltKeyStyle"
+                latin:codes="@integer/key_switch_alpha_symbol"
+                latin:keyIcon="@drawable/sym_bkeyboard_numalt"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_numalt" />
+            <key-style
+                latin:styleName="numSpaceKeyStyle"
+                latin:codes="@integer/key_space"
+                latin:keyIcon="@drawable/sym_bkeyboard_space"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
+        </case>
+    </switch>
+</merge>
diff --git a/java/res/xml-xlarge/kbd_phone.xml b/java/res/xml-xlarge/kbd_phone.xml
new file mode 100644
index 0000000..1e66102
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_phone.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="11.949%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <include
+        latin:keyboardLayout="@xml/kbd_numkey_styles" />
+    <!-- This row is intentionally not marked as a top row -->
+    <Row>
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyEdgeFlags="left" />
+        <!-- To match one character label size with "Tab", I placed spaces around the char '-'
+             and '+'. -->
+        <Spacer
+            latin:horizontalGap="8.470%p" />
+        <Key
+            latin:codes="45"
+            latin:keyLabel=" - "
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:codes="43"
+            latin:keyLabel=" + "
+            latin:keyWidth="8.042%p" />
+        <Spacer
+            latin:horizontalGap="8.479%p" />
+        <Key
+            latin:keyStyle="num1KeyStyle" />
+        <Key
+            latin:keyStyle="num2KeyStyle" />
+        <Key
+            latin:keyStyle="num3KeyStyle" />
+        <Spacer
+            latin:horizontalGap="9.360%p" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.804%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyStyle="moreKeyStyle"
+            latin:keyEdgeFlags="left" />
+        <!-- To match one character label size with "More", I placed spaces around the char ','
+             and '.'. -->
+        <Spacer
+            latin:horizontalGap="8.470%p" />
+        <Key
+            latin:codes="44"
+            latin:keyLabel=" , "
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:codes="46"
+            latin:keyLabel=" . "
+            latin:keyWidth="8.042%p" />
+        <Spacer
+            latin:horizontalGap="8.479%p" />
+        <Key
+            latin:keyStyle="num4KeyStyle" />
+        <Key
+            latin:keyStyle="num5KeyStyle" />
+        <Key
+            latin:keyStyle="num6KeyStyle" />
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="14.706%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row>
+        <!-- To match one character label size with "More", I placed spaces around the char '('
+             and ')'. -->
+        <!-- There is an empty area bellow the "More" key and left of the "(" key.  To ignore
+             the touch event on the area, "(" is intentionally not marked as a left edge key. -->
+        <Spacer
+            latin:horizontalGap="20.427%p" />
+        <Key
+            latin:codes="40"
+            latin:keyLabel=" ( "
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:codes="41"
+            latin:keyLabel=" ) "
+            latin:keyWidth="8.042%p" />
+        <Spacer
+            latin:horizontalGap="8.479%p" />
+        <Key
+            latin:keyStyle="num7KeyStyle" />
+        <Key
+            latin:keyStyle="num8KeyStyle" />
+        <Key
+            latin:keyStyle="num9KeyStyle" />
+        <!-- There is an empty area bellow the "Enter" key and right of the "9" key.  To ignore
+             the touch event on the area, "9" is intentionally not marked as a right edge key. -->
+        </Row>
+    <!-- This row is intentionally not marked as a bottom row -->
+    <Row>
+        <!-- There is an empty area bellow the "More" key and left of the "space" key.  To ignore
+             the touch event on the area, "space" is intentionally not marked as a left edge key. -->
+        <Spacer
+            latin:horizontalGap="20.427%p" />
+        <Key
+            latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
+            latin:keyWidth="16.085%p" />
+        <Spacer
+            latin:horizontalGap="8.479%p" />
+        <Key
+            latin:keyStyle="numStarKeyStyle" />
+        <Key
+            latin:keyStyle="num0KeyStyle" />
+        <Key
+            latin:keyStyle="numPoundKeyStyle" />
+        <!-- There is an empty area bellow the "Enter" key and right of the "#" key.  To ignore
+             the touch event on the area, "#" is intentionally not marked as a right edge key. -->
+    </Row>
+</Keyboard>
diff --git a/java/res/xml-xlarge/kbd_phone_symbols.xml b/java/res/xml-xlarge/kbd_phone_symbols.xml
new file mode 100644
index 0000000..7eadb96
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_phone_symbols.xml
@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="11.949%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <include
+        latin:keyboardLayout="@xml/kbd_numkey_styles" />
+    <!-- This row is intentionally not marked as a top row -->
+    <Row>
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyEdgeFlags="left" />
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:codes="45"
+            latin:keyLabel=" - "
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:codes="43"
+            latin:keyLabel=" + "
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:codes="44"
+            latin:keyLabel="@string/label_pause_key"
+            latin:keyWidth="8.042%p" />
+        <!-- To match one character label size with "Tab" and "Pause, I placed spaces around the
+             char '-' and '+'. -->
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:keyStyle="num1KeyStyle" />
+        <Key
+            latin:keyStyle="num2KeyStyle" />
+        <Key
+            latin:keyStyle="num3KeyStyle" />
+        <Spacer
+            latin:horizontalGap="9.360%p" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.804%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyStyle="moreKeyStyle"
+            latin:keyEdgeFlags="left" />
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:codes="44"
+            latin:keyLabel=" , "
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:codes="46"
+            latin:keyLabel=" . "
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:codes="59"
+            latin:keyLabel="@string/label_wait_key"
+            latin:keyWidth="8.042%p" />
+        <!-- To match one character label size with "More" and "Wait", I placed spaces around the
+             char ',' and '.'. -->
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:keyStyle="num4KeyStyle" />
+        <Key
+            latin:keyStyle="num5KeyStyle" />
+        <Key
+            latin:keyStyle="num6KeyStyle" />
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="14.706%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row>
+        <!-- To match one character label size with "More" and etc., I placed spaces around the
+             char 'N', '(' and ')'. -->
+        <!-- There is an empty area bellow the "More" key and left of the "(" key.  To ignore
+             the touch event on the area, "(" is intentionally not marked as a left edge key. -->
+        <Spacer
+            latin:horizontalGap="16.406%p" />
+        <Key
+            latin:codes="40"
+            latin:keyLabel=" ( "
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:codes="41"
+            latin:keyLabel=" ) "
+            latin:keyWidth="8.042%p" />
+        <Key
+            latin:codes="78"
+            latin:keyLabel=" N "
+            latin:keyWidth="8.042%p" />
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:keyStyle="num7KeyStyle" />
+        <Key
+            latin:keyStyle="num8KeyStyle" />
+        <Key
+            latin:keyStyle="num9KeyStyle" />
+        <!-- There is an empty area bellow the "Enter" key and right of the "9" key.  To ignore
+             the touch event on the area, "9" is intentionally not marked as a right edge key. -->
+    </Row>
+    <!-- This row is intentionally not marked as a bottom row -->
+    <Row>
+        <!-- There is an empty area bellow the "More" key and left of the "space" key.  To ignore
+             the touch event on the area, "space" is intentionally not marked as a left edge key. -->
+        <Spacer
+            latin:horizontalGap="16.406%p" />
+        <Key
+            latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
+            latin:keyWidth="24.127%p" />
+        <Spacer
+            latin:horizontalGap="4.458%p" />
+        <Key
+            latin:keyStyle="numStarKeyStyle" />
+        <Key
+            latin:keyStyle="num0KeyStyle" />
+        <Key
+            latin:keyStyle="numPoundKeyStyle" />
+        <!-- There is an empty area bellow the "Enter" key and right of the "#" key.  To ignore
+             the touch event on the area, "#" is intentionally not marked as a right edge key. -->
+    </Row>
+</Keyboard>
diff --git a/java/res/xml-xlarge/kbd_popup_template.xml b/java/res/xml-xlarge/kbd_popup_template.xml
new file mode 100644
index 0000000..aa99cee
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_popup_template.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="5.0%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
+    >
+</Keyboard>
diff --git a/java/res/xml-xlarge/kbd_qwerty.xml b/java/res/xml-xlarge/kbd_qwerty.xml
new file mode 100644
index 0000000..56cfe00
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_qwerty.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_rows" />
+</Keyboard>
diff --git a/java/res/xml-xlarge/kbd_qwerty_row1.xml b/java/res/xml-xlarge/kbd_qwerty_row1.xml
new file mode 100644
index 0000000..1596867
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_qwerty_row1.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <!-- This row is intentionally not marked as a top row -->
+    <Row
+        latin:keyWidth="8.272%p"
+    >
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="q"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_q" />
+        <Key
+            latin:keyLabel="w"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_w" />
+        <Key
+            latin:keyLabel="e"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_e" />
+        <Key
+            latin:keyLabel="r"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_r" />
+        <Key
+            latin:keyLabel="t"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_t" />
+        <Key
+            latin:keyLabel="y"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_y" />
+        <Key
+            latin:keyLabel="u"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_u" />
+        <Key
+            latin:keyLabel="i"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_i" />
+        <Key
+            latin:keyLabel="o"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_o" />
+        <Key
+            latin:keyLabel="p"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_p" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+</merge>
diff --git a/java/res/xml-xlarge/kbd_qwerty_row2.xml b/java/res/xml-xlarge/kbd_qwerty_row2.xml
new file mode 100644
index 0000000..2b9be10
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_qwerty_row2.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <Row
+        latin:keyWidth="8.157%p"
+    >
+        <Key
+            latin:keyStyle="toSymbolKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="11.167%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="a"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_a" />
+        <Key
+            latin:keyLabel="s"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_s" />
+        <Key
+            latin:keyLabel="d"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_d" />
+        <Key
+            latin:keyLabel="f" />
+        <Key
+            latin:keyLabel="g"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_g" />
+        <Key
+            latin:keyLabel="h" />
+        <Key
+            latin:keyLabel="j" />
+        <Key
+            latin:keyLabel="k" />
+        <Key
+            latin:keyLabel="l"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_l" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="15.750%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+</merge>
diff --git a/java/res/xml-xlarge/kbd_qwerty_row3.xml b/java/res/xml-xlarge/kbd_qwerty_row3.xml
new file mode 100644
index 0000000..209ef21
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_qwerty_row3.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <Row
+        latin:keyWidth="8.042%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="15.192%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="z"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_z" />
+        <Key
+            latin:keyLabel="x" />
+        <Key
+            latin:keyLabel="c"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_c" />
+        <Key
+            latin:keyLabel="v"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_v" />
+        <Key
+            latin:keyLabel="b" />
+        <Key
+            latin:keyLabel="n"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_n" />
+        <Key
+            latin:keyLabel="m" />
+        <switch>
+            <case
+                latin:mode="email"
+            >
+                <Key
+                    latin:keyLabel="," />
+                <Key
+                    latin:keyLabel="." />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel=","
+                    latin:manualTemporaryUpperCaseCode="33"
+                    latin:keyHintIcon="@drawable/key_hint_exclamation_holo"
+                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_exclamation_large_holo"
+                    latin:popupKeyboard="@xml/kbd_popup_template"
+                    latin:popupCharacters="!" />
+                <Key
+                    latin:keyLabel="."
+                    latin:manualTemporaryUpperCaseCode="63"
+                    latin:keyHintIcon="@drawable/key_hint_question_holo"
+                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_question_large_holo"
+                    latin:popupKeyboard="@xml/kbd_popup_template"
+                    latin:popupCharacters="\?" />
+            </default>
+        </switch>
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="12.530%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+</merge>
diff --git a/java/res/xml-xlarge/kbd_qwerty_row4.xml b/java/res/xml-xlarge/kbd_qwerty_row4.xml
new file mode 100644
index 0000000..7b9049a
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_qwerty_row4.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <!-- This row is intentionally not marked as a bottom row -->
+    <Row
+        latin:keyWidth="8.042%p"
+    >
+        <Spacer
+            latin:horizontalGap="16.404%p" />
+        <switch>
+            <case
+                latin:mode="email"
+            >
+                <Key
+                    latin:keyStyle="comKeyStyle" />
+                <Key
+                    latin:keyLabel="\@" />
+            </case>
+            <!-- TODO: implement logical OR for <case> attribute -->
+            <case
+                latin:mode="url"
+            >
+                <Key
+                    latin:keyStyle="comKeyStyle"
+                    latin:keyWidth="16.084%p" />
+            </case>
+            <default>
+                <Key
+                    latin:keyStyle="smileyKeyStyle" />
+                <Key
+                    latin:keyLabel="/"
+                    latin:manualTemporaryUpperCaseCode="64"
+                    latin:keyHintIcon="@drawable/key_hint_at_holo"
+                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_at_large_holo"
+                    latin:popupKeyboard="@xml/kbd_popup_template"
+                    latin:popupCharacters="\@" />
+            </default>
+        </switch>
+        <Key
+            latin:keyStyle="spaceKeyStyle"
+            latin:keyWidth="37.454%p" />
+        <switch>
+            <case
+                latin:mode="email"
+            >
+                <Key
+                    latin:keyLabel="-" />
+            </case>
+            <case
+                latin:mode="url"
+            >
+                <Key
+                    latin:keyLabel="/"
+                    latin:manualTemporaryUpperCaseCode="58"
+                    latin:keyHintIcon="@drawable/key_hint_colon_holo"
+                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_colon_large_holo"
+                    latin:popupKeyboard="@xml/kbd_popup_template"
+                    latin:popupCharacters=":" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel="\'"
+                    latin:manualTemporaryUpperCaseCode="34"
+                    latin:keyHintIcon="@drawable/key_hint_quote_holo"
+                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_quote_large_holo"
+                    latin:popupKeyboard="@xml/kbd_popup_template"
+                    latin:popupCharacters="&quot;" />
+            </default>
+        </switch>
+        <switch>
+            <case
+                latin:mode="email"
+            >
+                <Key
+                    latin:keyLabel="_" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel="-"
+                    latin:manualTemporaryUpperCaseCode="95"
+                    latin:keyHintIcon="@drawable/key_hint_underline_holo"
+                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_underline_large_holo"
+                    latin:popupKeyboard="@xml/kbd_popup_template"
+                    latin:popupCharacters="_" />
+            </default>
+        </switch>
+    </Row>
+</merge>
diff --git a/java/res/xml-xlarge/kbd_qwerty_rows.xml b/java/res/xml-xlarge/kbd_qwerty_rows.xml
new file mode 100644
index 0000000..6237712
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_qwerty_rows.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row1" />
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row2" />
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row3" />
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</merge>
diff --git a/java/res/xml-xlarge/kbd_qwerty_rows_scandinavia.xml b/java/res/xml-xlarge/kbd_qwerty_rows_scandinavia.xml
new file mode 100644
index 0000000..c56d4f4
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_qwerty_rows_scandinavia.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <Row
+        latin:keyWidth="7.520%p"
+    >
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="q"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_q" />
+        <Key
+            latin:keyLabel="w"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_w" />
+        <Key
+            latin:keyLabel="e"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_e" />
+        <Key
+            latin:keyLabel="r"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_r" />
+        <Key
+            latin:keyLabel="t"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_t" />
+        <Key
+            latin:keyLabel="y"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_y" />
+        <Key
+            latin:keyLabel="u"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_u" />
+        <Key
+            latin:keyLabel="i"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_i" />
+        <Key
+            latin:keyLabel="o"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_o" />
+        <Key
+            latin:keyLabel="p"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_p" />
+        <Key
+            latin:keyLabel="å" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="7.520%p"
+    >
+        <Key
+            latin:keyStyle="toSymbolKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="a"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_a" />
+        <Key
+            latin:keyLabel="s"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_s" />
+        <Key
+            latin:keyLabel="d"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_d" />
+        <Key
+            latin:keyLabel="f" />
+        <Key
+            latin:keyLabel="g"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_g" />
+        <Key
+            latin:keyLabel="h" />
+        <Key
+            latin:keyLabel="j" />
+        <Key
+            latin:keyLabel="k" />
+        <Key
+            latin:keyLabel="l"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_l" />
+        <Key
+            latin:keyLabel="@string/keylabel_for_scandinavia_row2_10"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_scandinavia_row2_10" />
+        <Key
+            latin:keyLabel="@string/keylabel_for_scandinavia_row2_11"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_scandinavia_row2_11" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row3" />
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</merge>
diff --git a/java/res/xml-xlarge/kbd_qwertz_rows.xml b/java/res/xml-xlarge/kbd_qwertz_rows.xml
new file mode 100644
index 0000000..de15b5f
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_qwertz_rows.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <Row
+        latin:keyWidth="8.272%p"
+    >
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="q"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_q" />
+        <Key
+            latin:keyLabel="w"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_w" />
+        <Key
+            latin:keyLabel="e"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_e" />
+        <Key
+            latin:keyLabel="r"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_r" />
+        <Key
+            latin:keyLabel="t"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_t" />
+        <Key
+            latin:keyLabel="z"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_z" />
+        <Key
+            latin:keyLabel="u"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_u" />
+        <Key
+            latin:keyLabel="i"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_i" />
+        <Key
+            latin:keyLabel="o"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_o" />
+        <Key
+            latin:keyLabel="p"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_p" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row2" />
+    <Row
+        latin:keyWidth="8.042%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="15.192%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="y"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_y" />
+        <Key
+            latin:keyLabel="x" />
+        <Key
+            latin:keyLabel="c"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_c" />
+        <Key
+            latin:keyLabel="v"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_v" />
+        <Key
+            latin:keyLabel="b" />
+        <Key
+            latin:keyLabel="n"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_n" />
+        <Key
+            latin:keyLabel="m" />
+        <switch>
+            <case
+                latin:mode="email"
+            >
+                <Key
+                    latin:keyLabel="," />
+                <Key
+                    latin:keyLabel="." />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel=","
+                    latin:manualTemporaryUpperCaseCode="33"
+                    latin:keyHintIcon="@drawable/key_hint_exclamation_holo"
+                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_exclamation_large_holo"
+                    latin:popupKeyboard="@xml/kbd_popup_template"
+                    latin:popupCharacters="!" />
+                <Key
+                    latin:keyLabel="."
+                    latin:manualTemporaryUpperCaseCode="63"
+                    latin:keyHintIcon="@drawable/key_hint_question_holo"
+                    latin:manualTemporaryUpperCaseHintIcon="@drawable/key_hint_question_large_holo"
+                    latin:popupKeyboard="@xml/kbd_popup_template"
+                    latin:popupCharacters="\?" />
+            </default>
+        </switch>
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="12.530%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+   <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</merge>
diff --git a/java/res/xml-xlarge/kbd_symbols.xml b/java/res/xml-xlarge/kbd_symbols.xml
new file mode 100644
index 0000000..a5e169d
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_symbols.xml
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <!-- This row is intentionally not marked as a top row -->
+    <Row
+        latin:keyWidth="8.272%p"
+    >
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="1"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="¹½⅓¼⅛" />
+        <Key
+            latin:keyLabel="2"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="²⅔" />
+        <Key
+            latin:keyLabel="3"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="³¾⅜" />
+        <Key
+            latin:keyLabel="4"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="⁴" />
+        <Key
+            latin:keyLabel="5"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="⅝" />
+        <Key
+            latin:keyLabel="6" />
+        <Key
+            latin:keyLabel="7"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="⅞" />
+        <Key
+            latin:keyLabel="8" />
+        <Key
+            latin:keyLabel="9" />
+        <Key
+            latin:keyLabel="0"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="ⁿ∅" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="8.157%p"
+    >
+        <Key
+            latin:keyStyle="toAlphaKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="11.167%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="#" />
+        <Key
+            latin:keyLabel="$"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="¢£€¥₣₤₱" />
+        <Key
+            latin:keyLabel="%"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="‰" />
+        <Key
+            latin:keyLabel="&amp;" />
+        <Key
+            latin:keyLabel="*"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="†‡★" />
+        <Key
+            latin:keyLabel="-"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="_–—" />
+        <Key
+            latin:keyLabel="+"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="±" />
+        <Key
+            latin:keyLabel="("
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="[{&lt;" />
+        <Key
+            latin:keyLabel=")"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="]}&gt;" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="15.750%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="8.042%p"
+    >
+        <Key
+            latin:keyStyle="moreKeyStyle"
+            latin:keyWidth="15.192%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="&lt;"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="≤«‹" />
+        <Key
+            latin:keyLabel="&gt;"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="≥»›" />
+        <Key
+            latin:keyLabel="[" />
+        <Key
+            latin:keyLabel="]" />
+        <Key
+            latin:keyLabel="="
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="≠≈" />
+        <Key
+            latin:keyLabel=":" />
+        <Key
+            latin:keyLabel=";" />
+        <Key
+            latin:keyLabel="!"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="¡" />
+        <Key
+            latin:keyLabel="\?"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="¿" />
+        <Key
+            latin:keyStyle="moreKeyStyle"
+            latin:keyWidth="12.530%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <!-- This row is intentionally not marked as a bottom row -->
+    <Row
+        latin:keyWidth="8.042%p"
+    >
+        <Spacer
+            latin:horizontalGap="16.404%p" />
+        <Key
+            latin:keyLabel="/" />
+        <Key
+            latin:keyLabel="\@" />
+        <Key
+            latin:keyStyle="spaceKeyStyle"
+            latin:keyWidth="37.454%p" />
+        <Key
+            latin:keyLabel="&quot;"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="“”«»˝" />
+        <Key
+            latin:keyLabel="_" />
+    </Row>
+</Keyboard>
diff --git a/java/res/xml-xlarge/kbd_symbols_shift.xml b/java/res/xml-xlarge/kbd_symbols_shift.xml
new file mode 100644
index 0000000..6edfbc7
--- /dev/null
+++ b/java/res/xml-xlarge/kbd_symbols_shift.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <!-- This row is intentionally not marked as a top row -->
+    <Row
+        latin:keyWidth="8.272%p"
+    >
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="7.949%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="~" />
+        <Key
+            latin:keyLabel="`" />
+        <Key
+            latin:keyLabel="|" />
+        <Key
+            latin:keyLabel="•"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="♪♥♠♦♣" />
+        <Key
+            latin:keyLabel="√" />
+        <Key
+            latin:keyLabel="π"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="Π" />
+        <Key
+            latin:keyLabel="÷" />
+        <Key
+            latin:keyLabel="×" />
+        <Key
+            latin:keyLabel="{" />
+        <Key
+            latin:keyLabel="}" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="9.331%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="8.157%p"
+    >
+        <Key
+            latin:keyStyle="toAlphaKeyStyle"
+            latin:keyLabelOption="alignLeft"
+            latin:keyWidth="11.167%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="£" />
+        <Key
+            latin:keyLabel="¢" />
+        <Key
+            latin:keyLabel="€" />
+        <Key
+            latin:keyLabel="¥" />
+        <Key
+            latin:keyLabel="^"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="↑↓←→" />
+        <Key
+            latin:keyLabel="°"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="¶§" />
+        <Key
+            latin:keyLabel="±"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="∞" />
+        <Key
+            latin:keyLabel="[" />
+        <Key
+            latin:keyLabel="]" />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="15.750%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="8.042%p"
+    >
+        <Key
+            latin:keyStyle="moreKeyStyle"
+            latin:keyWidth="15.192%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="\\" />
+        <Key
+            latin:keyLabel="©" />
+        <Key
+            latin:keyLabel="®"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="™" />
+        <Key
+            latin:keyLabel="{" />
+        <Key
+            latin:keyLabel="}" />
+        <Key
+            latin:keyLabel="," />
+        <Key
+            latin:keyLabel="." />
+        <Key
+            latin:keyLabel="¡" />
+        <Key
+            latin:keyLabel="¿" />
+        <Key
+            latin:keyStyle="moreKeyStyle"
+            latin:keyWidth="12.530%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <!-- This row is intentionally not marked as a bottom row -->
+    <Row
+        latin:keyWidth="8.042%p"
+    >
+        <Spacer
+            latin:horizontalGap="32.488%p" />
+        <Key
+            latin:keyStyle="spaceKeyStyle"
+            latin:keyWidth="37.454%p" />
+    </Row>
+</Keyboard>
diff --git a/java/res/xml-xlarge/popup_domains.xml b/java/res/xml-xlarge/popup_domains.xml
new file mode 100644
index 0000000..be0c918
--- /dev/null
+++ b/java/res/xml-xlarge/popup_domains.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="5.5%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
+>
+    <Row
+        latin:rowEdgeFlags="top|bottom"
+    >
+        <Key
+            latin:keyLabel="@string/popular_domain_1"
+            latin:keyOutputText="@string/popular_domain_1"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="@string/popular_domain_2"
+            latin:keyOutputText="@string/popular_domain_2" />
+        <Key
+            latin:keyLabel="@string/popular_domain_3"
+            latin:keyOutputText="@string/popular_domain_3" />
+        <Key
+            latin:keyLabel="@string/popular_domain_4"
+            latin:keyOutputText="@string/popular_domain_4"
+            latin:keyEdgeFlags="right" />
+    </Row>
+</Keyboard>
diff --git a/java/res/xml-xlarge/popup_smileys.xml b/java/res/xml-xlarge/popup_smileys.xml
new file mode 100644
index 0000000..bdd6805
--- /dev/null
+++ b/java/res/xml-xlarge/popup_smileys.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="5.0%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
+>
+    <Row
+        latin:rowEdgeFlags="top"
+    >
+        <Key
+            latin:keyLabel=":-)"
+            latin:keyOutputText=":-) "
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel=":-("
+            latin:keyOutputText=":-( " />
+        <Key
+            latin:keyLabel=";-)"
+            latin:keyOutputText=";-) " />
+        <Key
+            latin:keyLabel=":-P"
+            latin:keyOutputText=":-P " />
+        <Key
+            latin:keyLabel="=-O"
+            latin:keyOutputText="=-O "
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyLabel=":-*"
+            latin:keyOutputText=":-* "
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel=":O"
+            latin:keyOutputText=":O " />
+        <Key
+            latin:keyLabel="B-)"
+            latin:keyOutputText="B-) " />
+        <Key
+            latin:keyLabel=":-$"
+            latin:keyOutputText=":-$ " />
+        <Key
+            latin:keyLabel=":-!"
+            latin:keyOutputText=":-! "
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:rowEdgeFlags="bottom"
+    >
+        <Key
+            latin:keyLabel=":-["
+            latin:keyOutputText=":-[ "
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="O:-)"
+            latin:keyOutputText="O:-) " />
+        <Key
+            latin:keyLabel=":-\\"
+            latin:keyOutputText=":-\\ " />
+        <Key
+            latin:keyLabel=":'("
+            latin:keyOutputText=":'( " />
+        <Key
+            latin:keyLabel=":-D"
+            latin:keyOutputText=":-D "
+            latin:keyEdgeFlags="right" />
+    </Row>
+</Keyboard>
diff --git a/java/res/xml/kbd_azerty_rows.xml b/java/res/xml/kbd_azerty_rows.xml
new file mode 100644
index 0000000..c06724c
--- /dev/null
+++ b/java/res/xml/kbd_azerty_rows.xml
@@ -0,0 +1,155 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <Row
+        latin:keyWidth="10%p"
+        latin:rowEdgeFlags="top"
+    >
+        <Key
+            latin:keyLabel="a"
+            latin:keyHintIcon="@drawable/keyboard_hint_1"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_a"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="z"
+            latin:keyHintIcon="@drawable/keyboard_hint_2"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_z" />
+        <Key
+            latin:keyLabel="e"
+            latin:keyHintIcon="@drawable/keyboard_hint_3"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_e" />
+        <Key
+            latin:keyLabel="r"
+            latin:keyHintIcon="@drawable/keyboard_hint_4"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_r" />
+        <Key
+            latin:keyLabel="t"
+            latin:keyHintIcon="@drawable/keyboard_hint_5"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_t" />
+        <Key
+            latin:keyLabel="y"
+            latin:keyHintIcon="@drawable/keyboard_hint_6"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_y" />
+        <Key
+            latin:keyLabel="u"
+            latin:keyHintIcon="@drawable/keyboard_hint_7"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_u" />
+        <Key
+            latin:keyLabel="i"
+            latin:keyHintIcon="@drawable/keyboard_hint_8"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_i" />
+        <Key
+            latin:keyLabel="o"
+            latin:keyHintIcon="@drawable/keyboard_hint_9"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_o" />
+        <Key
+            latin:keyLabel="p"
+            latin:keyHintIcon="@drawable/keyboard_hint_0"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="10%p"
+    >
+        <Key
+            latin:keyLabel="q"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_q"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="s"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_s" />
+        <Key
+            latin:keyLabel="d"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_d" />
+        <Key
+            latin:keyLabel="f" />
+        <Key
+            latin:keyLabel="g"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_g" />
+        <Key
+            latin:keyLabel="h" />
+        <Key
+            latin:keyLabel="j" />
+        <Key
+            latin:keyLabel="k" />
+        <Key
+            latin:keyLabel="l"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_l" />
+        <Key
+            latin:keyLabel="m"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="10%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="15%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="w"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_w" />
+        <Key
+            latin:keyLabel="x" />
+        <Key
+            latin:keyLabel="c"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_c" />
+        <Key
+            latin:keyLabel="v"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_v" />
+        <Key
+            latin:keyLabel="b" />
+        <Key
+            latin:keyLabel="n"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_n" />
+        <Key
+            latin:keyLabel="\'" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="15%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</merge>
diff --git a/java/res/xml/kbd_key_styles.xml b/java/res/xml/kbd_key_styles.xml
new file mode 100644
index 0000000..9dd166a
--- /dev/null
+++ b/java/res/xml/kbd_key_styles.xml
@@ -0,0 +1,289 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <!-- Functional key styles -->
+    <switch>
+        <case
+            latin:colorScheme="white"
+        >
+            <key-style
+                latin:styleName="functionalKeyStyle"
+                latin:isModifier="true" />
+            <key-style
+                latin:styleName="shiftKeyStyle"
+                latin:codes="@integer/key_shift"
+                latin:keyIcon="@drawable/sym_keyboard_shift"
+                latin:shiftedIcon="@drawable/sym_keyboard_shift_locked"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_shift"
+                latin:parentStyle="functionalKeyStyle"
+                latin:isSticky="true" />
+            <key-style
+                latin:styleName="deleteKeyStyle"
+                latin:codes="@integer/key_delete"
+                latin:keyIcon="@drawable/sym_keyboard_delete"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_delete"
+                latin:parentStyle="functionalKeyStyle"
+                latin:isRepeatable="true" />
+            <switch>
+                <!-- When this qwerty keyboard has no voice key but voice key is enabled, then
+                     symbol keyboard will have mic key. That means we should use "?123mic" key
+                     here. -->
+                <case
+                    latin:voiceKeyEnabled="true"
+                    latin:hasVoiceKey="false"
+                >
+                    <key-style
+                        latin:styleName="toSymbolKeyStyle"
+                        latin:codes="@integer/key_switch_alpha_symbol"
+                        latin:keyIcon="@drawable/sym_keyboard_123_mic"
+                        latin:iconPreview="@drawable/sym_keyboard_feedback_123_mic"
+                        latin:parentStyle="functionalKeyStyle" />
+                </case>
+                <default>
+                    <key-style
+                        latin:styleName="toSymbolKeyStyle"
+                        latin:codes="@integer/key_switch_alpha_symbol"
+                        latin:keyLabel="@string/label_to_symbol_key"
+                        latin:parentStyle="functionalKeyStyle" />
+                </default>
+            </switch>
+            <key-style
+                latin:styleName="settingsKeyStyle"
+                latin:codes="@integer/key_settings"
+                latin:keyIcon="@drawable/sym_keyboard_settings"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_settings"
+                latin:parentStyle="functionalKeyStyle" />
+            <key-style
+                latin:styleName="spaceKeyStyle"
+                latin:codes="@integer/key_space"
+                latin:keyIcon="@drawable/sym_keyboard_space"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_space"
+                latin:parentStyle="functionalKeyStyle" />
+            <key-style
+                latin:styleName="tabKeyStyle"
+                latin:codes="@integer/key_tab"
+                latin:keyIcon="@drawable/sym_keyboard_tab"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_tab"
+                latin:parentStyle="functionalKeyStyle" />
+            <key-style
+                latin:styleName="micKeyStyle"
+                latin:codes="@integer/key_voice"
+                latin:popupKeyboard="@xml/popup_mic"
+                latin:keyIcon="@drawable/sym_keyboard_mic"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_mic"
+                latin:keyHintIcon="@drawable/hint_popup"
+                latin:parentStyle="functionalKeyStyle" />
+            <!-- Note: This key style is not for functional tab key. This is used for the tab key
+                 which is laid out as normal letter key. -->
+            <key-style
+                latin:styleName="nonSpecialBackgroundTabKeyStyle"
+                latin:codes="@integer/key_tab"
+                latin:keyIcon="@drawable/sym_keyboard_tab"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_tab" />
+        </case>
+        <case
+            latin:colorScheme="black"
+        >
+            <key-style
+                latin:styleName="functionalKeyStyle" />
+            <key-style
+                latin:styleName="shiftKeyStyle"
+                latin:codes="@integer/key_shift"
+                latin:keyIcon="@drawable/sym_bkeyboard_shift"
+                latin:shiftedIcon="@drawable/sym_bkeyboard_shift_locked"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_shift"
+                latin:parentStyle="functionalKeyStyle"
+                latin:isSticky="true" />
+            <key-style
+                latin:styleName="deleteKeyStyle"
+                latin:codes="@integer/key_delete"
+                latin:keyIcon="@drawable/sym_bkeyboard_delete"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_delete"
+                latin:parentStyle="functionalKeyStyle"
+                latin:isRepeatable="true" />
+            <switch>
+                <!-- When this qwerty keyboard has no voice key but voice key is enabled, then
+                     symbol keyboard will have mic key. That means we should use "?123mic" key
+                     here. -->
+                <case
+                    latin:voiceKeyEnabled="true"
+                    latin:hasVoiceKey="false"
+                >
+                    <key-style
+                        latin:styleName="toSymbolKeyStyle"
+                        latin:codes="@integer/key_switch_alpha_symbol"
+                        latin:keyIcon="@drawable/sym_bkeyboard_123_mic"
+                        latin:iconPreview="@drawable/sym_keyboard_feedback_123_mic"
+                        latin:parentStyle="functionalKeyStyle" />
+                </case>
+                <default>
+                    <key-style
+                        latin:styleName="toSymbolKeyStyle"
+                        latin:codes="@integer/key_switch_alpha_symbol"
+                        latin:keyLabel="@string/label_to_symbol_key"
+                        latin:parentStyle="functionalKeyStyle" />
+                </default>
+            </switch>
+            <key-style
+                latin:styleName="settingsKeyStyle"
+                latin:codes="@integer/key_settings"
+                latin:keyIcon="@drawable/sym_bkeyboard_settings"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_settings"
+                latin:parentStyle="functionalKeyStyle" />
+            <key-style
+                latin:styleName="spaceKeyStyle"
+                latin:codes="@integer/key_space"
+                latin:keyIcon="@drawable/sym_bkeyboard_space"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_space"
+                latin:parentStyle="functionalKeyStyle" />
+            <key-style
+                latin:styleName="tabKeyStyle"
+                latin:codes="@integer/key_tab"
+                latin:keyIcon="@drawable/sym_bkeyboard_tab"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_tab"
+                latin:parentStyle="functionalKeyStyle" />
+            <key-style
+                latin:styleName="micKeyStyle"
+                latin:codes="@integer/key_voice"
+                latin:popupKeyboard="@xml/popup_mic"
+                latin:keyIcon="@drawable/sym_bkeyboard_mic"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_mic"
+                latin:keyHintIcon="@drawable/hint_popup"
+                latin:parentStyle="functionalKeyStyle" />
+            <!-- Note: This key style is not for functional tab key. This is used for the tab key
+                 which is laid out as normal letter key. -->
+            <key-style
+                latin:styleName="nonSpecialBackgroundTabKeyStyle"
+                latin:codes="@integer/key_tab"
+                latin:keyIcon="@drawable/sym_bkeyboard_tab"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_tab" />
+        </case>
+    </switch>
+    <!-- Return key style -->
+    <switch>
+        <case
+            latin:imeOptions="actionGo"
+        >
+            <key-style
+                latin:styleName="returnKeyStyle"
+                latin:codes="@integer/key_return"
+                latin:keyLabel="@string/label_go_key"
+                latin:parentStyle="functionalKeyStyle" />
+        </case>
+        <case
+            latin:imeOptions="actionNext"
+        >
+            <key-style
+                latin:styleName="returnKeyStyle"
+                latin:codes="@integer/key_return"
+                latin:keyLabel="@string/label_next_key"
+                latin:parentStyle="functionalKeyStyle" />
+        </case>
+        <case
+            latin:imeOptions="actionDone"
+        >
+            <key-style
+                latin:styleName="returnKeyStyle"
+                latin:codes="@integer/key_return"
+                latin:keyLabel="@string/label_done_key"
+                latin:parentStyle="functionalKeyStyle" />
+        </case>
+        <case
+            latin:imeOptions="actionSend"
+        >
+            <key-style
+                latin:styleName="returnKeyStyle"
+                latin:codes="@integer/key_return"
+                latin:keyLabel="@string/label_send_key"
+                latin:parentStyle="functionalKeyStyle" />
+        </case>
+        <case
+            latin:imeOptions="actionSearch"
+        >
+            <switch>
+                <case
+                    latin:colorScheme="white"
+                >
+                    <key-style
+                        latin:styleName="returnKeyStyle"
+                        latin:codes="@integer/key_return"
+                        latin:keyIcon="@drawable/sym_keyboard_search"
+                        latin:iconPreview="@drawable/sym_keyboard_feedback_search"
+                        latin:parentStyle="functionalKeyStyle" />
+                </case>
+                <case
+                    latin:colorScheme="black"
+                >
+                    <key-style
+                        latin:styleName="returnKeyStyle"
+                        latin:codes="@integer/key_return"
+                        latin:keyIcon="@drawable/sym_bkeyboard_search"
+                        latin:iconPreview="@drawable/sym_keyboard_feedback_search"
+                        latin:parentStyle="functionalKeyStyle" />
+                </case>
+            </switch>
+        </case>
+        <default>
+            <switch>
+                <case
+                    latin:colorScheme="white"
+                >
+                    <key-style
+                        latin:styleName="returnKeyStyle"
+                        latin:codes="@integer/key_return"
+                        latin:keyIcon="@drawable/sym_keyboard_return"
+                        latin:iconPreview="@drawable/sym_keyboard_feedback_return"
+                        latin:parentStyle="functionalKeyStyle" />
+                </case>
+                <case
+                    latin:colorScheme="black"
+                >
+                    <key-style
+                        latin:styleName="returnKeyStyle"
+                        latin:codes="@integer/key_return"
+                        latin:keyIcon="@drawable/sym_bkeyboard_return"
+                        latin:iconPreview="@drawable/sym_keyboard_feedback_return"
+                        latin:parentStyle="functionalKeyStyle" />
+                </case>
+            </switch>
+        </default>
+    </switch>
+    <key-style
+        latin:styleName="toAlphaKeyStyle"
+        latin:codes="@integer/key_switch_alpha_symbol"
+        latin:keyLabel="@string/label_to_alpha_key"
+        latin:parentStyle="functionalKeyStyle" />
+    <key-style
+        latin:styleName="altKeyStyle"
+        latin:codes="@integer/key_shift"
+        latin:keyLabel="@string/label_alt_key"
+        latin:parentStyle="functionalKeyStyle"
+        latin:isSticky="true" />
+    <key-style
+        latin:styleName="smileyKeyStyle"
+        latin:keyLabel=":-)"
+        latin:keyOutputText=":-) "
+        latin:keyHintIcon="@drawable/hint_popup"
+        latin:popupKeyboard="@xml/popup_smileys"
+        latin:parentStyle="functionalKeyStyle" />
+</merge>
\ No newline at end of file
diff --git a/java/res/xml/kbd_number.xml b/java/res/xml/kbd_number.xml
new file mode 100644
index 0000000..cde7205
--- /dev/null
+++ b/java/res/xml/kbd_number.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, 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.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="26.67%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+   <switch>
+        <case
+            latin:colorScheme="white"
+        >
+            <key-style
+                latin:styleName="numSpaceKeyStyle"
+                latin:codes="@integer/key_space"
+                latin:keyIcon="@drawable/sym_keyboard_space"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
+        </case>
+        <case
+            latin:colorScheme="black"
+        >
+            <key-style
+                latin:styleName="numSpaceKeyStyle"
+                latin:codes="@integer/key_space"
+                latin:keyIcon="@drawable/sym_bkeyboard_space"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
+        </case>
+    </switch>
+    <Row
+        latin:rowEdgeFlags="top"
+    >
+        <Key
+            latin:keyLabel="1"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="2" />
+        <Key
+            latin:keyLabel="3" />
+        <Key
+            latin:keyLabel="-"
+            latin:keyStyle="functionalKeyStyle"
+            latin:keyWidth="20%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyLabel="4"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="5" />
+        <Key
+            latin:keyLabel="6" />
+        <Key
+            latin:keyLabel=","
+            latin:keyStyle="functionalKeyStyle"
+            latin:keyWidth="20%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row>
+        <Key
+            latin:keyLabel="7"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="8" />
+        <Key
+            latin:keyLabel="9" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="20%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:rowEdgeFlags="bottom"
+    >
+        <Key
+            latin:keyStyle="numSpaceKeyStyle"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="0" />
+        <Key
+            latin:keyLabel="." />
+        <Key
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="20%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+</Keyboard>
diff --git a/java/res/xml/kbd_numkey_styles.xml b/java/res/xml/kbd_numkey_styles.xml
new file mode 100644
index 0000000..006476d
--- /dev/null
+++ b/java/res/xml/kbd_numkey_styles.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <switch>
+        <case
+            latin:colorScheme="white"
+        >
+            <key-style
+                latin:styleName="num0KeyStyle"
+                latin:codes="48"
+                latin:keyIcon="@drawable/sym_keyboard_num0" />
+            <key-style
+                latin:styleName="num1KeyStyle"
+                latin:codes="49"
+                latin:keyIcon="@drawable/sym_keyboard_num1" />
+            <key-style
+                latin:styleName="num2KeyStyle"
+                latin:codes="50"
+                latin:keyIcon="@drawable/sym_keyboard_num2" />
+            <key-style
+                latin:styleName="num3KeyStyle"
+                latin:codes="51"
+                latin:keyIcon="@drawable/sym_keyboard_num3" />
+            <key-style
+                latin:styleName="num4KeyStyle"
+                latin:codes="52"
+                latin:keyIcon="@drawable/sym_keyboard_num4" />
+            <key-style
+                latin:styleName="num5KeyStyle"
+                latin:codes="53"
+                latin:keyIcon="@drawable/sym_keyboard_num5" />
+            <key-style
+                latin:styleName="num6KeyStyle"
+                latin:codes="54"
+                latin:keyIcon="@drawable/sym_keyboard_num6" />
+            <key-style
+                latin:styleName="num7KeyStyle"
+                latin:codes="55"
+                latin:keyIcon="@drawable/sym_keyboard_num7" />
+            <key-style
+                latin:styleName="num8KeyStyle"
+                latin:codes="56"
+                latin:keyIcon="@drawable/sym_keyboard_num8" />
+            <key-style
+                latin:styleName="num9KeyStyle"
+                latin:codes="57"
+                latin:keyIcon="@drawable/sym_keyboard_num9" />
+            <key-style
+                latin:styleName="numStarKeyStyle"
+                latin:codes="42"
+                latin:keyIcon="@drawable/sym_keyboard_numstar" />
+            <key-style
+                latin:styleName="numPoundKeyStyle"
+                latin:codes="35"
+                latin:keyIcon="@drawable/sym_keyboard_numpound" />
+            <key-style
+                latin:styleName="numAltKeyStyle"
+                latin:codes="@integer/key_switch_alpha_symbol"
+                latin:keyIcon="@drawable/sym_keyboard_numalt"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_numalt" />
+            <key-style
+                latin:styleName="numSpaceKeyStyle"
+                latin:codes="@integer/key_space"
+                latin:keyIcon="@drawable/sym_keyboard_space"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
+        </case>
+        <case
+            latin:colorScheme="black"
+        >
+            <key-style
+                latin:styleName="num0KeyStyle"
+                latin:codes="48"
+                latin:keyIcon="@drawable/sym_bkeyboard_num0" />
+            <key-style
+                latin:styleName="num1KeyStyle"
+                latin:codes="49"
+                latin:keyIcon="@drawable/sym_bkeyboard_num1" />
+            <key-style
+                latin:styleName="num2KeyStyle"
+                latin:codes="50"
+                latin:keyIcon="@drawable/sym_bkeyboard_num2" />
+            <key-style
+                latin:styleName="num3KeyStyle"
+                latin:codes="51"
+                latin:keyIcon="@drawable/sym_bkeyboard_num3" />
+            <key-style
+                latin:styleName="num4KeyStyle"
+                latin:codes="52"
+                latin:keyIcon="@drawable/sym_bkeyboard_num4" />
+            <key-style
+                latin:styleName="num5KeyStyle"
+                latin:codes="53"
+                latin:keyIcon="@drawable/sym_bkeyboard_num5" />
+            <key-style
+                latin:styleName="num6KeyStyle"
+                latin:codes="54"
+                latin:keyIcon="@drawable/sym_bkeyboard_num6" />
+            <key-style
+                latin:styleName="num7KeyStyle"
+                latin:codes="55"
+                latin:keyIcon="@drawable/sym_bkeyboard_num7" />
+            <key-style
+                latin:styleName="num8KeyStyle"
+                latin:codes="56"
+                latin:keyIcon="@drawable/sym_bkeyboard_num8" />
+            <key-style
+                latin:styleName="num9KeyStyle"
+                latin:codes="57"
+                latin:keyIcon="@drawable/sym_bkeyboard_num9" />
+            <key-style
+                latin:styleName="numStarKeyStyle"
+                latin:codes="42"
+                latin:keyIcon="@drawable/sym_bkeyboard_numstar" />
+            <key-style
+                latin:styleName="numPoundKeyStyle"
+                latin:codes="35"
+                latin:keyIcon="@drawable/sym_bkeyboard_numpound" />
+            <key-style
+                latin:styleName="numAltKeyStyle"
+                latin:codes="@integer/key_switch_alpha_symbol"
+                latin:keyIcon="@drawable/sym_bkeyboard_numalt"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_numalt" />
+            <key-style
+                latin:styleName="numSpaceKeyStyle"
+                latin:codes="@integer/key_space"
+                latin:keyIcon="@drawable/sym_bkeyboard_space"
+                latin:iconPreview="@drawable/sym_keyboard_feedback_space" />
+        </case>
+    </switch>
+</merge>
diff --git a/java/res/xml/kbd_phone.xml b/java/res/xml/kbd_phone.xml
index 10774c6..7e146ed 100644
--- a/java/res/xml/kbd_phone.xml
+++ b/java/res/xml/kbd_phone.xml
@@ -19,88 +19,72 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="26.67%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="26.67%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <include
+        latin:keyboardLayout="@xml/kbd_numkey_styles" />
     <Row
-        android:rowEdgeFlags="top"
+        latin:rowEdgeFlags="top"
     >
         <Key
-            android:codes="49"
-            android:keyIcon="@drawable/sym_keyboard_num1"
-            android:keyEdgeFlags="left" />
+            latin:keyStyle="num1KeyStyle"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:codes="50"
-            android:keyIcon="@drawable/sym_keyboard_num2" />
+            latin:keyStyle="num2KeyStyle" />
         <Key
-            android:codes="51"
-            android:keyIcon="@drawable/sym_keyboard_num3" />
+            latin:keyStyle="num3KeyStyle" />
         <Key
-            android:keyLabel="-"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="-"
+            latin:keyStyle="functionalKeyStyle"
+            latin:keyWidth="20%p"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row>
         <Key
-            android:codes="52"
-            android:keyIcon="@drawable/sym_keyboard_num4"
-            android:keyEdgeFlags="left" />
+            latin:keyStyle="num4KeyStyle"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:codes="53"
-            android:keyIcon="@drawable/sym_keyboard_num5" />
+            latin:keyStyle="num5KeyStyle" />
         <Key
-            android:codes="54"
-            android:keyIcon="@drawable/sym_keyboard_num6" />
+            latin:keyStyle="num6KeyStyle" />
         <Key
-            android:keyLabel="."
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="."
+            latin:keyStyle="functionalKeyStyle"
+            latin:keyWidth="20%p"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row>
         <Key
-            android:codes="55"
-            android:keyIcon="@drawable/sym_keyboard_num7"
-            android:keyEdgeFlags="left" />
+            latin:keyStyle="num7KeyStyle"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:codes="56"
-            android:keyIcon="@drawable/sym_keyboard_num8" />
+            latin:keyStyle="num8KeyStyle" />
         <Key
-            android:codes="57"
-            android:keyIcon="@drawable/sym_keyboard_num9" />
+            latin:keyStyle="num9KeyStyle" />
         <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="20%p"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row
-        android:rowEdgeFlags="bottom"
+        latin:rowEdgeFlags="bottom"
     >
         <Key
-            android:codes="@integer/key_symbol"
-            android:keyIcon="@drawable/sym_keyboard_numalt"
-            android:iconPreview="@drawable/sym_keyboard_feedback_numalt"
-            android:keyEdgeFlags="left" />
+            latin:keyStyle="numAltKeyStyle"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:codes="48"
-            android:keyIcon="@drawable/sym_keyboard_num0" />
+            latin:keyStyle="num0KeyStyle" />
         <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space" />
+            latin:keyStyle="numSpaceKeyStyle" />
         <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="20%p"
+            latin:keyEdgeFlags="right" />
     </Row>
 </Keyboard>
diff --git a/java/res/xml/kbd_phone_black.xml b/java/res/xml/kbd_phone_black.xml
deleted file mode 100644
index 5afa9a1..0000000
--- a/java/res/xml/kbd_phone_black.xml
+++ /dev/null
@@ -1,101 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="26.67%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:codes="49"
-            android:keyIcon="@drawable/sym_bkeyboard_num1"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="50"
-            android:keyIcon="@drawable/sym_bkeyboard_num2" />
-        <Key
-            android:codes="51"
-            android:keyIcon="@drawable/sym_bkeyboard_num3" />
-        <Key
-            android:keyLabel="-"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:codes="52"
-            android:keyIcon="@drawable/sym_bkeyboard_num4"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="53"
-            android:keyIcon="@drawable/sym_bkeyboard_num5" />
-        <Key
-            android:codes="54"
-            android:keyIcon="@drawable/sym_bkeyboard_num6" />
-        <Key
-            android:keyLabel="."
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:codes="55"
-            android:keyIcon="@drawable/sym_bkeyboard_num7"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="56"
-            android:keyIcon="@drawable/sym_bkeyboard_num8" />
-        <Key
-            android:codes="57"
-            android:keyIcon="@drawable/sym_bkeyboard_num9" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="20%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyIcon="@drawable/sym_bkeyboard_numalt"
-            android:iconPreview="@drawable/sym_keyboard_feedback_numalt" />
-        <Key
-            android:codes="48"
-            android:keyIcon="@drawable/sym_bkeyboard_num0" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml/kbd_phone_symbols.xml b/java/res/xml/kbd_phone_symbols.xml
index 4c928a8..1bb4bac 100644
--- a/java/res/xml/kbd_phone_symbols.xml
+++ b/java/res/xml/kbd_phone_symbols.xml
@@ -19,84 +19,78 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="26.67%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="26.67%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <include
+        latin:keyboardLayout="@xml/kbd_numkey_styles" />
     <Row
-        android:rowEdgeFlags="top"
+        latin:rowEdgeFlags="top"
     >
         <Key
-            android:keyLabel="("
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="("
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="/" />
+            latin:keyLabel="/" />
         <Key
-            android:keyLabel=")" />
+            latin:keyLabel=")" />
         <Key
-            android:keyLabel="-"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="-"
+            latin:keyStyle="functionalKeyStyle"
+            latin:keyWidth="20%p"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row>
         <Key
-            android:keyLabel="N"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="N"
+            latin:keyEdgeFlags="left" />
         <!-- Pause is a comma. Check PhoneNumberUtils.java to see if this 
             has changed. -->
         <Key
-            android:codes="44"
-            android:keyLabel="Pause" />
+            latin:codes="44"
+            latin:keyLabel="Pause" />
         <Key
-            android:keyLabel="," />
+            latin:keyLabel="," />
         <Key
-            android:keyLabel="."
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="."
+            latin:keyStyle="functionalKeyStyle"
+            latin:keyWidth="20%p"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row>
         <Key
-            android:codes="42"
-            android:keyIcon="@drawable/sym_keyboard_numstar"
-            android:keyEdgeFlags="left" />
+            latin:keyStyle="numStarKeyStyle"
+            latin:keyEdgeFlags="left" />
         <!-- Wait is a semicolon. -->
         <Key
-            android:codes="59"
-            android:keyLabel="Wait" />
+            latin:codes="59"
+            latin:keyLabel="Wait" />
         <Key
-            android:codes="35"
-            android:keyIcon="@drawable/sym_keyboard_numpound" />
+            latin:keyStyle="numPoundKeyStyle" />
         <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="20%p"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row
-        android:rowEdgeFlags="bottom"
+        latin:rowEdgeFlags="bottom"
     >
         <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_phone_key"
-            android:keyEdgeFlags="left" />
+            latin:codes="@integer/key_switch_alpha_symbol"
+            latin:keyLabel="@string/label_phone_key"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="+" />
+            latin:keyLabel="+" />
         <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space" />
+            latin:keyStyle="numSpaceKeyStyle" />
         <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
+            latin:keyStyle="returnKeyStyle"
+            latin:keyWidth="20%p"
+            latin:keyEdgeFlags="right" />
     </Row>
 </Keyboard>
diff --git a/java/res/xml/kbd_phone_symbols_black.xml b/java/res/xml/kbd_phone_symbols_black.xml
deleted file mode 100644
index 4d686e1..0000000
--- a/java/res/xml/kbd_phone_symbols_black.xml
+++ /dev/null
@@ -1,98 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="26.67%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="("
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="/" />
-        <Key
-            android:keyLabel=")" />
-        <Key
-            android:keyLabel="-"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="N"
-            android:keyEdgeFlags="left" />
-        <!-- Pause is a comma. Check PhoneNumberUtils.java to see if this 
-            has changed. -->
-        <Key
-            android:codes="44"
-            android:keyLabel="Pause" />
-        <Key
-            android:keyLabel="," />
-        <Key
-            android:keyLabel="."
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:codes="42"
-            android:keyIcon="@drawable/sym_bkeyboard_numstar"
-            android:keyEdgeFlags="left" />
-        <!-- Wait is a semicolon. -->
-        <Key
-            android:codes="59"
-            android:keyLabel="Wait" />
-        <Key
-            android:codes="35"
-            android:keyIcon="@drawable/sym_bkeyboard_numpound" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="20%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_phone_key"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="+" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml/kbd_popup_narrow_template.xml b/java/res/xml/kbd_popup_narrow_template.xml
index 23c686e..9b78711 100644
--- a/java/res/xml/kbd_popup_narrow_template.xml
+++ b/java/res/xml/kbd_popup_narrow_template.xml
@@ -18,10 +18,10 @@
 */
 -->
 
-<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="9.45%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
-    android:keyHeight="@dimen/popup_key_height"
+<Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="9.45%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
     >
 </Keyboard>
diff --git a/java/res/xml/kbd_popup_template.xml b/java/res/xml/kbd_popup_template.xml
index a287be1..004d490 100644
--- a/java/res/xml/kbd_popup_template.xml
+++ b/java/res/xml/kbd_popup_template.xml
@@ -18,10 +18,10 @@
 */
 -->
 
-<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
-    android:keyHeight="@dimen/popup_key_height"
+<Keyboard xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
     >
 </Keyboard>
diff --git a/java/res/xml/kbd_qwerty.xml b/java/res/xml/kbd_qwerty.xml
index a4ab0f8..42f1515 100644
--- a/java/res/xml/kbd_qwerty.xml
+++ b/java/res/xml/kbd_qwerty.xml
@@ -19,487 +19,12 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="q"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_q"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="w"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_w" />
-        <Key
-            android:keyLabel="e"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_e" />
-        <Key
-            android:keyLabel="r"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_r" />
-        <Key
-            android:keyLabel="t"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_t" />
-        <Key
-            android:keyLabel="y"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_y" />
-        <Key
-            android:keyLabel="u"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_u" />
-        <Key
-            android:keyLabel="i"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_i" />
-        <Key
-            android:keyLabel="o"
-            android:popupKeyboard="@xml/kbd_popup_narrow_template"
-            android:popupCharacters="@string/alternates_for_o" />
-        <Key
-            android:keyLabel="p"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="a"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a"
-            android:horizontalGap="5%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="s"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_s" />
-        <Key
-            android:keyLabel="d"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_d" />
-        <Key
-            android:keyLabel="f" />
-        <Key
-            android:keyLabel="g"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_g" />
-        <Key
-            android:keyLabel="h" />
-        <Key
-            android:keyLabel="j" />
-        <Key
-            android:keyLabel="k" />
-        <Key
-            android:keyLabel="l"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_l"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_keyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="z"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_z" />
-        <Key
-            android:keyLabel="x" />
-        <Key
-            android:keyLabel="c"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_c" />
-        <Key
-            android:keyLabel="v"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_v" />
-        <Key
-            android:keyLabel="b" />
-        <Key
-            android:keyLabel="n"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_n" />
-        <Key
-            android:keyLabel="m" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_keyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_rows" />
 </Keyboard>
diff --git a/java/res/xml/kbd_qwerty_black.xml b/java/res/xml/kbd_qwerty_black.xml
deleted file mode 100644
index 787e4ef..0000000
--- a/java/res/xml/kbd_qwerty_black.xml
+++ /dev/null
@@ -1,447 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2008, 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.
-*/
--->
-
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="q"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_q"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="w"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_w" />
-        <Key
-            android:keyLabel="e"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_e" />
-        <Key
-            android:keyLabel="r"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_r" />
-        <Key
-            android:keyLabel="t"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_t" />
-        <Key
-            android:keyLabel="y"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_y" />
-        <Key
-            android:keyLabel="u"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_u" />
-        <Key
-            android:keyLabel="i"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_i" />
-        <Key
-            android:keyLabel="o"
-            android:popupKeyboard="@xml/kbd_popup_narrow_template"
-            android:popupCharacters="@string/alternates_for_o" />
-        <Key
-            android:keyLabel="p"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="a"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_a"
-            android:horizontalGap="5%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="s"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_s" />
-        <Key
-            android:keyLabel="d"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_d" />
-        <Key
-            android:keyLabel="f" />
-        <Key
-            android:keyLabel="g"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_g" />
-        <Key
-            android:keyLabel="h" />
-        <Key
-            android:keyLabel="j" />
-        <Key
-            android:keyLabel="k" />
-        <Key
-            android:keyLabel="l"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_l"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyIcon="@drawable/sym_bkeyboard_shift"
-            android:iconPreview="@drawable/sym_keyboard_feedback_shift"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="z"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_z" />
-        <Key
-            android:keyLabel="x" />
-        <Key
-            android:keyLabel="c"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_c" />
-        <Key
-            android:keyLabel="v"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_v" />
-        <Key
-            android:keyLabel="b" />
-        <Key
-            android:keyLabel="n"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="@string/alternates_for_n" />
-        <Key
-            android:keyLabel="m" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="20%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab"
-            android:keyWidth="20%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_normal_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_url_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_email_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_im_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_smileys"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_webentry_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_symbol_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyIcon="@drawable/sym_bkeyboard_tab"
-            android:iconPreview="@drawable/sym_keyboard_feedback_tab" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml/kbd_qwerty_black_symbol.xml b/java/res/xml/kbd_qwerty_black_symbol.xml
new file mode 100644
index 0000000..fe6b3a6
--- /dev/null
+++ b/java/res/xml/kbd_qwerty_black_symbol.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <switch>
+        <case
+            latin:hasSettingsKey="false"
+        >
+            <switch>
+                <!-- When this qwerty keyboard has no voice key but voice key is enabled, then
+                     symbol keyboard will have mic key. That means we should use "?123mic" key here.
+                     -->
+                <case
+                    latin:voiceKeyEnabled="true"
+                    latin:hasVoiceKey="false"
+                >
+                    <Key
+                        latin:codes="@integer/key_switch_alpha_symbol"
+                        latin:keyIcon="@drawable/sym_bkeyboard_123_mic"
+                        latin:iconPreview="@drawable/sym_keyboard_feedback_123_mic"
+                        latin:keyWidth="20%p"
+                        latin:isModifier="true"
+                        latin:keyEdgeFlags="left" />
+                </case>
+                <default>
+                    <Key
+                        latin:codes="@integer/key_switch_alpha_symbol"
+                        latin:keyLabel="@string/label_to_symbol_key"
+                        latin:keyWidth="20%p"
+                        latin:isModifier="true"
+                        latin:keyEdgeFlags="left" />
+                </default>
+            </switch>
+        </case>
+        <case
+            latin:hasSettingsKey="true"
+        >
+            <switch>
+                <!-- When this qwerty keyboard has no voice key but voice key is enabled, then
+                     symbol keyboard will have mic key. That means we should use "?123mic" key here.
+                     -->
+                <case
+                    latin:voiceKeyEnabled="true"
+                    latin:hasVoiceKey="false"
+                >
+                    <Key
+                        latin:codes="@integer/key_switch_alpha_symbol"
+                        latin:keyIcon="@drawable/sym_bkeyboard_123_mic"
+                        latin:iconPreview="@drawable/sym_keyboard_feedback_123_mic"
+                        latin:keyWidth="15%p"
+                        latin:isModifier="true"
+                        latin:keyEdgeFlags="left" />
+                </case>
+                <default>
+                    <Key
+                        latin:codes="@integer/key_switch_alpha_symbol"
+                        latin:keyLabel="@string/label_to_symbol_key"
+                        latin:keyWidth="15%p"
+                        latin:isModifier="true"
+                        latin:keyEdgeFlags="left" />
+                </default>
+            </switch>
+        </case>
+    </switch>
+</merge>
diff --git a/java/res/xml/kbd_qwerty_f1.xml b/java/res/xml/kbd_qwerty_f1.xml
new file mode 100644
index 0000000..1f0ccfb
--- /dev/null
+++ b/java/res/xml/kbd_qwerty_f1.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <switch>
+        <case
+            latin:mode="url"
+        >
+            <Key
+                latin:keyLabel="/"
+                latin:popupKeyboard="@xml/popup_slash"
+                latin:keyHintIcon="@drawable/hint_popup"
+                latin:isModifier="true" />
+        </case>
+        <case
+            latin:mode="email"
+        >
+            <Key
+                latin:keyLabel="\@"
+                latin:popupKeyboard="@xml/popup_at"
+                latin:keyHintIcon="@drawable/hint_popup"
+                latin:isModifier="true" />
+        </case>
+        <default>
+            <switch>
+                <case
+                    latin:hasVoiceKey="true"
+                >
+                    <Key
+                        latin:keyStyle="micKeyStyle" />
+                </case>
+                <case
+                    latin:hasVoiceKey="false"
+                >
+                    <Key
+                        latin:keyLabel=","
+                        latin:popupKeyboard="@xml/popup_comma"
+                        latin:keyHintIcon="@drawable/hint_popup"
+                        latin:isModifier="true" />
+                </case>
+            </switch>
+        </default>
+    </switch>
+</merge>
diff --git a/java/res/xml/kbd_qwerty_row1.xml b/java/res/xml/kbd_qwerty_row1.xml
new file mode 100644
index 0000000..e4356a8
--- /dev/null
+++ b/java/res/xml/kbd_qwerty_row1.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <Row
+        latin:keyWidth="10%p"
+        latin:rowEdgeFlags="top"
+    >
+        <Key
+            latin:keyLabel="q"
+            latin:keyHintIcon="@drawable/keyboard_hint_1"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_q"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="w"
+            latin:keyHintIcon="@drawable/keyboard_hint_2"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_w" />
+        <Key
+            latin:keyLabel="e"
+            latin:keyHintIcon="@drawable/keyboard_hint_3"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_e" />
+        <Key
+            latin:keyLabel="r"
+            latin:keyHintIcon="@drawable/keyboard_hint_4"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_r" />
+        <Key
+            latin:keyLabel="t"
+            latin:keyHintIcon="@drawable/keyboard_hint_5"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_t" />
+        <Key
+            latin:keyLabel="y"
+            latin:keyHintIcon="@drawable/keyboard_hint_6"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_y" />
+        <Key
+            latin:keyLabel="u"
+            latin:keyHintIcon="@drawable/keyboard_hint_7"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_u" />
+        <Key
+            latin:keyLabel="i"
+            latin:keyHintIcon="@drawable/keyboard_hint_8"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_i" />
+        <Key
+            latin:keyLabel="o"
+            latin:keyHintIcon="@drawable/keyboard_hint_9"
+            latin:popupKeyboard="@xml/kbd_popup_narrow_template"
+            latin:popupCharacters="@string/alternates_for_o" />
+        <Key
+            latin:keyLabel="p"
+            latin:keyHintIcon="@drawable/keyboard_hint_0"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+</merge>
diff --git a/java/res/xml/kbd_qwerty_row2.xml b/java/res/xml/kbd_qwerty_row2.xml
new file mode 100644
index 0000000..d518495
--- /dev/null
+++ b/java/res/xml/kbd_qwerty_row2.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <Row
+        latin:keyWidth="10%p"
+    >
+        <Spacer
+            latin:horizontalGap="5%p" />
+        <Key
+            latin:keyLabel="a"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_a"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="s"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_s" />
+        <Key
+            latin:keyLabel="d"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_d" />
+        <Key
+            latin:keyLabel="f" />
+        <Key
+            latin:keyLabel="g"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_g" />
+        <Key
+            latin:keyLabel="h" />
+        <Key
+            latin:keyLabel="j" />
+        <Key
+            latin:keyLabel="k" />
+        <Key
+            latin:keyLabel="l"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_l"
+            latin:keyEdgeFlags="right" />
+    </Row>
+</merge>
diff --git a/java/res/xml/kbd_qwerty_row3.xml b/java/res/xml/kbd_qwerty_row3.xml
new file mode 100644
index 0000000..71a5f9c
--- /dev/null
+++ b/java/res/xml/kbd_qwerty_row3.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <Row
+        latin:keyWidth="10%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="15%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="z"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_z" />
+        <Key
+            latin:keyLabel="x" />
+        <Key
+            latin:keyLabel="c"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_c" />
+        <Key
+            latin:keyLabel="v"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_v" />
+        <Key
+            latin:keyLabel="b" />
+        <Key
+            latin:keyLabel="n"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_n" />
+        <Key
+            latin:keyLabel="m" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="15%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+</merge>
diff --git a/java/res/xml/kbd_qwerty_row4.xml b/java/res/xml/kbd_qwerty_row4.xml
new file mode 100644
index 0000000..cd03c51
--- /dev/null
+++ b/java/res/xml/kbd_qwerty_row4.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <Row
+        latin:keyWidth="10%p"
+        latin:rowEdgeFlags="bottom"
+    >
+        <switch>
+            <case
+                latin:hasSettingsKey="false"
+            >
+                <Key
+                    latin:keyStyle="toSymbolKeyStyle"
+                    latin:keyWidth="20%p"
+                    latin:keyEdgeFlags="left" />
+                <include
+                    latin:keyboardLayout="@xml/kbd_qwerty_f1" />
+                <switch>
+                    <case
+                        latin:mode="web"
+                    >
+                        <Key
+                            latin:keyStyle="spaceKeyStyle"
+                            latin:keyWidth="20%p" />
+                        <Key
+                            latin:keyStyle="tabKeyStyle"
+                            latin:keyWidth="20%p" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyStyle="spaceKeyStyle"
+                            latin:keyWidth="40%p" />
+                    </default>
+                </switch>
+                <Key
+                    latin:keyLabel="."
+                    latin:keyHintIcon="@drawable/hint_popup"
+                    latin:popupKeyboard="@xml/popup_punctuation"
+                    latin:keyStyle="functionalKeyStyle" />
+                <switch>
+                    <case
+                        latin:mode="im"
+                    >
+                        <Key
+                            latin:keyStyle="smileyKeyStyle"
+                            latin:keyWidth="20%p"
+                            latin:keyEdgeFlags="right" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyStyle="returnKeyStyle"
+                            latin:keyWidth="20%p"
+                            latin:keyEdgeFlags="right" />
+                    </default>
+                </switch>
+            </case>
+            <case
+                latin:hasSettingsKey="true"
+            >
+                <Key
+                    latin:keyStyle="toSymbolKeyStyle"
+                    latin:keyWidth="15%p"
+                    latin:keyEdgeFlags="left" />
+                <Key
+                    latin:keyStyle="settingsKeyStyle" />
+                <include
+                    latin:keyboardLayout="@xml/kbd_qwerty_f1" />
+                <switch>
+                    <case
+                        latin:mode="web"
+                    >
+                        <Key
+                            latin:keyStyle="spaceKeyStyle"
+                            latin:keyWidth="30%p" />
+                        <Key
+                            latin:keyStyle="tabKeyStyle" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyStyle="spaceKeyStyle"
+                            latin:keyWidth="30%p" />
+                    </default>
+                </switch>
+                <Key
+                    latin:keyLabel="."
+                    latin:keyHintIcon="@drawable/hint_popup"
+                    latin:popupKeyboard="@xml/popup_punctuation"
+                    latin:keyStyle="functionalKeyStyle" />
+                <switch>
+                    <case
+                        latin:mode="im"
+                    >
+                        <Key
+                            latin:keyStyle="smileyKeyStyle"
+                            latin:keyWidth="25%p"
+                            latin:keyEdgeFlags="right" />
+                    </case>
+                    <case
+                        latin:mode="web"
+                    >
+                        <Key
+                            latin:keyStyle="returnKeyStyle"
+                            latin:keyWidth="15%p"
+                            latin:keyEdgeFlags="right" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyStyle="returnKeyStyle"
+                            latin:keyWidth="25%p"
+                            latin:keyEdgeFlags="right" />
+                    </default>
+                </switch>
+            </case>
+        </switch>
+    </Row>
+</merge>
diff --git a/java/res/xml/kbd_qwerty_rows.xml b/java/res/xml/kbd_qwerty_rows.xml
new file mode 100644
index 0000000..6237712
--- /dev/null
+++ b/java/res/xml/kbd_qwerty_rows.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row1" />
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row2" />
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row3" />
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</merge>
diff --git a/java/res/xml/kbd_qwerty_rows_scandinavia.xml b/java/res/xml/kbd_qwerty_rows_scandinavia.xml
new file mode 100644
index 0000000..4fa2e6e
--- /dev/null
+++ b/java/res/xml/kbd_qwerty_rows_scandinavia.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <Row
+        latin:keyWidth="9.09%p"
+        latin:rowEdgeFlags="top"
+    >
+        <Key
+            latin:keyLabel="q"
+            latin:keyHintIcon="@drawable/keyboard_hint_1"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_q"
+            latin:keyWidth="8.75%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="w"
+            latin:keyHintIcon="@drawable/keyboard_hint_2"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_w" />
+        <Key
+            latin:keyLabel="e"
+            latin:keyHintIcon="@drawable/keyboard_hint_3"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_e" />
+        <Key
+            latin:keyLabel="r"
+            latin:keyHintIcon="@drawable/keyboard_hint_4"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_r" />
+        <Key
+            latin:keyLabel="t"
+            latin:keyHintIcon="@drawable/keyboard_hint_5"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_t" />
+        <Key
+            latin:keyLabel="y"
+            latin:keyHintIcon="@drawable/keyboard_hint_6"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_y" />
+        <Key
+            latin:keyLabel="u"
+            latin:keyHintIcon="@drawable/keyboard_hint_7"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_u" />
+        <Key
+            latin:keyLabel="i"
+            latin:keyHintIcon="@drawable/keyboard_hint_8"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_i" />
+        <Key
+            latin:keyLabel="o"
+            latin:keyHintIcon="@drawable/keyboard_hint_9"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_o" />
+        <Key
+            latin:keyLabel="p"
+            latin:keyHintIcon="@drawable/keyboard_hint_0"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_p" />
+        <Key
+            latin:keyLabel="å"
+            latin:keyWidth="8.75%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <Row
+        latin:keyWidth="9.09%p"
+    >
+        <Key
+            latin:keyLabel="a"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_a"
+            latin:keyWidth="8.75%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="s"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_s" />
+        <Key
+            latin:keyLabel="d"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_d" />
+        <Key
+            latin:keyLabel="f" />
+        <Key
+            latin:keyLabel="g"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_g" />
+        <Key
+            latin:keyLabel="h" />
+        <Key
+            latin:keyLabel="j" />
+        <Key
+            latin:keyLabel="k" />
+        <Key
+            latin:keyLabel="l"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_l" />
+        <Key
+            latin:keyLabel="@string/keylabel_for_scandinavia_row2_10"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_scandinavia_row2_10" />
+        <Key
+            latin:keyLabel="@string/keylabel_for_scandinavia_row2_11"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_scandinavia_row2_11"
+            latin:keyWidth="8.75%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row3" />
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</merge>
diff --git a/java/res/xml/kbd_qwertz_rows.xml b/java/res/xml/kbd_qwertz_rows.xml
new file mode 100644
index 0000000..4dbb641
--- /dev/null
+++ b/java/res/xml/kbd_qwertz_rows.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
+    <Row
+        latin:keyWidth="10%p"
+        latin:rowEdgeFlags="top"
+    >
+        <Key
+            latin:keyLabel="q"
+            latin:keyHintIcon="@drawable/keyboard_hint_1"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_q"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="w"
+            latin:keyHintIcon="@drawable/keyboard_hint_2"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_w" />
+        <Key
+            latin:keyLabel="e"
+            latin:keyHintIcon="@drawable/keyboard_hint_3"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_e" />
+        <Key
+            latin:keyLabel="r"
+            latin:keyHintIcon="@drawable/keyboard_hint_4"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_r" />
+        <Key
+            latin:keyLabel="t"
+            latin:keyHintIcon="@drawable/keyboard_hint_5"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_t" />
+        <Key
+            latin:keyLabel="z"
+            latin:keyHintIcon="@drawable/keyboard_hint_6"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_z" />
+        <Key
+            latin:keyLabel="u"
+            latin:keyHintIcon="@drawable/keyboard_hint_7"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_u" />
+        <Key
+            latin:keyLabel="i"
+            latin:keyHintIcon="@drawable/keyboard_hint_8"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_i" />
+        <Key
+            latin:keyLabel="o"
+            latin:keyHintIcon="@drawable/keyboard_hint_9"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_o" />
+        <Key
+            latin:keyLabel="p"
+            latin:keyHintIcon="@drawable/keyboard_hint_0"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row2" />
+    <Row
+        latin:keyWidth="10%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="15%p"
+            latin:keyEdgeFlags="left" />
+        <Key
+            latin:keyLabel="y"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_y" />
+        <Key
+            latin:keyLabel="x" />
+        <Key
+            latin:keyLabel="c"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_c" />
+        <Key
+            latin:keyLabel="v"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_v" />
+        <Key
+            latin:keyLabel="b" />
+        <Key
+            latin:keyLabel="n"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="@string/alternates_for_n" />
+        <Key
+            latin:keyLabel="m" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="15%p"
+            latin:keyEdgeFlags="right" />
+    </Row>
+   <include
+        latin:keyboardLayout="@xml/kbd_qwerty_row4" />
+</merge>
diff --git a/java/res/xml/kbd_symbols.xml b/java/res/xml/kbd_symbols.xml
index bcb6e8a..7264179 100644
--- a/java/res/xml/kbd_symbols.xml
+++ b/java/res/xml/kbd_symbols.xml
@@ -19,196 +19,123 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
     <Row
-        android:rowEdgeFlags="top"
+        latin:rowEdgeFlags="top"
     >
         <Key
-            android:keyLabel="1"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="¹½⅓¼⅛"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="1"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="¹½⅓¼⅛"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="2"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="²⅔" />
+            latin:keyLabel="2"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="²⅔" />
         <Key
-            android:keyLabel="3"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="³¾⅜" />
+            latin:keyLabel="3"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="³¾⅜" />
         <Key
-            android:keyLabel="4"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="⁴" />
+            latin:keyLabel="4"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="⁴" />
         <Key
-            android:keyLabel="5"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="⅝" />
+            latin:keyLabel="5"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="⅝" />
         <Key
-            android:keyLabel="6" />
+            latin:keyLabel="6" />
         <Key
-            android:keyLabel="7"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="⅞" />
+            latin:keyLabel="7"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="⅞" />
         <Key
-            android:keyLabel="8" />
+            latin:keyLabel="8" />
         <Key
-            android:keyLabel="9" />
+            latin:keyLabel="9" />
         <Key
-            android:keyLabel="0"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="ⁿ∅"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="0"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="ⁿ∅"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row>
         <Key
-            android:keyLabel="\@"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="\@"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="\#" />
+            latin:keyLabel="\#" />
         <Key
-            android:keyLabel="$"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="¢£€¥₣₤₱" />
+            latin:keyLabel="$"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="¢£€¥₣₤₱" />
         <Key
-            android:keyLabel="%"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="‰" />
+            latin:keyLabel="%"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="‰" />
         <Key
-            android:keyLabel="&amp;" />
+            latin:keyLabel="&amp;" />
         <Key
-            android:keyLabel="*"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="†‡★" />
+            latin:keyLabel="*"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="†‡★" />
         <Key
-            android:keyLabel="-"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="_–—" />
+            latin:keyLabel="-"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="_–—" />
         <Key
-            android:keyLabel="+"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="±" />
+            latin:keyLabel="+"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="±" />
         <Key
-            android:keyLabel="("
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="[{&lt;" />
+            latin:keyLabel="("
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="[{&lt;" />
         <Key
-            android:keyLabel=")"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="]}&gt;"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel=")"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="]}&gt;"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row>
         <Key
-            android:codes="@integer/key_shift"
-            android:keyLabel="@string/label_alt_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
+            latin:keyStyle="altKeyStyle"
+            latin:keyWidth="15%p"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="!"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="¡" />
+            latin:keyLabel="!"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="¡" />
         <Key
-            android:keyLabel="&quot;"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="“”«»˝" />
+            latin:keyLabel="&quot;"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="“”«»˝" />
         <Key
-            android:keyLabel="\'"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="‘’" />
+            latin:keyLabel="\'"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="‘’" />
         <Key
-            android:keyLabel=":" />
+            latin:keyLabel=":" />
         <Key
-            android:keyLabel=";" />
+            latin:keyLabel=";" />
         <Key
-            android:keyLabel="/" />
+            latin:keyLabel="/" />
         <Key
-            android:keyLabel="\?"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="¿" />
+            latin:keyLabel="\?"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="¿" />
         <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="15%p"
+            latin:keyEdgeFlags="right" />
     </Row>
-    <Row
-        android:keyboardMode="@+id/mode_symbols"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_alpha_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_symbols_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_alpha_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_f1"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
+    <include latin:keyboardLayout="@xml/kbd_symbols_row4" />
 </Keyboard>
diff --git a/java/res/xml/kbd_symbols_black.xml b/java/res/xml/kbd_symbols_black.xml
deleted file mode 100644
index add6c01..0000000
--- a/java/res/xml/kbd_symbols_black.xml
+++ /dev/null
@@ -1,202 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="1"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="¹½⅓¼⅛"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="2"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="²⅔" />
-        <Key
-            android:keyLabel="3"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="³¾⅜" />
-        <Key
-            android:keyLabel="4"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="⁴" />
-        <Key
-            android:keyLabel="5"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="⅝" />
-        <Key
-            android:keyLabel="6" />
-        <Key
-            android:keyLabel="7"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="⅞" />
-        <Key
-            android:keyLabel="8" />
-        <Key
-            android:keyLabel="9" />
-        <Key
-            android:keyLabel="0"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="ⁿ∅"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:keyLabel="\@"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="\#" />
-        <Key
-            android:keyLabel="$"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="¢£€¥₣₤₱" />
-        <Key
-            android:keyLabel="%"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="‰" />
-        <Key
-            android:keyLabel="&amp;" />
-        <Key
-            android:keyLabel="*"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="†‡★" />
-        <Key
-            android:keyLabel="-"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="_–—" />
-        <Key
-            android:keyLabel="+"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="±" />
-        <Key
-            android:keyLabel="("
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="[{&lt;" />
-        <Key
-            android:keyLabel=")"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="]}&gt;"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyLabel="@string/label_alt_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="!"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="¡" />
-        <Key
-            android:keyLabel="&quot;"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="“”«»˝" />
-        <Key
-            android:keyLabel="\'"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="‘’" />
-        <Key
-            android:keyLabel=":" />
-        <Key
-            android:keyLabel=";" />
-        <Key
-            android:keyLabel="/" />
-        <Key
-            android:keyLabel="\?"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="¿" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_symbols"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_alpha_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_symbols_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_alpha_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:codes="@integer/key_f1" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="."
-            android:keyIcon="@drawable/hint_popup"
-            android:popupKeyboard="@xml/popup_punctuation" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml/kbd_symbols_f1.xml b/java/res/xml/kbd_symbols_f1.xml
new file mode 100644
index 0000000..07ee4ed
--- /dev/null
+++ b/java/res/xml/kbd_symbols_f1.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <switch>
+        <case
+            latin:hasVoiceKey="true"
+        >
+            <Key
+                latin:keyStyle="micKeyStyle" />
+        </case>
+        <case
+            latin:hasVoiceKey="false"
+        >
+            <Key
+                latin:keyLabel=","
+                latin:popupKeyboard="@xml/popup_comma"
+                latin:keyHintIcon="@drawable/hint_popup"
+                latin:keyStyle="functionalKeyStyle" />
+        </case>
+    </switch>
+</merge>
diff --git a/java/res/xml/kbd_symbols_row4.xml b/java/res/xml/kbd_symbols_row4.xml
new file mode 100644
index 0000000..1a5417d
--- /dev/null
+++ b/java/res/xml/kbd_symbols_row4.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <Row
+        latin:rowEdgeFlags="bottom"
+    >
+        <switch>
+            <case
+                latin:hasSettingsKey="false"
+            >
+                <Key
+                    latin:keyStyle="toAlphaKeyStyle"
+                    latin:keyWidth="20%p"
+                    latin:keyEdgeFlags="left" />
+                <include
+                    latin:keyboardLayout="@xml/kbd_symbols_f1" />
+                <Key
+                    latin:keyStyle="spaceKeyStyle"
+                    latin:keyWidth="40%p" />
+                <Key
+                    latin:keyLabel="."
+                    latin:keyHintIcon="@drawable/hint_popup"
+                    latin:popupKeyboard="@xml/popup_punctuation"
+                    latin:keyStyle="functionalKeyStyle" />
+                <switch>
+                    <case
+                        latin:mode="im"
+                    >
+                        <Key
+                            latin:keyStyle="smileyKeyStyle"
+                            latin:keyWidth="20%p"
+                            latin:keyEdgeFlags="right" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyStyle="returnKeyStyle"
+                            latin:keyWidth="20%p"
+                            latin:keyEdgeFlags="right" />
+                    </default>
+                </switch>
+            </case>
+            <case
+                latin:hasSettingsKey="true"
+            >
+                <Key
+                    latin:keyStyle="toAlphaKeyStyle"
+                    latin:keyWidth="15%p"
+                    latin:keyEdgeFlags="left" />
+                <Key
+                    latin:keyStyle="settingsKeyStyle" />
+                <include
+                    latin:keyboardLayout="@xml/kbd_symbols_f1" />
+                <Key
+                    latin:keyStyle="spaceKeyStyle"
+                    latin:keyWidth="30%p" />
+                <Key
+                    latin:keyLabel="."
+                    latin:keyHintIcon="@drawable/hint_popup"
+                    latin:popupKeyboard="@xml/popup_punctuation"
+                    latin:keyStyle="functionalKeyStyle" />
+                <switch>
+                    <case
+                        latin:mode="im"
+                    >
+                        <Key
+                            latin:keyStyle="smileyKeyStyle"
+                            latin:keyWidth="25%p"
+                            latin:keyEdgeFlags="right" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyStyle="returnKeyStyle"
+                            latin:keyWidth="25%p"
+                            latin:keyEdgeFlags="right" />
+                    </default>
+                </switch>
+            </case>
+        </switch>
+    </Row>
+</merge>
diff --git a/java/res/xml/kbd_symbols_shift.xml b/java/res/xml/kbd_symbols_shift.xml
index 9bee220..83963bf 100644
--- a/java/res/xml/kbd_symbols_shift.xml
+++ b/java/res/xml/kbd_symbols_shift.xml
@@ -19,171 +19,101 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="@dimen/key_horizontal_gap"
+    latin:verticalGap="@dimen/key_bottom_gap"
+    latin:keyHeight="@dimen/key_height"
 >
+    <include
+        latin:keyboardLayout="@xml/kbd_key_styles" />
     <Row
-        android:rowEdgeFlags="top"
+        latin:rowEdgeFlags="top"
     >
         <Key
-            android:keyLabel="~"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="~"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="`" />
+            latin:keyLabel="`" />
         <Key
-            android:keyLabel="|" />
+            latin:keyLabel="|" />
         <Key
-            android:keyLabel="•"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="♪♥♠♦♣" />
+            latin:keyLabel="•"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="♪♥♠♦♣" />
         <Key
-            android:keyLabel="√" />
+            latin:keyLabel="√" />
         <Key
-            android:keyLabel="π"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="Π" />
+            latin:keyLabel="π"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="Π" />
         <Key
-            android:keyLabel="÷" />
+            latin:keyLabel="÷" />
         <Key
-            android:keyLabel="×" />
+            latin:keyLabel="×" />
         <Key
-            android:keyLabel="{" />
+            latin:keyLabel="{" />
         <Key
-            android:keyLabel="}"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="}"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row>
         <Key
-            android:codes="@integer/key_tab"
-            android:keyLabel="\u21E5"
-            android:keyEdgeFlags="left" />
+            latin:keyStyle="nonSpecialBackgroundTabKeyStyle"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="£" />
+            latin:keyLabel="£" />
         <Key
-            android:keyLabel="¢" />
+            latin:keyLabel="¢" />
         <Key
-            android:keyLabel="€" />
+            latin:keyLabel="€" />
         <Key
-            android:keyLabel="°" />
+            latin:keyLabel="°" />
         <Key
-            android:keyLabel="^"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="↑↓←→" />
+            latin:keyLabel="^"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="↑↓←→" />
         <Key
-            android:keyLabel="_" />
+            latin:keyLabel="_" />
         <Key
-            android:keyLabel="="
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="≠≈∞" />
+            latin:keyLabel="="
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="≠≈∞" />
         <Key
-            android:keyLabel="[" />
+            latin:keyLabel="[" />
         <Key
-            android:keyLabel="]"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="]"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row>
         <Key
-            android:codes="@integer/key_shift"
-            android:keyLabel="@string/label_alt_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="15%p"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="™" />
+            latin:keyLabel="™" />
         <Key
-            android:keyLabel="®" />
+            latin:keyLabel="®" />
         <Key
-            android:keyLabel="©" />
+            latin:keyLabel="©" />
         <Key
-            android:keyLabel="¶"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="§" />
+            latin:keyLabel="¶"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="§" />
         <Key
-            android:keyLabel="\\" />
+            latin:keyLabel="\\" />
         <Key
-            android:keyLabel="&lt;"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="≤«‹" />
+            latin:keyLabel="&lt;"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="≤«‹" />
         <Key
-            android:keyLabel="&gt;"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="≥»›" />
+            latin:keyLabel="&gt;"
+            latin:popupKeyboard="@xml/kbd_popup_template"
+            latin:popupCharacters="≥»›" />
         <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_keyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="15%p"
+            latin:keyEdgeFlags="right" />
     </Row>
-    <Row
-        android:keyboardMode="@+id/mode_symbols"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_alpha_key"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="„"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="…"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_symbols_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_alpha_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="„"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_keyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p"
-            android:isModifier="true" />
-        <Key
-            android:keyLabel="…"
-            android:isModifier="true" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_keyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:isModifier="true"
-            android:keyEdgeFlags="right" />
-    </Row>
+    <include latin:keyboardLayout="@xml/kbd_symbols_shift_row4" />
 </Keyboard>
diff --git a/java/res/xml/kbd_symbols_shift_black.xml b/java/res/xml/kbd_symbols_shift_black.xml
deleted file mode 100644
index 52b67c3..0000000
--- a/java/res/xml/kbd_symbols_shift_black.xml
+++ /dev/null
@@ -1,177 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 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.
-*/
--->
-
-<Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="@dimen/key_bottom_gap"
-    android:keyHeight="@dimen/key_height"
->
-    <Row
-        android:rowEdgeFlags="top"
-    >
-        <Key
-            android:keyLabel="~"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="`" />
-        <Key
-            android:keyLabel="|" />
-        <Key
-            android:keyLabel="•"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="♪♥♠♦♣" />
-        <Key
-            android:keyLabel="√" />
-        <Key
-            android:keyLabel="π"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="Π" />
-        <Key
-            android:keyLabel="÷" />
-        <Key
-            android:keyLabel="×" />
-        <Key
-            android:keyLabel="{" />
-        <Key
-            android:keyLabel="}"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:codes="@integer/key_tab"
-            android:keyLabel="\u21E5"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="£" />
-        <Key
-            android:keyLabel="¢" />
-        <Key
-            android:keyLabel="€" />
-        <Key
-            android:keyLabel="°" />
-        <Key
-            android:keyLabel="^"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="↑↓←→" />
-        <Key
-            android:keyLabel="_" />
-        <Key
-            android:keyLabel="="
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="≠≈∞" />
-        <Key
-            android:keyLabel="[" />
-        <Key
-            android:keyLabel="]"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row>
-        <Key
-            android:codes="@integer/key_shift"
-            android:keyLabel="@string/label_alt_key"
-            android:keyWidth="15%p"
-            android:isModifier="true"
-            android:isSticky="true"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="™" />
-        <Key
-            android:keyLabel="®" />
-        <Key
-            android:keyLabel="©" />
-        <Key
-            android:keyLabel="¶"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="§" />
-        <Key
-            android:keyLabel="\\" />
-        <Key
-            android:keyLabel="&lt;"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="≤«‹" />
-        <Key
-            android:keyLabel="&gt;"
-            android:popupKeyboard="@xml/kbd_popup_template"
-            android:popupCharacters="≥»›" />
-        <Key
-            android:codes="@integer/key_delete"
-            android:keyIcon="@drawable/sym_bkeyboard_delete"
-            android:iconPreview="@drawable/sym_keyboard_feedback_delete"
-            android:keyWidth="15%p"
-            android:isRepeatable="true"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_symbols"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_alpha_key"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:keyLabel="„" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="40%p" />
-        <Key
-            android:keyLabel="…" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="20%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-    <Row
-        android:keyboardMode="@+id/mode_symbols_with_settings_key"
-        android:rowEdgeFlags="bottom"
-    >
-        <Key
-            android:codes="@integer/key_symbol"
-            android:keyLabel="@string/label_alpha_key"
-            android:keyWidth="15%p"
-            android:keyEdgeFlags="left" />
-        <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_bkeyboard_settings"
-            android:iconPreview="@drawable/sym_keyboard_feedback_settings" />
-        <Key
-            android:keyLabel="„" />
-        <Key
-            android:codes="@integer/key_space"
-            android:keyIcon="@drawable/sym_bkeyboard_space"
-            android:iconPreview="@drawable/sym_keyboard_feedback_space"
-            android:keyWidth="30%p" />
-        <Key
-            android:keyLabel="…" />
-        <Key
-            android:codes="@integer/key_return"
-            android:keyIcon="@drawable/sym_bkeyboard_return"
-            android:iconPreview="@drawable/sym_keyboard_feedback_return"
-            android:keyWidth="25%p"
-            android:keyEdgeFlags="right" />
-    </Row>
-</Keyboard>
diff --git a/java/res/xml/kbd_symbols_shift_row4.xml b/java/res/xml/kbd_symbols_shift_row4.xml
new file mode 100644
index 0000000..9159bab
--- /dev/null
+++ b/java/res/xml/kbd_symbols_shift_row4.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 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.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <Row
+        latin:rowEdgeFlags="bottom"
+    >
+        <switch>
+            <case
+                latin:hasSettingsKey="false"
+            >
+                <Key
+                    latin:keyStyle="toAlphaKeyStyle"
+                    latin:keyWidth="20%p"
+                    latin:keyEdgeFlags="left" />
+                <Key
+                    latin:keyLabel="„"
+                    latin:keyStyle="functionalKeyStyle" />
+                <Key
+                    latin:keyStyle="spaceKeyStyle"
+                    latin:keyWidth="40%p" />
+                <Key
+                    latin:keyLabel="…"
+                    latin:keyStyle="functionalKeyStyle" />
+                <switch>
+                    <case
+                        latin:mode="im"
+                    >
+                        <Key
+                            latin:keyStyle="smileyKeyStyle"
+                            latin:keyWidth="20%p"
+                            latin:keyEdgeFlags="right" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyStyle="returnKeyStyle"
+                            latin:keyWidth="20%p"
+                            latin:keyEdgeFlags="right" />
+                    </default>
+                </switch>
+            </case>
+            <case
+                latin:hasSettingsKey="true"
+            >
+                <Key
+                    latin:keyStyle="toAlphaKeyStyle"
+                    latin:keyWidth="15%p"
+                    latin:keyEdgeFlags="left" />
+                <Key
+                    latin:keyStyle="settingsKeyStyle" />
+                <Key
+                    latin:keyLabel="„"
+                    latin:keyStyle="functionalKeyStyle" />
+                <Key
+                    latin:keyStyle="spaceKeyStyle"
+                    latin:keyWidth="30%p" />
+                <Key
+                    latin:keyLabel="…"
+                    latin:keyStyle="functionalKeyStyle" />
+                <switch>
+                    <case
+                        latin:mode="im"
+                    >
+                        <Key
+                            latin:keyStyle="smileyKeyStyle"
+                            latin:keyWidth="25%p"
+                            latin:keyEdgeFlags="right" />
+                    </case>
+                    <default>
+                        <Key
+                            latin:keyStyle="returnKeyStyle"
+                            latin:keyWidth="25%p"
+                            latin:keyEdgeFlags="right" />
+                    </default>
+                </switch>
+            </case>
+        </switch>
+    </Row>
+</merge>
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index e5654e9..4ee60da 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -20,7 +20,178 @@
 <!-- The attributes in this XML file provide configuration information -->
 <!-- for the Input Method Manager. -->
 
+<!-- Keyboard: en_US, cs, da, de, en_GB, es, es_US, fr, fr_CA, fr_CH, it, nb, nl, sr, sv -->
+<!-- Voice: cs, da, de, en_AU, en_GB, en_IN, en_NZ, en_US, es, fr, ko, ja, pl, pt, ru, tr, zh_CN, zh_TW -->
+<!-- TODO: use <lang>_keyboard icon instead of a common keyboard icon. -->
+<!-- TODO: use <lang>_mic icon instead of a common mic icon. -->
 <input-method xmlns:android="http://schemas.android.com/apk/res/android"
         android:settingsActivity="com.android.inputmethod.latin.LatinIMESettings"
-        android:isDefault="@bool/im_is_default"
-/>
+        android:isDefault="@bool/im_is_default">
+    <!-- If IME doesn't have an applicable subtype, the first subtype will be used as a default
+         subtype.-->
+    <subtype android:icon="@drawable/ic_subtype_keyboard_en_us"
+            android:label="@string/subtype_mode_en_US_keyboard"
+            android:imeSubtypeLocale="en_US"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_cs"
+            android:label="@string/subtype_mode_cs_keyboard"
+            android:imeSubtypeLocale="cs"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_da"
+            android:label="@string/subtype_mode_da_keyboard"
+            android:imeSubtypeLocale="da"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_de"
+            android:label="@string/subtype_mode_de_keyboard"
+            android:imeSubtypeLocale="de"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_en_gb"
+            android:label="@string/subtype_mode_en_GB_keyboard"
+            android:imeSubtypeLocale="en_GB"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_es"
+            android:label="@string/subtype_mode_es_keyboard"
+            android:imeSubtypeLocale="es"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_es_us"
+            android:label="@string/subtype_mode_es_US_keyboard"
+            android:imeSubtypeLocale="es_US"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_fr"
+            android:label="@string/subtype_mode_fr_keyboard"
+            android:imeSubtypeLocale="fr"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_fr_ca"
+            android:label="@string/subtype_mode_fr_CA_keyboard"
+            android:imeSubtypeLocale="fr_CA"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_fr_ch"
+            android:label="@string/subtype_mode_fr_CH_keyboard"
+            android:imeSubtypeLocale="fr_CH"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_it"
+            android:label="@string/subtype_mode_it_keyboard"
+            android:imeSubtypeLocale="it"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_nb"
+            android:label="@string/subtype_mode_nb_keyboard"
+            android:imeSubtypeLocale="nb"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_nl"
+            android:label="@string/subtype_mode_nl_keyboard"
+            android:imeSubtypeLocale="nl"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_ru"
+            android:label="@string/subtype_mode_ru_keyboard"
+            android:imeSubtypeLocale="ru"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_sr"
+            android:label="@string/subtype_mode_sr_keyboard"
+            android:imeSubtypeLocale="sr"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard_sv"
+            android:label="@string/subtype_mode_sv_keyboard"
+            android:imeSubtypeLocale="sv"
+            android:imeSubtypeMode="keyboard"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_cs"
+            android:label="@string/subtype_mode_cs_voice"
+            android:imeSubtypeLocale="cs"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_de"
+            android:label="@string/subtype_mode_de_voice"
+            android:imeSubtypeLocale="de"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_en_au"
+            android:label="@string/subtype_mode_en_AU_voice"
+            android:imeSubtypeLocale="en_AU"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_en_gb"
+            android:label="@string/subtype_mode_en_GB_voice"
+            android:imeSubtypeLocale="en_GB"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_en_in"
+            android:label="@string/subtype_mode_en_IN_voice"
+            android:imeSubtypeLocale="en_IN"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_en_nz"
+            android:label="@string/subtype_mode_en_NZ_voice"
+            android:imeSubtypeLocale="en_NZ"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_en_us"
+            android:label="@string/subtype_mode_en_US_voice"
+            android:imeSubtypeLocale="en_US"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_es"
+            android:label="@string/subtype_mode_es_voice"
+            android:imeSubtypeLocale="es"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_fr"
+            android:label="@string/subtype_mode_fr_voice"
+            android:imeSubtypeLocale="fr"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_ko"
+            android:label="@string/subtype_mode_ko_voice"
+            android:imeSubtypeLocale="ko"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_ja"
+            android:label="@string/subtype_mode_ja_voice"
+            android:imeSubtypeLocale="ja"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_pl"
+            android:label="@string/subtype_mode_pl_voice"
+            android:imeSubtypeLocale="pl"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_pt"
+            android:label="@string/subtype_mode_pt_voice"
+            android:imeSubtypeLocale="pt"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_ru"
+            android:label="@string/subtype_mode_ru_voice"
+            android:imeSubtypeLocale="ru"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_tr"
+            android:label="@string/subtype_mode_tr_voice"
+            android:imeSubtypeLocale="tr"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_zh_cn"
+            android:label="@string/subtype_mode_zh_CN_voice"
+            android:imeSubtypeLocale="zh_CN"
+            android:imeSubtypeMode="voice"
+    />
+    <subtype android:icon="@drawable/ic_subtype_mic_zh_tw"
+            android:label="@string/subtype_mode_zh_TW_voice"
+            android:imeSubtypeLocale="zh_TW"
+            android:imeSubtypeMode="voice"
+    />
+</input-method>
diff --git a/java/res/xml/popup_at.xml b/java/res/xml/popup_at.xml
index 197eea4..4b19d4f 100644
--- a/java/res/xml/popup_at.xml
+++ b/java/res/xml/popup_at.xml
@@ -19,21 +19,21 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
-    android:keyHeight="@dimen/popup_key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
 >
     <Row
-        android:rowEdgeFlags="top|bottom"
+        latin:rowEdgeFlags="top|bottom"
     >
         <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:keyEdgeFlags="left" />
+            latin:codes="@integer/key_settings"
+            latin:keyIcon="@drawable/sym_keyboard_settings"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="\@"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="\@"
+            latin:keyEdgeFlags="right" />
     </Row>
 </Keyboard>
diff --git a/java/res/xml/popup_comma.xml b/java/res/xml/popup_comma.xml
index 7666f4b..cef836a 100644
--- a/java/res/xml/popup_comma.xml
+++ b/java/res/xml/popup_comma.xml
@@ -19,21 +19,21 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
-    android:keyHeight="@dimen/popup_key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
 >
     <Row
-        android:rowEdgeFlags="top|bottom"
+        latin:rowEdgeFlags="top|bottom"
     >
         <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:keyEdgeFlags="left" />
+            latin:codes="@integer/key_settings"
+            latin:keyIcon="@drawable/sym_keyboard_settings"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel=","
-            android:keyEdgeFlags="right" />
+            latin:keyLabel=","
+            latin:keyEdgeFlags="right" />
     </Row>
 </Keyboard>
diff --git a/java/res/xml/popup_domains.xml b/java/res/xml/popup_domains.xml
index 4e9789f..5f92e2f 100644
--- a/java/res/xml/popup_domains.xml
+++ b/java/res/xml/popup_domains.xml
@@ -19,28 +19,28 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="15%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
-    android:keyHeight="@dimen/popup_key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="15%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
 >
     <Row
-        android:rowEdgeFlags="top|bottom"
+        latin:rowEdgeFlags="top|bottom"
     >
         <Key
-            android:keyLabel="@string/popular_domain_1"
-            android:keyOutputText="@string/popular_domain_1"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel="@string/popular_domain_1"
+            latin:keyOutputText="@string/popular_domain_1"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="@string/popular_domain_2"
-            android:keyOutputText="@string/popular_domain_2" />
+            latin:keyLabel="@string/popular_domain_2"
+            latin:keyOutputText="@string/popular_domain_2" />
         <Key
-            android:keyLabel="@string/popular_domain_3"
-            android:keyOutputText="@string/popular_domain_3" />
+            latin:keyLabel="@string/popular_domain_3"
+            latin:keyOutputText="@string/popular_domain_3" />
         <Key
-            android:keyLabel="@string/popular_domain_4"
-            android:keyOutputText="@string/popular_domain_4"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="@string/popular_domain_4"
+            latin:keyOutputText="@string/popular_domain_4"
+            latin:keyEdgeFlags="right" />
     </Row>
 </Keyboard>
diff --git a/java/res/xml/popup_mic.xml b/java/res/xml/popup_mic.xml
index 5bbd7df..99c97ce 100644
--- a/java/res/xml/popup_mic.xml
+++ b/java/res/xml/popup_mic.xml
@@ -19,22 +19,22 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
-    android:keyHeight="@dimen/popup_key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
 >
     <Row
-        android:rowEdgeFlags="top|bottom"
+        latin:rowEdgeFlags="top|bottom"
     >
         <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:keyEdgeFlags="left" />
+            latin:codes="@integer/key_settings"
+            latin:keyIcon="@drawable/sym_keyboard_settings"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:codes="@integer/key_voice"
-            android:keyIcon="@drawable/sym_keyboard_mic"
-            android:keyEdgeFlags="right" />
+            latin:codes="@integer/key_voice"
+            latin:keyIcon="@drawable/sym_keyboard_mic"
+            latin:keyEdgeFlags="right" />
     </Row>
 </Keyboard>
diff --git a/java/res/xml/popup_punctuation.xml b/java/res/xml/popup_punctuation.xml
index c429e38..76572b0 100644
--- a/java/res/xml/popup_punctuation.xml
+++ b/java/res/xml/popup_punctuation.xml
@@ -19,50 +19,50 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
-    android:keyHeight="@dimen/popup_key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
 >
     <Row
-        android:rowEdgeFlags="top"
+        latin:rowEdgeFlags="top"
     >
         <Key
-            android:keyLabel=":"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel=":"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="/" />
+            latin:keyLabel="/" />
         <Key
-            android:keyLabel="&amp;" />
+            latin:keyLabel="&amp;" />
         <Key
-            android:keyLabel="(" />
+            latin:keyLabel="(" />
         <Key
-            android:keyLabel=")" />
+            latin:keyLabel=")" />
         <Key
-            android:keyLabel="-" />
+            latin:keyLabel="-" />
         <Key
-            android:keyLabel="+"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="+"
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row
-        android:rowEdgeFlags="bottom"
+        latin:rowEdgeFlags="bottom"
     >
         <Key
-            android:keyLabel=";"
-            android:keyEdgeFlags="left" />
+            latin:keyLabel=";"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="\@" />
+            latin:keyLabel="\@" />
         <Key
-            android:keyLabel="\'" />
+            latin:keyLabel="\'" />
         <Key
-            android:keyLabel="&quot;" />
+            latin:keyLabel="&quot;" />
         <Key
-            android:keyLabel="\?" />
+            latin:keyLabel="\?" />
         <Key
-            android:keyLabel="!" />
+            latin:keyLabel="!" />
         <Key
-            android:keyLabel=","
-            android:keyEdgeFlags="right" />
+            latin:keyLabel=","
+            latin:keyEdgeFlags="right" />
     </Row>
 </Keyboard>
diff --git a/java/res/xml/popup_slash.xml b/java/res/xml/popup_slash.xml
index a38fde0..1ace909 100644
--- a/java/res/xml/popup_slash.xml
+++ b/java/res/xml/popup_slash.xml
@@ -19,21 +19,21 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="10%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
-    android:keyHeight="@dimen/popup_key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="10%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
 >
     <Row
-        android:rowEdgeFlags="top|bottom"
+        latin:rowEdgeFlags="top|bottom"
     >
         <Key
-            android:codes="@integer/key_settings"
-            android:keyIcon="@drawable/sym_keyboard_settings"
-            android:keyEdgeFlags="left" />
+            latin:codes="@integer/key_settings"
+            latin:keyIcon="@drawable/sym_keyboard_settings"
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="/"
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="/"
+            latin:keyEdgeFlags="right" />
     </Row>
 </Keyboard>
diff --git a/java/res/xml/popup_smileys.xml b/java/res/xml/popup_smileys.xml
index 1a14e1d..2f08231 100644
--- a/java/res/xml/popup_smileys.xml
+++ b/java/res/xml/popup_smileys.xml
@@ -19,71 +19,71 @@
 -->
 
 <Keyboard
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:keyWidth="15%p"
-    android:horizontalGap="0px"
-    android:verticalGap="0px"
-    android:keyHeight="@dimen/popup_key_height"
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyWidth="15%p"
+    latin:horizontalGap="0px"
+    latin:verticalGap="0px"
+    latin:keyHeight="@dimen/popup_key_height"
 >
     <Row
-        android:rowEdgeFlags="top"
+        latin:rowEdgeFlags="top"
     >
         <Key
-            android:keyLabel=":-)"
-            android:keyOutputText=":-) "
-            android:keyEdgeFlags="left" />
+            latin:keyLabel=":-)"
+            latin:keyOutputText=":-) "
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel=":-("
-            android:keyOutputText=":-( " />
+            latin:keyLabel=":-("
+            latin:keyOutputText=":-( " />
         <Key
-            android:keyLabel=";-)"
-            android:keyOutputText=";-) " />
+            latin:keyLabel=";-)"
+            latin:keyOutputText=";-) " />
         <Key
-            android:keyLabel=":-P"
-            android:keyOutputText=":-P " />
+            latin:keyLabel=":-P"
+            latin:keyOutputText=":-P " />
         <Key
-            android:keyLabel="=-O"
-            android:keyOutputText="=-O "
-            android:keyEdgeFlags="right" />
+            latin:keyLabel="=-O"
+            latin:keyOutputText="=-O "
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row>
         <Key
-            android:keyLabel=":-*"
-            android:keyOutputText=":-* "
-            android:keyEdgeFlags="left" />
+            latin:keyLabel=":-*"
+            latin:keyOutputText=":-* "
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel=":O"
-            android:keyOutputText=":O " />
+            latin:keyLabel=":O"
+            latin:keyOutputText=":O " />
         <Key
-            android:keyLabel="B-)"
-            android:keyOutputText="B-) " />
+            latin:keyLabel="B-)"
+            latin:keyOutputText="B-) " />
         <Key
-            android:keyLabel=":-$"
-            android:keyOutputText=":-$ " />
+            latin:keyLabel=":-$"
+            latin:keyOutputText=":-$ " />
         <Key
-            android:keyLabel=":-!"
-            android:keyOutputText=":-! "
-            android:keyEdgeFlags="right" />
+            latin:keyLabel=":-!"
+            latin:keyOutputText=":-! "
+            latin:keyEdgeFlags="right" />
     </Row>
     <Row
-        android:rowEdgeFlags="bottom"
+        latin:rowEdgeFlags="bottom"
     >
         <Key
-            android:keyLabel=":-["
-            android:keyOutputText=":-[ "
-            android:keyEdgeFlags="left" />
+            latin:keyLabel=":-["
+            latin:keyOutputText=":-[ "
+            latin:keyEdgeFlags="left" />
         <Key
-            android:keyLabel="O:-)"
-            android:keyOutputText="O:-) " />
+            latin:keyLabel="O:-)"
+            latin:keyOutputText="O:-) " />
         <Key
-            android:keyLabel=":-\\"
-            android:keyOutputText=":-\\ " />
+            latin:keyLabel=":-\\"
+            latin:keyOutputText=":-\\ " />
         <Key
-            android:keyLabel=":'("
-            android:keyOutputText=":'( " />
+            latin:keyLabel=":'("
+            latin:keyOutputText=":'( " />
         <Key
-            android:keyLabel=":-D"
-            android:keyOutputText=":-D "
-            android:keyEdgeFlags="right" />
+            latin:keyLabel=":-D"
+            latin:keyOutputText=":-D "
+            latin:keyEdgeFlags="right" />
     </Row>
 </Keyboard>
diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml
index 9348e95..85612b0 100644
--- a/java/res/xml/prefs.xml
+++ b/java/res/xml/prefs.xml
@@ -70,12 +70,13 @@
             android:defaultValue="@string/voice_mode_main"
             />
 
-
+    <!-- TODO: Filter subtypes by IME in SubtypeEnabler -->
+    <!-- TODO: Maybe use this only for phone? -->
     <PreferenceScreen
             android:title="@string/language_selection_title"
             android:summary="@string/language_selection_summary">
         <intent
-                android:action="com.android.inputmethod.latin.INPUT_LANGUAGE_SELECTION"/>
+                android:action="android.settings.INPUT_METHOD_AND_SUBTYPE_ENABLER"/>
     </PreferenceScreen>
 
     <PreferenceCategory
@@ -90,22 +91,40 @@
             android:defaultValue="true"
             />
 
-        <CheckBoxPreference
-            android:key="show_suggestions"
-            android:title="@string/show_suggestions"
-            android:summary="@string/show_suggestions_summary"
+        <ListPreference
+            android:key="show_suggestions_setting"
+            android:summary="@string/prefs_show_suggestions_summary"
+            android:title="@string/prefs_show_suggestions"
             android:persistent="true"
-            android:defaultValue="true"
+            android:entryValues="@array/prefs_suggestion_visibility_values"
+            android:entries="@array/prefs_suggestion_visibilities"
+            android:defaultValue="@string/prefs_suggestion_visibility_default_value"
+            />
+
+        <ListPreference
+            android:key="auto_completion_threshold"
+            android:title="@string/auto_complete"
+            android:summary="@string/auto_complete_summary"
+            android:persistent="true"
+            android:entryValues="@array/auto_completion_threshold_mode_values"
+            android:entries="@array/auto_completion_threshold_modes"
+            android:defaultValue="@string/auto_completion_threshold_mode_value_modest"
             />
 
         <CheckBoxPreference
-            android:key="auto_complete"
-            android:title="@string/auto_complete"
-            android:summary="@string/auto_complete_summary"
-            android:persistent="true" 
-            android:defaultValue="@bool/enable_autocorrect"
-            android:dependency="show_suggestions"
+            android:key="bigram_suggestion"
+            android:title="@string/bigram_suggestion"
+            android:summary="@string/bigram_suggestion_summary"
+            android:persistent="true"
+            android:defaultValue="true"
             />
-    </PreferenceCategory>            
+    </PreferenceCategory>
+
+    <CheckBoxPreference
+            android:key="usability_study_mode"
+            android:title="@string/prefs_usability_study_mode"
+            android:persistent="true"
+            android:defaultValue="false"
+            />
 
 </PreferenceScreen>
diff --git a/java/res/xml/prefs_for_debug.xml b/java/res/xml/prefs_for_debug.xml
index 8177d3c..c42fe66 100644
--- a/java/res/xml/prefs_for_debug.xml
+++ b/java/res/xml/prefs_for_debug.xml
@@ -32,7 +32,7 @@
             android:persistent="true"
             android:entryValues="@array/keyboard_layout_modes_values"
             android:entries="@array/keyboard_layout_modes"
-            android:defaultValue="4"
+            android:defaultValue="5"
             />
 
     <CheckBoxPreference
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
new file mode 100644
index 0000000..87d128f
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 com.android.inputmethod.keyboard.KeyboardParser.ParseException;
+import com.android.inputmethod.keyboard.KeyStyles.KeyStyle;
+import com.android.inputmethod.latin.R;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
+import android.util.Xml;
+
+/**
+ * Class for describing the position and characteristics of a single key in the keyboard.
+ */
+public class Key {
+    /**
+     * All the key codes (unicode or custom code) that this key could generate, zero'th
+     * being the most important.
+     */
+    public final int[] mCodes;
+    /** The unicode that this key generates in manual temporary upper case mode. */
+    public final int mManualTemporaryUpperCaseCode;
+
+    /** Label to display */
+    public final CharSequence mLabel;
+    /** Option of the label */
+    public final int mLabelOption;
+
+    /** Icon to display instead of a label. Icon takes precedence over a label */
+    private Drawable mIcon;
+    /** Preview version of the icon, for the preview popup */
+    private Drawable mPreviewIcon;
+    /** Hint icon to display on the key in conjunction with the label */
+    public final Drawable mHintIcon;
+    /**
+     * The hint icon to display on the key when keyboard is in manual temporary upper case
+     * mode.
+     */
+    public final Drawable mManualTemporaryUpperCaseHintIcon;
+
+    /** Width of the key, not including the gap */
+    public final int mWidth;
+    /** Height of the key, not including the gap */
+    public final int mHeight;
+    /** The horizontal gap before this key */
+    public final int mGap;
+    /** Whether this key is sticky, i.e., a toggle key */
+    public final boolean mSticky;
+    /** X coordinate of the key in the keyboard layout */
+    public final int mX;
+    /** Y coordinate of the key in the keyboard layout */
+    public final int mY;
+    /** Text to output when pressed. This can be multiple characters, like ".com" */
+    public final CharSequence mOutputText;
+    /** Popup characters */
+    public final CharSequence mPopupCharacters;
+    /**
+     * If this key pops up a mini keyboard, this is the resource id for the XML layout for that
+     * keyboard.
+     */
+    public final int mPopupResId;
+
+    /**
+     * Flags that specify the anchoring to edges of the keyboard for detecting touch events
+     * that are just out of the boundary of the key. This is a bit mask of
+     * {@link Keyboard#EDGE_LEFT}, {@link Keyboard#EDGE_RIGHT},
+     * {@link Keyboard#EDGE_TOP} and {@link Keyboard#EDGE_BOTTOM}.
+     */
+    public final int mEdgeFlags;
+    /** Whether this is a modifier key, such as Shift or Alt */
+    public final boolean mModifier;
+    /** Whether this key repeats itself when held down */
+    public final boolean mRepeatable;
+
+    /** The Keyboard that this key belongs to */
+    private final Keyboard mKeyboard;
+
+    /** The current pressed state of this key */
+    public boolean mPressed;
+    /** If this is a sticky key, is it on? */
+    public boolean mOn;
+
+    private final static int[] KEY_STATE_NORMAL_ON = {
+        android.R.attr.state_checkable,
+        android.R.attr.state_checked
+    };
+
+    private final static int[] KEY_STATE_PRESSED_ON = {
+        android.R.attr.state_pressed,
+        android.R.attr.state_checkable,
+        android.R.attr.state_checked
+    };
+
+    private final static int[] KEY_STATE_NORMAL_OFF = {
+        android.R.attr.state_checkable
+    };
+
+    private final static int[] KEY_STATE_PRESSED_OFF = {
+        android.R.attr.state_pressed,
+        android.R.attr.state_checkable
+    };
+
+    private final static int[] KEY_STATE_NORMAL = {
+    };
+
+    private final static int[] KEY_STATE_PRESSED = {
+        android.R.attr.state_pressed
+    };
+
+    // functional normal state (with properties)
+    private static final int[] KEY_STATE_FUNCTIONAL_NORMAL = {
+            android.R.attr.state_single
+    };
+
+    // functional pressed state (with properties)
+    private static final int[] KEY_STATE_FUNCTIONAL_PRESSED = {
+            android.R.attr.state_single,
+            android.R.attr.state_pressed
+    };
+
+    /** Create an empty key with no attributes. */
+    public Key(Row row, char letter, int x, int y) {
+        mKeyboard = row.getKeyboard();
+        mHeight = row.mDefaultHeight;
+        mGap = row.mDefaultHorizontalGap;
+        mWidth = row.mDefaultWidth - mGap;
+        mEdgeFlags = row.mRowEdgeFlags;
+        mHintIcon = null;
+        mManualTemporaryUpperCaseHintIcon = null;
+        mManualTemporaryUpperCaseCode = 0;
+        mLabelOption = 0;
+        mModifier = false;
+        mSticky = false;
+        mRepeatable = false;
+        mOutputText = null;
+        mPopupCharacters = null;
+        mPopupResId = 0;
+        mLabel = String.valueOf(letter);
+        mCodes = new int[] { letter };
+        // Horizontal gap is divided equally to both sides of the key.
+        mX = x + mGap / 2;
+        mY = y;
+    }
+
+    /** Create a key with the given top-left coordinate and extract its attributes from
+     * the XML parser.
+     * @param res resources associated with the caller's context
+     * @param row the row that this key belongs to. The row must already be attached to
+     * a {@link Keyboard}.
+     * @param x the x coordinate of the top-left
+     * @param y the y coordinate of the top-left
+     * @param parser the XML parser containing the attributes for this key
+     */
+    public Key(Resources res, Row row, int x, int y, XmlResourceParser parser,
+            KeyStyles keyStyles) {
+        mKeyboard = row.getKeyboard();
+
+        TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser),
+                R.styleable.Keyboard);
+        mHeight = KeyboardParser.getDimensionOrFraction(a,
+                R.styleable.Keyboard_keyHeight,
+                mKeyboard.getKeyboardHeight(), row.mDefaultHeight);
+        mGap = KeyboardParser.getDimensionOrFraction(a,
+                R.styleable.Keyboard_horizontalGap,
+                mKeyboard.getKeyboardWidth(), row.mDefaultHorizontalGap);
+        mWidth = KeyboardParser.getDimensionOrFraction(a,
+                R.styleable.Keyboard_keyWidth,
+                mKeyboard.getKeyboardWidth(), row.mDefaultWidth) - mGap;
+        a.recycle();
+
+        a = res.obtainAttributes(Xml.asAttributeSet(parser), R.styleable.Keyboard_Key);
+
+        final KeyStyle style;
+        if (a.hasValue(R.styleable.Keyboard_Key_keyStyle)) {
+            String styleName = a.getString(R.styleable.Keyboard_Key_keyStyle);
+            style = keyStyles.getKeyStyle(styleName);
+            if (style == null)
+                throw new ParseException("Unknown key style: " + styleName, parser);
+        } else {
+            style = keyStyles.getEmptyKeyStyle();
+        }
+
+        // Horizontal gap is divided equally to both sides of the key.
+        this.mX = x + mGap / 2;
+        this.mY = y;
+
+        int[] codes = style.getIntArray(a, R.styleable.Keyboard_Key_codes);
+        mPreviewIcon = style.getDrawable(a, R.styleable.Keyboard_Key_iconPreview);
+        Keyboard.setDefaultBounds(mPreviewIcon);
+        mPopupCharacters = style.getText(a, R.styleable.Keyboard_Key_popupCharacters);
+        mPopupResId = style.getResourceId(a, R.styleable.Keyboard_Key_popupKeyboard, 0);
+        mRepeatable = style.getBoolean(a, R.styleable.Keyboard_Key_isRepeatable, false);
+        mModifier = style.getBoolean(a, R.styleable.Keyboard_Key_isModifier, false);
+        mSticky = style.getBoolean(a, R.styleable.Keyboard_Key_isSticky, false);
+        mEdgeFlags = style.getFlag(a, R.styleable.Keyboard_Key_keyEdgeFlags, 0)
+                | row.mRowEdgeFlags;
+
+        mIcon = style.getDrawable(a, R.styleable.Keyboard_Key_keyIcon);
+        Keyboard.setDefaultBounds(mIcon);
+        mHintIcon = style.getDrawable(a, R.styleable.Keyboard_Key_keyHintIcon);
+        Keyboard.setDefaultBounds(mHintIcon);
+        mManualTemporaryUpperCaseHintIcon = style.getDrawable(a,
+                R.styleable.Keyboard_Key_manualTemporaryUpperCaseHintIcon);
+        Keyboard.setDefaultBounds(mManualTemporaryUpperCaseHintIcon);
+
+        mLabel = style.getText(a, R.styleable.Keyboard_Key_keyLabel);
+        mLabelOption = style.getFlag(a, R.styleable.Keyboard_Key_keyLabelOption, 0);
+        mManualTemporaryUpperCaseCode = style.getInt(a,
+                R.styleable.Keyboard_Key_manualTemporaryUpperCaseCode, 0);
+        mOutputText = style.getText(a, R.styleable.Keyboard_Key_keyOutputText);
+        final Drawable shiftedIcon = style.getDrawable(a,
+                R.styleable.Keyboard_Key_shiftedIcon);
+        a.recycle();
+
+        if (shiftedIcon != null)
+            mKeyboard.getShiftedIcons().put(this, shiftedIcon);
+
+        if (codes == null && !TextUtils.isEmpty(mLabel))
+            codes = new int[] { mLabel.charAt(0) };
+        mCodes = codes;
+    }
+
+    public Drawable getIcon() {
+        return mIcon;
+    }
+
+    public Drawable getPreviewIcon() {
+        return mPreviewIcon;
+    }
+
+    public void setIcon(Drawable icon) {
+        mIcon = icon;
+    }
+
+    public void setPreviewIcon(Drawable icon) {
+        mPreviewIcon = icon;
+    }
+
+    /**
+     * Informs the key that it has been pressed, in case it needs to change its appearance or
+     * state.
+     * @see #onReleased(boolean)
+     */
+    public void onPressed() {
+        mPressed = !mPressed;
+    }
+
+    /**
+     * Changes the pressed state of the key. If it is a sticky key, it will also change the
+     * toggled state of the key if the finger was release inside.
+     * @param inside whether the finger was released inside the key
+     * @see #onPressed()
+     */
+    public void onReleased(boolean inside) {
+        mPressed = !mPressed;
+        if (mSticky && !mKeyboard.isShiftLockEnabled(this))
+            mOn = !mOn;
+    }
+
+    public boolean isInside(int x, int y) {
+        return mKeyboard.isInside(this, x, y);
+    }
+
+    /**
+     * Detects if a point falls on this key.
+     * @param x the x-coordinate of the point
+     * @param y the y-coordinate of the point
+     * @return whether or not the point falls on the key. If the key is attached to an edge, it will
+     * assume that all points between the key and the edge are considered to be on the key.
+     */
+    public boolean isOnKey(int x, int y) {
+        final int flags = mEdgeFlags;
+        final boolean leftEdge = (flags & Keyboard.EDGE_LEFT) != 0;
+        final boolean rightEdge = (flags & Keyboard.EDGE_RIGHT) != 0;
+        final boolean topEdge = (flags & Keyboard.EDGE_TOP) != 0;
+        final boolean bottomEdge = (flags & Keyboard.EDGE_BOTTOM) != 0;
+        final int left = this.mX;
+        final int right = left + this.mWidth;
+        final int top = this.mY;
+        final int bottom = top + this.mHeight;
+        return (x >= left || leftEdge) && (x < right || rightEdge)
+                && (y >= top || topEdge) && (y < bottom || bottomEdge);
+    }
+
+    /**
+     * Returns the square of the distance to the nearest edge of the key and the given point.
+     * @param x the x-coordinate of the point
+     * @param y the y-coordinate of the point
+     * @return the square of the distance of the point from the nearest edge of the key
+     */
+    public int squaredDistanceToEdge(int x, int y) {
+        final int left = this.mX;
+        final int right = left + this.mWidth;
+        final int top = this.mY;
+        final int bottom = top + this.mHeight;
+        final int edgeX = x < left ? left : (x > right ? right : x);
+        final int edgeY = y < top ? top : (y > bottom ? bottom : y);
+        final int dx = x - edgeX;
+        final int dy = y - edgeY;
+        return dx * dx + dy * dy;
+    }
+
+    // sticky is used for shift key.  If a key is not sticky and is modifier,
+    // the key will be treated as functional.
+    private boolean isFunctionalKey() {
+        return !mSticky && mModifier;
+    }
+
+    /**
+     * Returns the drawable state for the key, based on the current state and type of the key.
+     * @return the drawable state of the key.
+     * @see android.graphics.drawable.StateListDrawable#setState(int[])
+     */
+    public int[] getCurrentDrawableState() {
+        if (isFunctionalKey()) {
+            if (mPressed) {
+                return KEY_STATE_FUNCTIONAL_PRESSED;
+            } else {
+                return KEY_STATE_FUNCTIONAL_NORMAL;
+            }
+        }
+
+        int[] states = KEY_STATE_NORMAL;
+
+        if (mOn) {
+            if (mPressed) {
+                states = KEY_STATE_PRESSED_ON;
+            } else {
+                states = KEY_STATE_NORMAL_ON;
+            }
+        } else {
+            if (mSticky) {
+                if (mPressed) {
+                    states = KEY_STATE_PRESSED_OFF;
+                } else {
+                    states = KEY_STATE_NORMAL_OFF;
+                }
+            } else {
+                if (mPressed) {
+                    states = KEY_STATE_PRESSED;
+                }
+            }
+        }
+        return states;
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
similarity index 94%
rename from java/src/com/android/inputmethod/latin/KeyDetector.java
rename to java/src/com/android/inputmethod/keyboard/KeyDetector.java
index 76fe120..777a795 100644
--- a/java/src/com/android/inputmethod/latin/KeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
@@ -14,15 +14,14 @@
  * the License.
  */
 
-package com.android.inputmethod.latin;
-
-import android.inputmethodservice.Keyboard;
-import android.inputmethodservice.Keyboard.Key;
+package com.android.inputmethod.keyboard;
 
 import java.util.Arrays;
 import java.util.List;
 
-abstract class KeyDetector {
+public abstract class KeyDetector {
+    public static final int NOT_A_KEY = -1;
+
     protected Keyboard mKeyboard;
 
     private Key[] mKeys;
@@ -85,7 +84,7 @@
      */
     public int[] newCodeArray() {
         int[] codes = new int[getMaxNearbyKeys()];
-        Arrays.fill(codes, LatinKeyboardBaseView.NOT_A_KEY);
+        Arrays.fill(codes, NOT_A_KEY);
         return codes;
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/KeyStyles.java
new file mode 100644
index 0000000..daa9c86
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/KeyStyles.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 com.android.inputmethod.keyboard.KeyboardParser.ParseException;
+import com.android.inputmethod.latin.R;
+
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.util.TypedValue;
+
+import java.util.HashMap;
+import java.util.StringTokenizer;
+
+public class KeyStyles {
+    private static final String TAG = "KeyStyles";
+
+    private final HashMap<String, DeclaredKeyStyle> mStyles =
+            new HashMap<String, DeclaredKeyStyle>();
+    private static final KeyStyle EMPTY_KEY_STYLE = new EmptyKeyStyle();
+
+    public interface KeyStyle {
+        public int[] getIntArray(TypedArray a, int index);
+        public Drawable getDrawable(TypedArray a, int index);
+        public CharSequence getText(TypedArray a, int index);
+        public int getResourceId(TypedArray a, int index, int defaultValue);
+        public int getInt(TypedArray a, int index, int defaultValue);
+        public int getFlag(TypedArray a, int index, int defaultValue);
+        public boolean getBoolean(TypedArray a, int index, boolean defaultValue);
+    }
+
+    public static class EmptyKeyStyle implements KeyStyle {
+        private EmptyKeyStyle() {
+        }
+
+        @Override
+        public int[] getIntArray(TypedArray a, int index) {
+            return parseIntArray(a, index);
+        }
+
+        @Override
+        public Drawable getDrawable(TypedArray a, int index) {
+            return a.getDrawable(index);
+        }
+
+        @Override
+        public CharSequence getText(TypedArray a, int index) {
+            return a.getText(index);
+        }
+
+        @Override
+        public int getResourceId(TypedArray a, int index, int defaultValue) {
+            return a.getResourceId(index, defaultValue);
+        }
+
+        @Override
+        public int getInt(TypedArray a, int index, int defaultValue) {
+            return a.getInt(index, defaultValue);
+        }
+
+        @Override
+        public int getFlag(TypedArray a, int index, int defaultValue) {
+            return a.getInt(index, defaultValue);
+        }
+
+        @Override
+        public boolean getBoolean(TypedArray a, int index, boolean defaultValue) {
+            return a.getBoolean(index, defaultValue);
+        }
+
+        protected static int[] parseIntArray(TypedArray a, int index) {
+            TypedValue v = new TypedValue();
+            a.getValue(index, v);
+            if (v.type == TypedValue.TYPE_INT_DEC || v.type == TypedValue.TYPE_INT_HEX) {
+                return new int[] { v.data };
+            } else if (v.type == TypedValue.TYPE_STRING) {
+                return parseCSV(v.string.toString());
+            } else {
+                return null;
+            }
+        }
+
+        private static int[] parseCSV(String value) {
+            int count = 0;
+            int lastIndex = 0;
+            if (value.length() > 0) {
+                count++;
+                while ((lastIndex = value.indexOf(",", lastIndex + 1)) > 0) {
+                    count++;
+                }
+            }
+            int[] values = new int[count];
+            count = 0;
+            StringTokenizer st = new StringTokenizer(value, ",");
+            while (st.hasMoreTokens()) {
+                try {
+                    values[count++] = Integer.parseInt(st.nextToken());
+                } catch (NumberFormatException nfe) {
+                    Log.w(TAG, "Error parsing integer CSV " + value);
+                }
+            }
+            return values;
+        }
+    }
+
+    public static class DeclaredKeyStyle extends EmptyKeyStyle {
+        private final HashMap<Integer, Object> mAttributes = new HashMap<Integer, Object>();
+
+        @Override
+        public int[] getIntArray(TypedArray a, int index) {
+            return a.hasValue(index)
+                    ? super.getIntArray(a, index) : (int[])mAttributes.get(index);
+        }
+
+        @Override
+        public Drawable getDrawable(TypedArray a, int index) {
+            return a.hasValue(index)
+                    ? super.getDrawable(a, index) : (Drawable)mAttributes.get(index);
+        }
+
+        @Override
+        public CharSequence getText(TypedArray a, int index) {
+            return a.hasValue(index)
+                    ? super.getText(a, index) : (CharSequence)mAttributes.get(index);
+        }
+
+        @Override
+        public int getResourceId(TypedArray a, int index, int defaultValue) {
+            final Integer value = (Integer)mAttributes.get(index);
+            return super.getResourceId(a, index, (value != null) ? value : defaultValue);
+        }
+
+        @Override
+        public int getFlag(TypedArray a, int index, int defaultValue) {
+            final Integer value = (Integer)mAttributes.get(index);
+            return super.getFlag(a, index, defaultValue) | (value != null ? value : 0);
+        }
+
+        @Override
+        public boolean getBoolean(TypedArray a, int index, boolean defaultValue) {
+            final Boolean value = (Boolean)mAttributes.get(index);
+            return super.getBoolean(a, index, (value != null) ? value : defaultValue);
+        }
+
+        private DeclaredKeyStyle() {
+            super();
+        }
+
+        private void parseKeyStyleAttributes(TypedArray a) {
+            // TODO: Currently not all Key attributes can be declared as style.
+            readIntArray(a, R.styleable.Keyboard_Key_codes);
+            readText(a, R.styleable.Keyboard_Key_keyLabel);
+            readFlag(a, R.styleable.Keyboard_Key_keyLabelOption);
+            readText(a, R.styleable.Keyboard_Key_keyOutputText);
+            readDrawable(a, R.styleable.Keyboard_Key_keyIcon);
+            readDrawable(a, R.styleable.Keyboard_Key_iconPreview);
+            readDrawable(a, R.styleable.Keyboard_Key_keyHintIcon);
+            readDrawable(a, R.styleable.Keyboard_Key_shiftedIcon);
+            readResourceId(a, R.styleable.Keyboard_Key_popupKeyboard);
+            readBoolean(a, R.styleable.Keyboard_Key_isModifier);
+            readBoolean(a, R.styleable.Keyboard_Key_isSticky);
+            readBoolean(a, R.styleable.Keyboard_Key_isRepeatable);
+        }
+
+        private void readDrawable(TypedArray a, int index) {
+            if (a.hasValue(index))
+                mAttributes.put(index, a.getDrawable(index));
+        }
+
+        private void readText(TypedArray a, int index) {
+            if (a.hasValue(index))
+                mAttributes.put(index, a.getText(index));
+        }
+
+        private void readResourceId(TypedArray a, int index) {
+            if (a.hasValue(index))
+                mAttributes.put(index, a.getResourceId(index, 0));
+        }
+
+        private void readFlag(TypedArray a, int index) {
+            final Integer value = (Integer)mAttributes.get(index);
+            if (a.hasValue(index))
+                mAttributes.put(index, a.getInt(index, 0) | (value != null ? value : 0));
+        }
+
+        private void readBoolean(TypedArray a, int index) {
+            if (a.hasValue(index))
+                mAttributes.put(index, a.getBoolean(index, false));
+        }
+
+        private void readIntArray(TypedArray a, int index) {
+            if (a.hasValue(index)) {
+                final int[] value = parseIntArray(a, index);
+                if (value != null)
+                    mAttributes.put(index, value);
+            }
+        }
+
+        private void addParent(DeclaredKeyStyle parentStyle) {
+            mAttributes.putAll(parentStyle.mAttributes);
+        }
+    }
+
+    public void parseKeyStyleAttributes(TypedArray a, TypedArray keyAttrs,
+            XmlResourceParser parser) {
+        String styleName = a.getString(R.styleable.Keyboard_KeyStyle_styleName);
+        if (mStyles.containsKey(styleName))
+            throw new ParseException("duplicate key style declared: " + styleName, parser);
+
+        final DeclaredKeyStyle style = new DeclaredKeyStyle();
+        if (a.hasValue(R.styleable.Keyboard_KeyStyle_parentStyle)) {
+            String parentStyle = a.getString(
+                    R.styleable.Keyboard_KeyStyle_parentStyle);
+            final DeclaredKeyStyle parent = mStyles.get(parentStyle);
+            if (parent == null)
+                throw new ParseException("Unknown parentStyle " + parent, parser);
+            style.addParent(parent);
+        }
+        style.parseKeyStyleAttributes(keyAttrs);
+        mStyles.put(styleName, style);
+    }
+
+    public KeyStyle getKeyStyle(String styleName) {
+        return mStyles.get(styleName);
+    }
+
+    public KeyStyle getEmptyKeyStyle() {
+        return EMPTY_KEY_STYLE;
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
new file mode 100644
index 0000000..6a1d62e
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 com.android.inputmethod.latin.R;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Loads an XML description of a keyboard and stores the attributes of the keys. A keyboard
+ * consists of rows of keys.
+ * <p>The layout file for a keyboard contains XML that looks like the following snippet:</p>
+ * <pre>
+ * &lt;Keyboard
+ *         latin:keyWidth="%10p"
+ *         latin:keyHeight="50px"
+ *         latin:horizontalGap="2px"
+ *         latin:verticalGap="2px" &gt;
+ *     &lt;Row latin:keyWidth="32px" &gt;
+ *         &lt;Key latin:keyLabel="A" /&gt;
+ *         ...
+ *     &lt;/Row&gt;
+ *     ...
+ * &lt;/Keyboard&gt;
+ * </pre>
+ */
+public class Keyboard {
+    private static final String TAG = "Keyboard";
+
+    public static final int EDGE_LEFT = 0x01;
+    public static final int EDGE_RIGHT = 0x02;
+    public static final int EDGE_TOP = 0x04;
+    public static final int EDGE_BOTTOM = 0x08;
+
+    /** Some common keys code.  These should be aligned with values/keycodes.xml */
+    public static final int CODE_ENTER = '\n';
+    public static final int CODE_TAB = '\t';
+    public static final int CODE_SPACE = ' ';
+    public static final int CODE_PERIOD = '.';
+
+    /** Special keys code.  These should be aligned with values/keycodes.xml */
+    public static final int CODE_SHIFT = -1;
+    public static final int CODE_SWITCH_ALPHA_SYMBOL = -2;
+    public static final int CODE_CANCEL = -3;
+    public static final int CODE_DONE = -4;
+    public static final int CODE_DELETE = -5;
+    public static final int CODE_ALT = -6;
+    public static final int CODE_SETTINGS = -100;
+    public static final int CODE_SETTINGS_LONGPRESS = -101;
+    // TODO: remove this once LatinIME stops referring to this.
+    public static final int CODE_VOICE = -102;
+    public static final int CODE_CAPSLOCK = -103;
+    public static final int CODE_NEXT_LANGUAGE = -104;
+    public static final int CODE_PREV_LANGUAGE = -105;
+
+    /** Horizontal gap default for all rows */
+    private int mDefaultHorizontalGap;
+
+    /** Default key width */
+    private int mDefaultWidth;
+
+    /** Default key height */
+    private int mDefaultHeight;
+
+    /** Default gap between rows */
+    private int mDefaultVerticalGap;
+
+    /** List of shift keys in this keyboard and its icons and state */
+    private final List<Key> mShiftKeys = new ArrayList<Key>();
+    private final HashMap<Key, Drawable> mShiftedIcons = new HashMap<Key, Drawable>();
+    private final HashMap<Key, Drawable> mNormalShiftIcons = new HashMap<Key, Drawable>();
+    private final HashSet<Key> mShiftLockEnabled = new HashSet<Key>();
+    private final KeyboardShiftState mShiftState = new KeyboardShiftState();
+
+    /** Space key and its icons */
+    protected Key mSpaceKey;
+    protected Drawable mSpaceIcon;
+    protected Drawable mSpacePreviewIcon;
+
+    /** Total height of the keyboard, including the padding and keys */
+    private int mTotalHeight;
+
+    /**
+     * Total width of the keyboard, including left side gaps and keys, but not any gaps on the
+     * right side.
+     */
+    private int mTotalWidth;
+
+    /** List of keys in this keyboard */
+    private final List<Key> mKeys = new ArrayList<Key>();
+
+    /** Width of the screen available to fit the keyboard */
+    private final int mDisplayWidth;
+
+    /** Height of the screen */
+    private final int mDisplayHeight;
+
+    public final KeyboardId mId;
+
+    // Variables for pre-computing nearest keys.
+
+    public final int GRID_WIDTH;
+    public final int GRID_HEIGHT;
+    private final int GRID_SIZE;
+    private int mCellWidth;
+    private int mCellHeight;
+    private int[][] mGridNeighbors;
+    private int mProximityThreshold;
+    private static int[] EMPTY_INT_ARRAY = new int[0];
+    /** Number of key widths from current touch point to search for nearest keys. */
+    private static float SEARCH_DISTANCE = 1.2f;
+
+    /**
+     * Creates a keyboard from the given xml key layout file.
+     * @param context the application or service context
+     * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
+     */
+    public Keyboard(Context context, int xmlLayoutResId) {
+        this(context, xmlLayoutResId, null);
+    }
+
+    /**
+     * Creates a keyboard from the given keyboard identifier.
+     * @param context the application or service context
+     * @param id keyboard identifier
+     */
+    public Keyboard(Context context, KeyboardId id) {
+        this(context, id.getXmlId(), id);
+    }
+
+    /**
+     * Creates a keyboard from the given xml key layout file.
+     * @param context the application or service context
+     * @param xmlLayoutResId the resource file that contains the keyboard layout and keys.
+     * @param id keyboard identifier
+     */
+    private Keyboard(Context context, int xmlLayoutResId, KeyboardId id) {
+        this(context, xmlLayoutResId, id,
+                context.getResources().getDisplayMetrics().widthPixels,
+                context.getResources().getDisplayMetrics().heightPixels);
+    }
+
+    private Keyboard(Context context, int xmlLayoutResId, KeyboardId id, int width,
+            int height) {
+        Resources res = context.getResources();
+        GRID_WIDTH = res.getInteger(R.integer.config_keyboard_grid_width);
+        GRID_HEIGHT = res.getInteger(R.integer.config_keyboard_grid_height);
+        GRID_SIZE = GRID_WIDTH * GRID_HEIGHT;
+
+        mDisplayWidth = width;
+        mDisplayHeight = height;
+
+        mDefaultHorizontalGap = 0;
+        setKeyWidth(mDisplayWidth / 10);
+        mDefaultVerticalGap = 0;
+        mDefaultHeight = mDefaultWidth;
+        mId = id;
+        loadKeyboard(context, xmlLayoutResId);
+    }
+
+    /**
+     * <p>Creates a blank keyboard from the given resource file and populates it with the specified
+     * characters in left-to-right, top-to-bottom fashion, using the specified number of columns.
+     * </p>
+     * <p>If the specified number of columns is -1, then the keyboard will fit as many keys as
+     * possible in each row.</p>
+     * @param context the application or service context
+     * @param layoutTemplateResId the layout template file, containing no keys.
+     * @param characters the list of characters to display on the keyboard. One key will be created
+     * for each character.
+     * @param columns the number of columns of keys to display. If this number is greater than the
+     * number of keys that can fit in a row, it will be ignored. If this number is -1, the
+     * keyboard will fit as many keys as possible in each row.
+     */
+    public Keyboard(Context context, int layoutTemplateResId,
+            CharSequence characters, int columns, int horizontalPadding) {
+        this(context, layoutTemplateResId);
+        int x = 0;
+        int y = 0;
+        int column = 0;
+        mTotalWidth = 0;
+
+        final Row row = new Row(this);
+        final int maxColumns = columns == -1 ? Integer.MAX_VALUE : columns;
+        for (int i = 0; i < characters.length(); i++) {
+            char c = characters.charAt(i);
+            if (column >= maxColumns
+                    || x + mDefaultWidth + horizontalPadding > mDisplayWidth) {
+                x = 0;
+                y += mDefaultVerticalGap + mDefaultHeight;
+                column = 0;
+            }
+            final Key key = new Key(row, c, x, y);
+            column++;
+            x += key.mWidth + key.mGap;
+            mKeys.add(key);
+            if (x > mTotalWidth) {
+                mTotalWidth = x;
+            }
+        }
+        mTotalHeight = y + mDefaultHeight;
+    }
+
+    public List<Key> getKeys() {
+        return mKeys;
+    }
+
+    public int getHorizontalGap() {
+        return mDefaultHorizontalGap;
+    }
+
+    public void setHorizontalGap(int gap) {
+        mDefaultHorizontalGap = gap;
+    }
+
+    public int getVerticalGap() {
+        return mDefaultVerticalGap;
+    }
+
+    public void setVerticalGap(int gap) {
+        mDefaultVerticalGap = gap;
+    }
+
+    public int getKeyHeight() {
+        return mDefaultHeight;
+    }
+
+    public void setKeyHeight(int height) {
+        mDefaultHeight = height;
+    }
+
+    public int getKeyWidth() {
+        return mDefaultWidth;
+    }
+
+    public void setKeyWidth(int width) {
+        mDefaultWidth = width;
+        final int threshold = (int) (width * SEARCH_DISTANCE);
+        mProximityThreshold = threshold * threshold;
+    }
+
+    /**
+     * Returns the total height of the keyboard
+     * @return the total height of the keyboard
+     */
+    public int getHeight() {
+        return mTotalHeight;
+    }
+
+    public int getMinWidth() {
+        return mTotalWidth;
+    }
+
+    public int getKeyboardHeight() {
+        return mDisplayHeight;
+    }
+
+    public int getKeyboardWidth() {
+        return mDisplayWidth;
+    }
+
+    public List<Key> getShiftKeys() {
+        return mShiftKeys;
+    }
+
+    public Map<Key, Drawable> getShiftedIcons() {
+        return mShiftedIcons;
+    }
+
+    public void enableShiftLock() {
+        for (final Key key : getShiftKeys()) {
+            mShiftLockEnabled.add(key);
+            mNormalShiftIcons.put(key, key.getIcon());
+        }
+    }
+
+    public boolean isShiftLockEnabled(Key key) {
+        return mShiftLockEnabled.contains(key);
+    }
+
+    public boolean setShiftLocked(boolean newShiftLockState) {
+        final Map<Key, Drawable> shiftedIcons = getShiftedIcons();
+        for (final Key key : getShiftKeys()) {
+            key.mOn = newShiftLockState;
+            key.setIcon(newShiftLockState ? shiftedIcons.get(key) : mNormalShiftIcons.get(key));
+        }
+        mShiftState.setShiftLocked(newShiftLockState);
+        return true;
+    }
+
+    public boolean isShiftLocked() {
+        return mShiftState.isShiftLocked();
+    }
+
+    public boolean setShifted(boolean newShiftState) {
+        final Map<Key, Drawable> shiftedIcons = getShiftedIcons();
+        for (final Key key : getShiftKeys()) {
+            if (!newShiftState && !mShiftState.isShiftLocked()) {
+                key.setIcon(mNormalShiftIcons.get(key));
+            } else if (newShiftState && !mShiftState.isShiftedOrShiftLocked()) {
+                key.setIcon(shiftedIcons.get(key));
+            }
+        }
+        return mShiftState.setShifted(newShiftState);
+    }
+
+    public boolean isShiftedOrShiftLocked() {
+        return mShiftState.isShiftedOrShiftLocked();
+    }
+
+    public void setAutomaticTemporaryUpperCase() {
+        setShifted(true);
+        mShiftState.setAutomaticTemporaryUpperCase();
+    }
+
+    public boolean isAutomaticTemporaryUpperCase() {
+        return isAlphaKeyboard() && mShiftState.isAutomaticTemporaryUpperCase();
+    }
+
+    public boolean isManualTemporaryUpperCase() {
+        return isAlphaKeyboard() && mShiftState.isManualTemporaryUpperCase();
+    }
+
+    public KeyboardShiftState getKeyboardShiftState() {
+        return mShiftState;
+    }
+
+    public boolean isAlphaKeyboard() {
+        return mId != null && mId.isAlphabetKeyboard();
+    }
+
+    public boolean isPhoneKeyboard() {
+        return mId != null && mId.isPhoneKeyboard();
+    }
+
+    public boolean isNumberKeyboard() {
+        return mId != null && mId.isNumberKeyboard();
+    }
+
+    public void setSpaceKey(Key space) {
+        mSpaceKey = space;
+        mSpaceIcon = space.getIcon();
+        mSpacePreviewIcon = space.getPreviewIcon();
+    }
+
+    private void computeNearestNeighbors() {
+        // Round-up so we don't have any pixels outside the grid
+        mCellWidth = (getMinWidth() + GRID_WIDTH - 1) / GRID_WIDTH;
+        mCellHeight = (getHeight() + GRID_HEIGHT - 1) / GRID_HEIGHT;
+        mGridNeighbors = new int[GRID_SIZE][];
+        final int[] indices = new int[mKeys.size()];
+        final int gridWidth = GRID_WIDTH * mCellWidth;
+        final int gridHeight = GRID_HEIGHT * mCellHeight;
+        final int threshold = mProximityThreshold;
+        for (int x = 0; x < gridWidth; x += mCellWidth) {
+            for (int y = 0; y < gridHeight; y += mCellHeight) {
+                final int centerX = x + mCellWidth / 2;
+                final int centerY = y + mCellHeight / 2;
+                int count = 0;
+                for (int i = 0; i < mKeys.size(); i++) {
+                    final Key key = mKeys.get(i);
+                    if (key.squaredDistanceToEdge(centerX, centerY) < threshold)
+                        indices[count++] = i;
+                }
+                final int[] cell = new int[count];
+                System.arraycopy(indices, 0, cell, 0, count);
+                mGridNeighbors[(y / mCellHeight) * GRID_WIDTH + (x / mCellWidth)] = cell;
+            }
+        }
+    }
+
+    public boolean isInside(Key key, int x, int y) {
+        return key.isOnKey(x, y);
+    }
+
+    /**
+     * Returns the indices of the keys that are closest to the given point.
+     * @param x the x-coordinate of the point
+     * @param y the y-coordinate of the point
+     * @return the array of integer indices for the nearest keys to the given point. If the given
+     * point is out of range, then an array of size zero is returned.
+     */
+    public int[] getNearestKeys(int x, int y) {
+        if (mGridNeighbors == null) computeNearestNeighbors();
+        if (x >= 0 && x < getMinWidth() && y >= 0 && y < getHeight()) {
+            int index = (y / mCellHeight) * GRID_WIDTH + (x / mCellWidth);
+            if (index < GRID_SIZE) {
+                return mGridNeighbors[index];
+            }
+        }
+        return EMPTY_INT_ARRAY;
+    }
+
+    // TODO should be private
+    protected Row createRowFromXml(Resources res, XmlResourceParser parser) {
+        return new Row(res, this, parser);
+    }
+
+    // TODO should be private
+    protected Key createKeyFromXml(Resources res, Row parent, int x, int y,
+            XmlResourceParser parser, KeyStyles keyStyles) {
+        return new Key(res, parent, x, y, parser, keyStyles);
+    }
+
+    private void loadKeyboard(Context context, int xmlLayoutResId) {
+        try {
+            final Resources res = context.getResources();
+            KeyboardParser parser = new KeyboardParser(this, res);
+            parser.parseKeyboard(res.getXml(xmlLayoutResId));
+            // mTotalWidth is the width of this keyboard which is maximum width of row.
+            mTotalWidth = parser.getMaxRowWidth();
+            mTotalHeight = parser.getTotalHeight();
+        } catch (XmlPullParserException e) {
+            Log.w(TAG, "keyboard XML parse error: " + e);
+            throw new IllegalArgumentException(e);
+        } catch (IOException e) {
+            Log.w(TAG, "keyboard XML parse error: " + e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected static void setDefaultBounds(Drawable drawable)  {
+        if (drawable != null)
+            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
+                    drawable.getIntrinsicHeight());
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
new file mode 100644
index 0000000..e52db29
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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;
+
+public interface KeyboardActionListener {
+
+    /**
+     * Called when the user presses a key. This is sent before the
+     * {@link #onKey} is called. For keys that repeat, this is only
+     * called once.
+     *
+     * @param primaryCode
+     *            the unicode of the key being pressed. If the touch is
+     *            not on a valid key, the value will be zero.
+     */
+    void onPress(int primaryCode);
+
+    /**
+     * Called when the user releases a key. This is sent after the
+     * {@link #onKey} is called. For keys that repeat, this is only
+     * called once.
+     *
+     * @param primaryCode
+     *            the code of the key that was released
+     */
+    void onRelease(int primaryCode);
+
+    /**
+     * Send a key press to the listener.
+     *
+     * @param primaryCode
+     *            this is the key that was pressed
+     * @param keyCodes
+     *            the codes for all the possible alternative keys with
+     *            the primary code being the first. If the primary key
+     *            code is a single character such as an alphabet or
+     *            number or symbol, the alternatives will include other
+     *            characters that may be on the same key or adjacent
+     *            keys. These codes are useful to correct for
+     *            accidental presses of a key adjacent to the intended
+     *            key.
+     * @param x
+     *            x-coordinate pixel of touched event. If onKey is not called by onTouchEvent,
+     *            the value should be NOT_A_TOUCH_COORDINATE.
+     * @param y
+     *            y-coordinate pixel of touched event. If onKey is not called by onTouchEvent,
+     *            the value should be NOT_A_TOUCH_COORDINATE.
+     */
+    void onKey(int primaryCode, int[] keyCodes, int x, int y);
+
+    /**
+     * Sends a sequence of characters to the listener.
+     *
+     * @param text
+     *            the sequence of characters to be displayed.
+     */
+    void onText(CharSequence text);
+
+    /**
+     * Called when user released a finger outside any key.
+     */
+    void onCancel();
+
+    /**
+     * Called when the user quickly moves the finger from right to
+     * left.
+     */
+    void swipeLeft();
+
+    /**
+     * Called when the user quickly moves the finger from left to
+     * right.
+     */
+    void swipeRight();
+
+    /**
+     * Called when the user quickly moves the finger from up to down.
+     */
+    void swipeDown();
+
+    /**
+     * Called when the user quickly moves the finger from down to up.
+     */
+    void swipeUp();
+}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
new file mode 100644
index 0000000..883d217
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 com.android.inputmethod.latin.R;
+
+import android.view.inputmethod.EditorInfo;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * Represents the parameters necessary to construct a new LatinKeyboard,
+ * which also serve as a unique identifier for each keyboard type.
+ */
+public class KeyboardId {
+    public static final int MODE_TEXT = 0;
+    public static final int MODE_URL = 1;
+    public static final int MODE_EMAIL = 2;
+    public static final int MODE_IM = 3;
+    public static final int MODE_WEB = 4;
+    public static final int MODE_PHONE = 5;
+    public static final int MODE_NUMBER = 6;
+
+    public final Locale mLocale;
+    public final int mOrientation;
+    public final int mMode;
+    public final int mXmlId;
+    public final int mColorScheme;
+    public final boolean mHasSettingsKey;
+    public final boolean mVoiceKeyEnabled;
+    public final boolean mHasVoiceKey;
+    public final int mImeOptions;
+    public final boolean mEnableShiftLock;
+
+    private final int mHashCode;
+
+    public KeyboardId(Locale locale, int orientation, int mode,
+            int xmlId, int colorScheme, boolean hasSettingsKey, boolean voiceKeyEnabled,
+            boolean hasVoiceKey, int imeOptions, boolean enableShiftLock) {
+        this.mLocale = locale;
+        this.mOrientation = orientation;
+        this.mMode = mode;
+        this.mXmlId = xmlId;
+        this.mColorScheme = colorScheme;
+        this.mHasSettingsKey = hasSettingsKey;
+        this.mVoiceKeyEnabled = voiceKeyEnabled;
+        this.mHasVoiceKey = hasVoiceKey;
+        // We are interested only in IME_MASK_ACTION enum value and IME_FLAG_NO_ENTER_ACTION.
+        this.mImeOptions = imeOptions
+                & (EditorInfo.IME_MASK_ACTION | EditorInfo.IME_FLAG_NO_ENTER_ACTION);
+        this.mEnableShiftLock = enableShiftLock;
+
+        this.mHashCode = Arrays.hashCode(new Object[] {
+                locale,
+                orientation,
+                mode,
+                xmlId,
+                colorScheme,
+                hasSettingsKey,
+                voiceKeyEnabled,
+                hasVoiceKey,
+                imeOptions,
+                enableShiftLock,
+        });
+    }
+
+    public int getXmlId() {
+        return mXmlId;
+    }
+
+    public boolean isAlphabetKeyboard() {
+        return mXmlId == R.xml.kbd_qwerty;
+    }
+
+    public boolean isPhoneKeyboard() {
+        return mMode == MODE_PHONE;
+    }
+
+    public boolean isNumberKeyboard() {
+        return mMode == MODE_NUMBER;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        return other instanceof KeyboardId && equals((KeyboardId) other);
+    }
+
+    boolean equals(KeyboardId other) {
+        return other.mLocale.equals(this.mLocale)
+            && other.mOrientation == this.mOrientation
+            && other.mMode == this.mMode
+            && other.mXmlId == this.mXmlId
+            && other.mColorScheme == this.mColorScheme
+            && other.mHasSettingsKey == this.mHasSettingsKey
+            && other.mVoiceKeyEnabled == this.mVoiceKeyEnabled
+            && other.mHasVoiceKey == this.mHasVoiceKey
+            && other.mImeOptions == this.mImeOptions
+            && other.mEnableShiftLock == this.mEnableShiftLock;
+    }
+
+    @Override
+    public int hashCode() {
+        return mHashCode;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("[%s %s %5s imeOptions=0x%08x xml=0x%08x %s%s%s%s%s]",
+                mLocale,
+                (mOrientation == 1 ? "port" : "land"),
+                modeName(mMode),
+                mImeOptions,
+                mXmlId,
+                colorSchemeName(mColorScheme),
+                (mHasSettingsKey ? " hasSettingsKey" : ""),
+                (mVoiceKeyEnabled ? " voiceKeyEnabled" : ""),
+                (mHasVoiceKey ? " hasVoiceKey" : ""),
+                (mEnableShiftLock ? " enableShiftLock" : ""));
+    }
+
+    private static String modeName(int mode) {
+        switch (mode) {
+        case MODE_TEXT: return "text";
+        case MODE_URL: return "url";
+        case MODE_EMAIL: return "email";
+        case MODE_IM: return "im";
+        case MODE_WEB: return "web";
+        case MODE_PHONE: return "phone";
+        case MODE_NUMBER: return "number";
+        }
+        return null;
+    }
+
+    private static String colorSchemeName(int colorScheme) {
+        switch (colorScheme) {
+        case KeyboardView.COLOR_SCHEME_WHITE: return "white";
+        case KeyboardView.COLOR_SCHEME_BLACK: return "black";
+        }
+        return null;
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardParser.java b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
new file mode 100644
index 0000000..dd80f0e
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardParser.java
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 com.android.inputmethod.latin.R;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.Log;
+import android.util.TypedValue;
+import android.util.Xml;
+import android.view.InflateException;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Parser for BaseKeyboard.
+ *
+ * This class parses Keyboard XML file and fill out keys in Keyboard.
+ * The Keyboard XML file looks like:
+ * <pre>
+ *   &gt;!-- xml/keyboard.xml --&lt;
+ *   &gt;Keyboard keyboard_attributes*&lt;
+ *     &gt;!-- Keyboard Content --&lt;
+ *     &gt;Row row_attributes*&lt;
+ *       &gt;!-- Row Content --&lt;
+ *       &gt;Key key_attributes* /&lt;
+ *       &gt;Spacer horizontalGap="0.2in" /&lt;
+ *       &gt;include keyboardLayout="@xml/other_keys"&lt;
+ *       ...
+ *     &gt;/Row&lt;
+ *     &gt;include keyboardLayout="@xml/other_rows"&lt;
+ *     ...
+ *   &gt;/Keyboard&lt;
+ * </pre>
+ * The XML file which is included in other file must have &gt;merge&lt; as root element, such as:
+ * <pre>
+ *   &gt;!-- xml/other_keys.xml --&lt;
+ *   &gt;merge&lt;
+ *     &gt;Key key_attributes* /&lt;
+ *     ...
+ *   &gt;/merge&lt;
+ * </pre>
+ * and
+ * <pre>
+ *   &gt;!-- xml/other_rows.xml --&lt;
+ *   &gt;merge&lt;
+ *     &gt;Row row_attributes*&lt;
+ *       &gt;Key key_attributes* /&lt;
+ *     &gt;/Row&lt;
+ *     ...
+ *   &gt;/merge&lt;
+ * </pre>
+ * You can also use switch-case-default tags to select Rows and Keys.
+ * <pre>
+ *   &gt;switch&lt;
+ *     &gt;case case_attribute*&lt;
+ *       &gt;!-- Any valid tags at switch position --&lt;
+ *     &gt;/case&lt;
+ *     ...
+ *     &gt;default&lt;
+ *       &gt;!-- Any valid tags at switch position --&lt;
+ *     &gt;/default&lt;
+ *   &gt;/switch&lt;
+ * </pre>
+ * You can declare Key style and specify styles within Key tags.
+ * <pre>
+ *     &gt;switch&lt;
+ *       &gt;case colorScheme="white"&lt;
+ *         &gt;key-style styleName="shift-key" parentStyle="modifier-key"
+ *           keyIcon="@drawable/sym_keyboard_shift"
+ *         /&lt;
+ *       &gt;/case&lt;
+ *       &gt;case colorScheme="black"&lt;
+ *         &gt;key-style styleName="shift-key" parentStyle="modifier-key"
+ *           keyIcon="@drawable/sym_bkeyboard_shift"
+ *         /&lt;
+ *       &gt;/case&lt;
+ *     &gt;/switch&lt;
+ *     ...
+ *     &gt;Key keyStyle="shift-key" ... /&lt;
+ * </pre>
+ */
+
+public class KeyboardParser {
+    private static final String TAG = "KeyboardParser";
+    private static final boolean DEBUG_TAG = false;
+
+    // Keyboard XML Tags
+    private static final String TAG_KEYBOARD = "Keyboard";
+    private static final String TAG_ROW = "Row";
+    private static final String TAG_KEY = "Key";
+    private static final String TAG_SPACER = "Spacer";
+    private static final String TAG_INCLUDE = "include";
+    private static final String TAG_MERGE = "merge";
+    private static final String TAG_SWITCH = "switch";
+    private static final String TAG_CASE = "case";
+    private static final String TAG_DEFAULT = "default";
+    private static final String TAG_KEY_STYLE = "key-style";
+
+    private final Keyboard mKeyboard;
+    private final Resources mResources;
+
+    private int mCurrentX = 0;
+    private int mCurrentY = 0;
+    private int mMaxRowWidth = 0;
+    private int mTotalHeight = 0;
+    private Row mCurrentRow = null;
+    private final KeyStyles mKeyStyles = new KeyStyles();
+
+    public KeyboardParser(Keyboard keyboard, Resources res) {
+        mKeyboard = keyboard;
+        mResources = res;
+    }
+
+    public int getMaxRowWidth() {
+        return mMaxRowWidth;
+    }
+
+    public int getTotalHeight() {
+        return mTotalHeight;
+    }
+
+    public void parseKeyboard(XmlResourceParser parser)
+            throws XmlPullParserException, IOException {
+        int event;
+        while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
+            if (event == XmlResourceParser.START_TAG) {
+                final String tag = parser.getName();
+                if (DEBUG_TAG) debugStartTag("parseKeyboard", tag, false);
+                if (TAG_KEYBOARD.equals(tag)) {
+                    parseKeyboardAttributes(parser);
+                    parseKeyboardContent(parser, mKeyboard.getKeys());
+                    break;
+                } else {
+                    throw new IllegalStartTag(parser, TAG_KEYBOARD);
+                }
+            }
+        }
+    }
+
+    private void parseKeyboardAttributes(XmlResourceParser parser) {
+        final Keyboard keyboard = mKeyboard;
+        final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+                R.styleable.Keyboard);
+        final int width = keyboard.getKeyboardWidth();
+        final int height = keyboard.getKeyboardHeight();
+        keyboard.setKeyWidth(getDimensionOrFraction(a,
+                R.styleable.Keyboard_keyWidth, width, width / 10));
+        keyboard.setKeyHeight(getDimensionOrFraction(a,
+                R.styleable.Keyboard_keyHeight, height, 50));
+        keyboard.setHorizontalGap(getDimensionOrFraction(a,
+                R.styleable.Keyboard_horizontalGap, width, 0));
+        keyboard.setVerticalGap(getDimensionOrFraction(a,
+                R.styleable.Keyboard_verticalGap, height, 0));
+        a.recycle();
+        if (DEBUG_TAG) Log.d(TAG, "id=" + keyboard.mId);
+    }
+
+    private void parseKeyboardContent(XmlResourceParser parser, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        int event;
+        while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
+            if (event == XmlResourceParser.START_TAG) {
+                final String tag = parser.getName();
+                if (DEBUG_TAG) debugStartTag("parseKeyboardContent", tag, keys == null);
+                if (TAG_ROW.equals(tag)) {
+                    Row row = mKeyboard.createRowFromXml(mResources, parser);
+                    if (keys != null)
+                        startRow(row);
+                    parseRowContent(parser, row, keys);
+                } else if (TAG_INCLUDE.equals(tag)) {
+                    parseIncludeKeyboardContent(parser, keys);
+                } else if (TAG_SWITCH.equals(tag)) {
+                    parseSwitchKeyboardContent(parser, keys);
+                } else if (TAG_KEY_STYLE.equals(tag)) {
+                    parseKeyStyle(parser, keys);
+                } else {
+                    throw new IllegalStartTag(parser, TAG_ROW);
+                }
+            } else if (event == XmlResourceParser.END_TAG) {
+                final String tag = parser.getName();
+                if (DEBUG_TAG) debugEndTag("parseKeyboardContent", tag, keys == null);
+                if (TAG_KEYBOARD.equals(tag)) {
+                    endKeyboard(mKeyboard.getVerticalGap());
+                    break;
+                } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag)) {
+                    break;
+                } else if (TAG_MERGE.equals(tag)) {
+                    break;
+                } else if (TAG_KEY_STYLE.equals(tag)) {
+                    continue;
+                } else {
+                    throw new IllegalEndTag(parser, TAG_ROW);
+                }
+            }
+        }
+    }
+
+    private void parseRowContent(XmlResourceParser parser, Row row, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        int event;
+        while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
+            if (event == XmlResourceParser.START_TAG) {
+                final String tag = parser.getName();
+                if (DEBUG_TAG) debugStartTag("parseRowContent", tag, keys == null);
+                if (TAG_KEY.equals(tag)) {
+                    parseKey(parser, row, keys);
+                } else if (TAG_SPACER.equals(tag)) {
+                    parseSpacer(parser, keys);
+                } else if (TAG_INCLUDE.equals(tag)) {
+                    parseIncludeRowContent(parser, row, keys);
+                } else if (TAG_SWITCH.equals(tag)) {
+                    parseSwitchRowContent(parser, row, keys);
+                } else if (TAG_KEY_STYLE.equals(tag)) {
+                    parseKeyStyle(parser, keys);
+                } else {
+                    throw new IllegalStartTag(parser, TAG_KEY);
+                }
+            } else if (event == XmlResourceParser.END_TAG) {
+                final String tag = parser.getName();
+                if (DEBUG_TAG) debugEndTag("parseRowContent", tag, keys == null);
+                if (TAG_ROW.equals(tag)) {
+                    if (keys != null)
+                        endRow();
+                    break;
+                } else if (TAG_CASE.equals(tag) || TAG_DEFAULT.equals(tag)) {
+                    break;
+                } else if (TAG_MERGE.equals(tag)) {
+                    break;
+                } else if (TAG_KEY_STYLE.equals(tag)) {
+                    continue;
+                } else {
+                    throw new IllegalEndTag(parser, TAG_KEY);
+                }
+            }
+        }
+    }
+
+    private void parseKey(XmlResourceParser parser, Row row, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        if (keys == null) {
+            checkEndTag(TAG_KEY, parser);
+        } else {
+            Key key = mKeyboard.createKeyFromXml(mResources, row, mCurrentX, mCurrentY, parser,
+                    mKeyStyles);
+            checkEndTag(TAG_KEY, parser);
+            keys.add(key);
+            if (key.mCodes[0] == Keyboard.CODE_SHIFT)
+                mKeyboard.getShiftKeys().add(key);
+            if (key.mCodes[0] == Keyboard.CODE_SPACE)
+                mKeyboard.setSpaceKey(key);
+            endKey(key);
+        }
+    }
+
+    private void parseSpacer(XmlResourceParser parser, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        if (keys == null) {
+            checkEndTag(TAG_SPACER, parser);
+        } else {
+            final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+                    R.styleable.Keyboard);
+            final int gap = getDimensionOrFraction(a, R.styleable.Keyboard_horizontalGap,
+                    mKeyboard.getKeyboardWidth(), 0);
+            a.recycle();
+            checkEndTag(TAG_SPACER, parser);
+            setSpacer(gap);
+        }
+    }
+
+    private void parseIncludeKeyboardContent(XmlResourceParser parser, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        parseIncludeInternal(parser, null, keys);
+    }
+
+    private void parseIncludeRowContent(XmlResourceParser parser, Row row, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        parseIncludeInternal(parser, row, keys);
+    }
+
+    private void parseIncludeInternal(XmlResourceParser parser, Row row, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        if (keys == null) {
+            checkEndTag(TAG_INCLUDE, parser);
+        } else {
+            final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+                    R.styleable.Keyboard_Include);
+            final int keyboardLayout = a.getResourceId(
+                    R.styleable.Keyboard_Include_keyboardLayout, 0);
+            a.recycle();
+
+            checkEndTag(TAG_INCLUDE, parser);
+            if (keyboardLayout == 0)
+                throw new ParseException("No keyboardLayout attribute in <include/>", parser);
+            if (DEBUG_TAG) Log.d(TAG, String.format("  keyboardLayout=0x%08x", keyboardLayout));
+            parseMerge(mResources.getLayout(keyboardLayout), row, keys);
+        }
+    }
+
+    private void parseMerge(XmlResourceParser parser, Row row, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        int event;
+        while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
+            if (event == XmlResourceParser.START_TAG) {
+                final String tag = parser.getName();
+                if (DEBUG_TAG) debugStartTag("parseMerge", tag, keys == null);
+                if (TAG_MERGE.equals(tag)) {
+                    if (row == null) {
+                        parseKeyboardContent(parser, keys);
+                    } else {
+                        parseRowContent(parser, row, keys);
+                    }
+                    break;
+                } else {
+                    throw new ParseException(
+                            "Included keyboard layout must have <merge> root element", parser);
+                }
+            }
+        }
+    }
+
+    private void parseSwitchKeyboardContent(XmlResourceParser parser, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        parseSwitchInternal(parser, null, keys);
+    }
+
+    private void parseSwitchRowContent(XmlResourceParser parser, Row row, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        parseSwitchInternal(parser, row, keys);
+    }
+
+    private void parseSwitchInternal(XmlResourceParser parser, Row row, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        boolean selected = false;
+        int event;
+        if (DEBUG_TAG) Log.d(TAG, "parseSwitchInternal: id=" + mKeyboard.mId);
+        while ((event = parser.next()) != XmlResourceParser.END_DOCUMENT) {
+            if (event == XmlResourceParser.START_TAG) {
+                final String tag = parser.getName();
+                if (DEBUG_TAG) debugStartTag("parseSwitchInternal", tag, keys == null);
+                if (TAG_CASE.equals(tag)) {
+                    selected |= parseCase(parser, row, selected ? null : keys);
+                } else if (TAG_DEFAULT.equals(tag)) {
+                    selected |= parseDefault(parser, row, selected ? null : keys);
+                } else {
+                    throw new IllegalStartTag(parser, TAG_KEY);
+                }
+            } else if (event == XmlResourceParser.END_TAG) {
+                final String tag = parser.getName();
+                if (DEBUG_TAG) debugEndTag("parseRowContent", tag, keys == null);
+                if (TAG_SWITCH.equals(tag)) {
+                    break;
+                } else {
+                    throw new IllegalEndTag(parser, TAG_KEY);
+                }
+            }
+        }
+    }
+
+    private boolean parseCase(XmlResourceParser parser, Row row, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        final boolean selected = parseCaseCondition(parser);
+        if (row == null) {
+            // Processing Rows.
+            parseKeyboardContent(parser, selected ? keys : null);
+        } else {
+            // Processing Keys.
+            parseRowContent(parser, row, selected ? keys : null);
+        }
+        return selected;
+    }
+
+    private boolean parseCaseCondition(XmlResourceParser parser) {
+        final KeyboardId id = mKeyboard.mId;
+        if (id == null)
+            return true;
+
+        final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+                R.styleable.Keyboard_Case);
+        final TypedArray viewAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+                R.styleable.KeyboardView);
+        try {
+            final boolean modeMatched = matchInteger(a,
+                    R.styleable.Keyboard_Case_mode, id.mMode);
+            final boolean settingsKeyMatched = matchBoolean(a,
+                    R.styleable.Keyboard_Case_hasSettingsKey, id.mHasSettingsKey);
+            final boolean voiceEnabledMatched = matchBoolean(a,
+                    R.styleable.Keyboard_Case_voiceKeyEnabled, id.mVoiceKeyEnabled);
+            final boolean voiceKeyMatched = matchBoolean(a,
+                    R.styleable.Keyboard_Case_hasVoiceKey, id.mHasVoiceKey);
+            final boolean colorSchemeMatched = matchInteger(viewAttr,
+                    R.styleable.KeyboardView_colorScheme, id.mColorScheme);
+            // As noted at KeyboardSwitcher.KeyboardId class, we are interested only in
+            // enum value masked by IME_MASK_ACTION and IME_FLAG_NO_ENTER_ACTION. So matching
+            // this attribute with id.mImeOptions as integer value is enough for our purpose.
+            final boolean imeOptionsMatched = matchInteger(a,
+                    R.styleable.Keyboard_Case_imeOptions, id.mImeOptions);
+            final boolean selected = modeMatched && settingsKeyMatched && voiceEnabledMatched
+                    && voiceKeyMatched && colorSchemeMatched && imeOptionsMatched;
+
+            if (DEBUG_TAG) {
+                Log.d(TAG, String.format(
+                        "parseCaseCondition: %s%s%s%s%s%s%s",
+                        Boolean.toString(selected).toUpperCase(),
+                        debugInteger(a, R.styleable.Keyboard_Case_mode, "mode"),
+                        debugBoolean(a, R.styleable.Keyboard_Case_hasSettingsKey,
+                                "hasSettingsKey"),
+                        debugBoolean(a, R.styleable.Keyboard_Case_voiceKeyEnabled,
+                                "voiceKeyEnabled"),
+                        debugBoolean(a, R.styleable.Keyboard_Case_hasVoiceKey, "hasVoiceKey"),
+                        debugInteger(viewAttr, R.styleable.KeyboardView_colorScheme,
+                                "colorScheme"),
+                        debugInteger(a, R.styleable.Keyboard_Case_imeOptions, "imeOptions")));
+            }
+
+            return selected;
+        } finally {
+            a.recycle();
+            viewAttr.recycle();
+        }
+    }
+
+    private static boolean matchInteger(TypedArray a, int index, int value) {
+        // If <case> does not have "index" attribute, that means this <case> is wild-card for the
+        // attribute.
+        return !a.hasValue(index) || a.getInt(index, 0) == value;
+    }
+
+    private static boolean matchBoolean(TypedArray a, int index, boolean value) {
+        // If <case> does not have "index" attribute, that means this <case> is wild-card for the
+        // attribute.
+        return !a.hasValue(index) || a.getBoolean(index, false) == value;
+    }
+
+    private boolean parseDefault(XmlResourceParser parser, Row row, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        if (row == null) {
+            parseKeyboardContent(parser, keys);
+        } else {
+            parseRowContent(parser, row, keys);
+        }
+        return true;
+    }
+
+    private void parseKeyStyle(XmlResourceParser parser, List<Key> keys)
+            throws XmlPullParserException, IOException {
+        TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+                R.styleable.Keyboard_KeyStyle);
+        TypedArray keyAttrs = mResources.obtainAttributes(Xml.asAttributeSet(parser),
+                R.styleable.Keyboard_Key);
+        try {
+            if (!a.hasValue(R.styleable.Keyboard_KeyStyle_styleName))
+                throw new ParseException("<" + TAG_KEY_STYLE
+                        + "/> needs styleName attribute", parser);
+            if (keys != null)
+                mKeyStyles.parseKeyStyleAttributes(a, keyAttrs, parser);
+        } finally {
+            a.recycle();
+            keyAttrs.recycle();
+        }
+    }
+
+    private static void checkEndTag(String tag, XmlResourceParser parser)
+            throws XmlPullParserException, IOException {
+        if (parser.next() == XmlResourceParser.END_TAG && tag.equals(parser.getName()))
+            return;
+        throw new NonEmptyTag(tag, parser);
+    }
+
+    private void startRow(Row row) {
+        mCurrentX = 0;
+        mCurrentRow = row;
+    }
+
+    private void endRow() {
+        if (mCurrentRow == null)
+            throw new InflateException("orphant end row tag");
+        mCurrentY += mCurrentRow.mVerticalGap + mCurrentRow.mDefaultHeight;
+        mCurrentRow = null;
+    }
+
+    private void endKey(Key key) {
+        mCurrentX += key.mGap + key.mWidth;
+        if (mCurrentX > mMaxRowWidth)
+            mMaxRowWidth = mCurrentX;
+    }
+
+    private void endKeyboard(int defaultVerticalGap) {
+        mTotalHeight = mCurrentY - defaultVerticalGap;
+    }
+
+    private void setSpacer(int gap) {
+        mCurrentX += gap;
+    }
+
+    public static int getDimensionOrFraction(TypedArray a, int index, int base, int defValue) {
+        final TypedValue value = a.peekValue(index);
+        if (value == null)
+            return defValue;
+        if (value.type == TypedValue.TYPE_DIMENSION) {
+            return a.getDimensionPixelOffset(index, defValue);
+        } else if (value.type == TypedValue.TYPE_FRACTION) {
+            // Round it to avoid values like 47.9999 from getting truncated
+            return Math.round(a.getFraction(index, base, base, defValue));
+        }
+        return defValue;
+    }
+
+    @SuppressWarnings("serial")
+    public static class ParseException extends InflateException {
+        public ParseException(String msg, XmlResourceParser parser) {
+            super(msg + " at line " + parser.getLineNumber());
+        }
+    }
+
+    @SuppressWarnings("serial")
+    private static class IllegalStartTag extends ParseException {
+        public IllegalStartTag(XmlResourceParser parser, String parent) {
+            super("Illegal start tag " + parser.getName() + " in " + parent, parser);
+        }
+    }
+
+    @SuppressWarnings("serial")
+    private static class IllegalEndTag extends ParseException {
+        public IllegalEndTag(XmlResourceParser parser, String parent) {
+            super("Illegal end tag " + parser.getName() + " in " + parent, parser);
+        }
+    }
+
+    @SuppressWarnings("serial")
+    private static class NonEmptyTag extends ParseException {
+        public NonEmptyTag(String tag, XmlResourceParser parser) {
+            super(tag + " must be empty tag", parser);
+        }
+    }
+
+    private static void debugStartTag(String title, String tag, boolean skip) {
+        Log.d(TAG, title + ": <" + tag + ">" + (skip ? " skip" : ""));
+    }
+
+    private static void debugEndTag(String title, String tag, boolean skip) {
+        Log.d(TAG, title + ": </" + tag + ">" + (skip ? " skip" : ""));
+    }
+
+    private static String debugInteger(TypedArray a, int index, String name) {
+        return a.hasValue(index) ? " " + name + "=" + a.getInt(index, 0) : "";
+    }
+
+    private static String debugBoolean(TypedArray a, int index, String name) {
+        return a.hasValue(index) ? " " + name + "=" + a.getBoolean(index, false) : "";
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardShiftState.java b/java/src/com/android/inputmethod/keyboard/KeyboardShiftState.java
new file mode 100644
index 0000000..3e1eaf4
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardShiftState.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.util.Log;
+
+public class KeyboardShiftState {
+    private static final String TAG = "KeyboardShiftState";
+    private static final boolean DEBUG = KeyboardSwitcher.DEBUG_STATE;
+
+    private static final int NORMAL = 0;
+    private static final int MANUAL_SHIFTED = 1;
+    private static final int SHIFT_LOCKED = 2;
+    private static final int AUTO_SHIFTED = 3;
+    private static final int SHIFT_LOCK_SHIFTED = 4;
+
+    private int mState = NORMAL;
+
+    public boolean setShifted(boolean newShiftState) {
+        final int oldState = mState;
+        if (newShiftState) {
+            if (oldState == NORMAL || oldState == AUTO_SHIFTED) {
+                mState = MANUAL_SHIFTED;
+            } else if (oldState == SHIFT_LOCKED) {
+                mState = SHIFT_LOCK_SHIFTED;
+            }
+        } else {
+            if (oldState == MANUAL_SHIFTED || oldState == AUTO_SHIFTED) {
+                mState = NORMAL;
+            } else if (oldState == SHIFT_LOCK_SHIFTED) {
+                mState = SHIFT_LOCKED;
+                            }
+        }
+        if (DEBUG)
+            Log.d(TAG, "setShifted(" + newShiftState + "): " + toString(oldState) + " > " + this);
+        return mState != oldState;
+    }
+
+    public void setShiftLocked(boolean newShiftLockState) {
+        final int oldState = mState;
+        if (newShiftLockState) {
+            if (oldState == NORMAL || oldState == MANUAL_SHIFTED || oldState == AUTO_SHIFTED)
+                mState = SHIFT_LOCKED;
+        } else {
+            if (oldState == SHIFT_LOCKED || oldState == SHIFT_LOCK_SHIFTED)
+                mState = NORMAL;
+        }
+        if (DEBUG)
+            Log.d(TAG, "setShiftLocked(" + newShiftLockState + "): " + toString(oldState)
+                    + " > " + this);
+    }
+
+    public void setAutomaticTemporaryUpperCase() {
+        final int oldState = mState;
+        mState = AUTO_SHIFTED;
+        if (DEBUG)
+            Log.d(TAG, "setAutomaticTemporaryUpperCase: " + toString(oldState) + " > " + this);
+    }
+
+    public boolean isShiftedOrShiftLocked() {
+        return mState != NORMAL;
+    }
+
+    public boolean isShiftLocked() {
+        return mState == SHIFT_LOCKED || mState == SHIFT_LOCK_SHIFTED;
+    }
+
+    public boolean isAutomaticTemporaryUpperCase() {
+        return mState == AUTO_SHIFTED;
+    }
+
+    public boolean isManualTemporaryUpperCase() {
+        return mState == MANUAL_SHIFTED || mState == SHIFT_LOCK_SHIFTED;
+    }
+
+    @Override
+    public String toString() {
+        return toString(mState);
+    }
+
+    private static String toString(int state) {
+        switch (state) {
+        case NORMAL: return "NORMAL";
+        case MANUAL_SHIFTED: return "MANUAL_SHIFTED";
+        case SHIFT_LOCKED: return "SHIFT_LOCKED";
+        case AUTO_SHIFTED: return "AUTO_SHIFTED";
+        case SHIFT_LOCK_SHIFTED: return "SHIFT_LOCK_SHIFTED";
+        default: return "UKNOWN";
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
new file mode 100644
index 0000000..d3302fd
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -0,0 +1,646 @@
+/*
+ * Copyright (C) 2008 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 com.android.inputmethod.latin.LatinIME;
+import com.android.inputmethod.latin.LatinIMESettings;
+import com.android.inputmethod.latin.LatinIMEUtil;
+import com.android.inputmethod.latin.LatinImeLogger;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SubtypeSwitcher;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.util.Log;
+import android.view.InflateException;
+import android.view.inputmethod.InputMethodManager;
+
+import java.lang.ref.SoftReference;
+import java.util.HashMap;
+import java.util.Locale;
+
+public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener {
+    private static final String TAG = "KeyboardSwitcher";
+    private static final boolean DEBUG = false;
+    public static final boolean DEBUG_STATE = false;
+
+    // Changing DEFAULT_LAYOUT_ID also requires prefs_for_debug.xml to be matched with.
+    public static final String DEFAULT_LAYOUT_ID = "5";
+    public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902";
+    private static final int[] THEMES = new int [] {
+        R.layout.input_basic,
+        R.layout.input_basic_highcontrast,
+        R.layout.input_stone_normal,
+        R.layout.input_stone_bold,
+        R.layout.input_gingerbread,
+        R.layout.input_honeycomb, // DEFAULT_LAYOUT_ID
+    };
+
+    private static final int SYMBOLS_MODE_STATE_NONE = 0;
+    private static final int SYMBOLS_MODE_STATE_BEGIN = 1;
+    private static final int SYMBOLS_MODE_STATE_SYMBOL = 2;
+
+    private SubtypeSwitcher mSubtypeSwitcher;
+    private SharedPreferences mPrefs;
+
+    private LatinKeyboardView mInputView;
+    private LatinIME mInputMethodService;
+
+    private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
+    private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
+
+    private KeyboardId mSymbolsId;
+    private KeyboardId mSymbolsShiftedId;
+
+    private KeyboardId mCurrentId;
+    private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
+            new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
+
+    private int mMode = KeyboardId.MODE_TEXT; /* default value */
+    private int mImeOptions;
+    private boolean mIsSymbols;
+    /** mIsAutoCompletionActive indicates that auto completed word will be input instead of
+     * what user actually typed. */
+    private boolean mIsAutoCompletionActive;
+    private boolean mVoiceKeyEnabled;
+    private boolean mVoiceButtonOnPrimary;
+    private int mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
+
+    // Indicates whether or not we have the settings key
+    private boolean mHasSettingsKey;
+    private static final int SETTINGS_KEY_MODE_AUTO = R.string.settings_key_mode_auto;
+    private static final int SETTINGS_KEY_MODE_ALWAYS_SHOW =
+            R.string.settings_key_mode_always_show;
+    // NOTE: No need to have SETTINGS_KEY_MODE_ALWAYS_HIDE here because it's not being referred to
+    // in the source code now.
+    // Default is SETTINGS_KEY_MODE_AUTO.
+    private static final int DEFAULT_SETTINGS_KEY_MODE = SETTINGS_KEY_MODE_AUTO;
+
+    private int mLayoutId;
+
+    private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
+
+    public static KeyboardSwitcher getInstance() {
+        return sInstance;
+    }
+
+    private KeyboardSwitcher() {
+    }
+
+    public static void init(LatinIME ims, SharedPreferences prefs) {
+        sInstance.mInputMethodService = ims;
+        sInstance.mPrefs = prefs;
+        sInstance.mSubtypeSwitcher = SubtypeSwitcher.getInstance();
+
+        sInstance.mLayoutId = Integer.valueOf(
+                prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID));
+        prefs.registerOnSharedPreferenceChangeListener(sInstance);
+    }
+
+    private void makeSymbolsKeyboardIds() {
+        final Locale locale = mSubtypeSwitcher.getInputLocale();
+        final int orientation = mInputMethodService.getResources().getConfiguration().orientation;
+        final int mode = mMode;
+        final int colorScheme = getColorScheme();
+        final boolean hasSettingsKey = mHasSettingsKey;
+        final boolean voiceKeyEnabled = mVoiceKeyEnabled;
+        final boolean hasVoiceKey = voiceKeyEnabled && !mVoiceButtonOnPrimary;
+        final int imeOptions = mImeOptions;
+        // Note: This comment is only applied for phone number keyboard layout.
+        // On non-xlarge device, "@integer/key_switch_alpha_symbol" key code is used to switch
+        // between "phone keyboard" and "phone symbols keyboard".  But on xlarge device,
+        // "@integer/key_shift" key code is used for that purpose in order to properly display
+        // "more" and "locked more" key labels.  To achieve these behavior, we should initialize
+        // mSymbolsId and mSymbolsShiftedId to "phone keyboard" and "phone symbols keyboard"
+        // respectively here for xlarge device's layout switching.
+        mSymbolsId = new KeyboardId(locale, orientation, mode,
+                mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone : R.xml.kbd_symbols,
+                colorScheme, hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
+        mSymbolsShiftedId = new KeyboardId(locale, orientation, mode,
+                mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift,
+                colorScheme, hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
+    }
+
+    private boolean hasVoiceKey(boolean isSymbols) {
+        return mVoiceKeyEnabled && (isSymbols != mVoiceButtonOnPrimary);
+    }
+
+    public void loadKeyboard(int mode, int imeOptions, boolean voiceKeyEnabled,
+            boolean voiceButtonOnPrimary) {
+        mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
+        try {
+            loadKeyboardInternal(mode, imeOptions, voiceKeyEnabled, voiceButtonOnPrimary,
+                    false);
+        } catch (RuntimeException e) {
+            Log.w(TAG, e);
+            LatinImeLogger.logOnException(mode + "," + imeOptions, e);
+        }
+    }
+
+    private void loadKeyboardInternal(int mode, int imeOptions, boolean voiceButtonEnabled,
+            boolean voiceButtonOnPrimary, boolean isSymbols) {
+        if (mInputView == null) return;
+        mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
+
+        mMode = mode;
+        mImeOptions = imeOptions;
+        mVoiceKeyEnabled = voiceButtonEnabled;
+        mVoiceButtonOnPrimary = voiceButtonOnPrimary;
+        mIsSymbols = isSymbols;
+        // Update the settings key state because number of enabled IMEs could have been changed
+        mHasSettingsKey = getSettingsKeyMode(mPrefs, mInputMethodService);
+        makeSymbolsKeyboardIds();
+
+        KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
+        LatinKeyboard keyboard = getKeyboard(id);
+
+        mCurrentId = id;
+        mInputView.setKeyboard(keyboard);
+    }
+
+    private LatinKeyboard getKeyboard(KeyboardId id) {
+        final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id);
+        LatinKeyboard keyboard = (ref == null) ? null : ref.get();
+        if (keyboard == null) {
+            final Locale savedLocale =  mSubtypeSwitcher.changeSystemLocale(
+                    mSubtypeSwitcher.getInputLocale());
+
+            keyboard = new LatinKeyboard(mInputMethodService, id);
+
+            if (id.mEnableShiftLock) {
+                keyboard.enableShiftLock();
+            }
+
+            mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard));
+            if (DEBUG)
+                Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": "
+                        + ((ref == null) ? "LOAD" : "GCed") + " id=" + id);
+
+            mSubtypeSwitcher.changeSystemLocale(savedLocale);
+        } else if (DEBUG) {
+            Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT  id=" + id);
+        }
+
+        keyboard.onAutoCompletionStateChanged(mIsAutoCompletionActive);
+        keyboard.setShifted(false);
+        return keyboard;
+    }
+
+    private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) {
+        final boolean hasVoiceKey = hasVoiceKey(isSymbols);
+        final int charColorId = getColorScheme();
+        final int xmlId;
+        final boolean enableShiftLock;
+
+        if (isSymbols) {
+            if (mode == KeyboardId.MODE_PHONE) {
+                xmlId = R.xml.kbd_phone_symbols;
+            } else if (mode == KeyboardId.MODE_NUMBER) {
+                // Note: MODE_NUMBER keyboard layout has no "switch alpha symbol" key.
+                xmlId = R.xml.kbd_number;
+            } else {
+                xmlId = R.xml.kbd_symbols;
+            }
+            enableShiftLock = false;
+        } else {
+            if (mode == KeyboardId.MODE_PHONE) {
+                xmlId = R.xml.kbd_phone;
+                enableShiftLock = false;
+            } else if (mode == KeyboardId.MODE_NUMBER) {
+                xmlId = R.xml.kbd_number;
+                enableShiftLock = false;
+            } else {
+                xmlId = R.xml.kbd_qwerty;
+                enableShiftLock = true;
+            }
+        }
+        final int orientation = mInputMethodService.getResources().getConfiguration().orientation;
+        final Locale locale = mSubtypeSwitcher.getInputLocale();
+        return new KeyboardId(locale, orientation, mode, xmlId, charColorId,
+                mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, imeOptions, enableShiftLock);
+    }
+
+    public int getKeyboardMode() {
+        return mMode;
+    }
+
+    public boolean isAlphabetMode() {
+        return mCurrentId != null && mCurrentId.isAlphabetKeyboard();
+    }
+
+    public boolean isInputViewShown() {
+        return mInputView != null && mInputView.isShown();
+    }
+
+    public boolean isKeyboardAvailable() {
+        if (mInputView != null)
+            return mInputView.getLatinKeyboard() != null;
+        return false;
+    }
+
+    private LatinKeyboard getLatinKeyboard() {
+        if (mInputView != null)
+            return mInputView.getLatinKeyboard();
+        return null;
+    }
+
+    public void setPreferredLetters(int[] frequencies) {
+        LatinKeyboard latinKeyboard = getLatinKeyboard();
+        if (latinKeyboard != null)
+            latinKeyboard.setPreferredLetters(frequencies);
+    }
+
+    public void keyReleased() {
+        LatinKeyboard latinKeyboard = getLatinKeyboard();
+        if (latinKeyboard != null)
+            latinKeyboard.keyReleased();
+    }
+
+    public boolean isShiftedOrShiftLocked() {
+        LatinKeyboard latinKeyboard = getLatinKeyboard();
+        if (latinKeyboard != null)
+            return latinKeyboard.isShiftedOrShiftLocked();
+        return false;
+    }
+
+    public boolean isShiftLocked() {
+        LatinKeyboard latinKeyboard = getLatinKeyboard();
+        if (latinKeyboard != null)
+            return latinKeyboard.isShiftLocked();
+        return false;
+    }
+
+    public boolean isAutomaticTemporaryUpperCase() {
+        LatinKeyboard latinKeyboard = getLatinKeyboard();
+        if (latinKeyboard != null)
+            return latinKeyboard.isAutomaticTemporaryUpperCase();
+        return false;
+    }
+
+    public boolean isManualTemporaryUpperCase() {
+        LatinKeyboard latinKeyboard = getLatinKeyboard();
+        if (latinKeyboard != null)
+            return latinKeyboard.isManualTemporaryUpperCase();
+        return false;
+    }
+
+    private void setManualTemporaryUpperCase(boolean shifted) {
+        LatinKeyboard latinKeyboard = getLatinKeyboard();
+        if (latinKeyboard != null) {
+            // On non-distinct multi touch panel device, we should also turn off the shift locked
+            // state when shift key is pressed to go to normal mode.
+            // On the other hand, on distinct multi touch panel device, turning off the shift locked
+            // state with shift key pressing is handled by onReleaseShift().
+            if (!hasDistinctMultitouch() && !shifted && latinKeyboard.isShiftLocked()) {
+                latinKeyboard.setShiftLocked(false);
+            }
+            if (latinKeyboard.setShifted(shifted)) {
+                mInputView.invalidateAllKeys();
+            }
+        }
+    }
+
+    private void setShiftLocked(boolean shiftLocked) {
+        LatinKeyboard latinKeyboard = getLatinKeyboard();
+        if (latinKeyboard != null && latinKeyboard.setShiftLocked(shiftLocked)) {
+            mInputView.invalidateAllKeys();
+        }
+    }
+
+    /**
+     * Toggle keyboard shift state triggered by user touch event.
+     */
+    public void toggleShift() {
+        mInputMethodService.mHandler.cancelUpdateShiftState();
+        if (DEBUG_STATE)
+            Log.d(TAG, "toggleShift:"
+                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+                    + " shiftKeyState=" + mShiftKeyState);
+        if (isAlphabetMode()) {
+            setManualTemporaryUpperCase(!isShiftedOrShiftLocked());
+        } else {
+            toggleShiftInSymbol();
+        }
+    }
+
+    public void toggleCapsLock() {
+        mInputMethodService.mHandler.cancelUpdateShiftState();
+        if (DEBUG_STATE)
+            Log.d(TAG, "toggleCapsLock:"
+                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+                    + " shiftKeyState=" + mShiftKeyState);
+        if (isAlphabetMode()) {
+            if (isShiftLocked()) {
+                // Shift key is long pressed while caps lock state, we will toggle back to normal
+                // state. And mark as if shift key is released.
+                setShiftLocked(false);
+                mShiftKeyState.onRelease();
+            } else {
+                setShiftLocked(true);
+            }
+        }
+    }
+
+    private void setAutomaticTemporaryUpperCase() {
+        LatinKeyboard latinKeyboard = getLatinKeyboard();
+        if (latinKeyboard != null) {
+            latinKeyboard.setAutomaticTemporaryUpperCase();
+            mInputView.invalidateAllKeys();
+        }
+    }
+
+    /**
+     * Update keyboard shift state triggered by connected EditText status change.
+     */
+    public void updateShiftState() {
+        final ShiftKeyState shiftKeyState = mShiftKeyState;
+        if (DEBUG_STATE)
+            Log.d(TAG, "updateShiftState:"
+                    + " autoCaps=" + mInputMethodService.getCurrentAutoCapsState()
+                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+                    + " shiftKeyState=" + shiftKeyState);
+        if (isAlphabetMode()) {
+            if (!isShiftLocked() && !shiftKeyState.isIgnoring()) {
+                if (shiftKeyState.isReleasing() && mInputMethodService.getCurrentAutoCapsState()) {
+                    // Only when shift key is releasing, automatic temporary upper case will be set.
+                    setAutomaticTemporaryUpperCase();
+                } else {
+                    setManualTemporaryUpperCase(shiftKeyState.isMomentary());
+                }
+            }
+        } else {
+            // In symbol keyboard mode, we should clear shift key state because only alphabet
+            // keyboard has shift key.
+            shiftKeyState.onRelease();
+        }
+    }
+
+    public void changeKeyboardMode() {
+        if (DEBUG_STATE)
+            Log.d(TAG, "changeKeyboardMode:"
+                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+                    + " shiftKeyState=" + mShiftKeyState);
+        toggleKeyboardMode();
+        if (isShiftLocked() && isAlphabetMode())
+            setShiftLocked(true);
+        updateShiftState();
+    }
+
+    public void onPressShift() {
+        if (!isKeyboardAvailable())
+            return;
+        ShiftKeyState shiftKeyState = mShiftKeyState;
+        if (DEBUG_STATE)
+            Log.d(TAG, "onPressShift:"
+                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+                    + " shiftKeyState=" + shiftKeyState);
+        if (isAlphabetMode()) {
+            if (isShiftLocked()) {
+                // Shift key is pressed while caps lock state, we will treat this state as shifted
+                // caps lock state and mark as if shift key pressed while normal state.
+                shiftKeyState.onPress();
+                setManualTemporaryUpperCase(true);
+            } else if (isAutomaticTemporaryUpperCase()) {
+                // Shift key is pressed while automatic temporary upper case, we have to move to
+                // manual temporary upper case.
+                shiftKeyState.onPress();
+                setManualTemporaryUpperCase(true);
+            } else if (isShiftedOrShiftLocked()) {
+                // In manual upper case state, we just record shift key has been pressing while
+                // shifted state.
+                shiftKeyState.onPressOnShifted();
+            } else {
+                // In base layout, chording or manual temporary upper case mode is started.
+                shiftKeyState.onPress();
+                toggleShift();
+            }
+        } else {
+            // In symbol mode, just toggle symbol and symbol more keyboard.
+            shiftKeyState.onPress();
+            toggleShift();
+        }
+    }
+
+    public void onReleaseShift() {
+        if (!isKeyboardAvailable())
+            return;
+        ShiftKeyState shiftKeyState = mShiftKeyState;
+        if (DEBUG_STATE)
+            Log.d(TAG, "onReleaseShift:"
+                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+                    + " shiftKeyState=" + shiftKeyState);
+        if (isAlphabetMode()) {
+            if (shiftKeyState.isMomentary()) {
+                // After chording input while normal state.
+                toggleShift();
+            } else if (isShiftLocked() && !shiftKeyState.isIgnoring()) {
+                // Shift has been pressed without chording while caps lock state.
+                toggleCapsLock();
+            } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()) {
+                // Shift has been pressed without chording while shifted state.
+                toggleShift();
+            }
+        }
+        shiftKeyState.onRelease();
+    }
+
+    public void onPressSymbol() {
+        if (DEBUG_STATE)
+            Log.d(TAG, "onReleaseShift:"
+                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+                    + " symbolKeyState=" + mSymbolKeyState);
+        changeKeyboardMode();
+        mSymbolKeyState.onPress();
+    }
+
+    public void onReleaseSymbol() {
+        if (DEBUG_STATE)
+            Log.d(TAG, "onReleaseShift:"
+                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+                    + " symbolKeyState=" + mSymbolKeyState);
+        if (mSymbolKeyState.isMomentary())
+            changeKeyboardMode();
+        mSymbolKeyState.onRelease();
+    }
+
+    public void onOtherKeyPressed() {
+        if (DEBUG_STATE)
+            Log.d(TAG, "onOtherKeyPressed:"
+                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
+                    + " shiftKeyState=" + mShiftKeyState
+                    + " symbolKeyState=" + mSymbolKeyState);
+        mShiftKeyState.onOtherKeyPressed();
+        mSymbolKeyState.onOtherKeyPressed();
+    }
+
+    private void toggleShiftInSymbol() {
+        if (isAlphabetMode())
+            return;
+        final LatinKeyboard keyboard;
+        if (mCurrentId.equals(mSymbolsId) || !mCurrentId.equals(mSymbolsShiftedId)) {
+            mCurrentId = mSymbolsShiftedId;
+            keyboard = getKeyboard(mCurrentId);
+            // Symbol shifted keyboard has an ALT key that has a caps lock style indicator. To
+            // enable the indicator, we need to call enableShiftLock() and setShiftLocked(true).
+            // Thus we can keep the ALT key's Key.on value true while LatinKey.onRelease() is
+            // called.
+            keyboard.setShiftLocked(true);
+        } else {
+            mCurrentId = mSymbolsId;
+            keyboard = getKeyboard(mCurrentId);
+            // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the
+            // indicator, we need to call enableShiftLock() and setShiftLocked(false).
+            keyboard.setShifted(false);
+        }
+        mInputView.setKeyboard(keyboard);
+    }
+
+    private void toggleKeyboardMode() {
+        loadKeyboardInternal(mMode, mImeOptions, mVoiceKeyEnabled, mVoiceButtonOnPrimary,
+                !mIsSymbols);
+        if (mIsSymbols) {
+            mSymbolsModeState = SYMBOLS_MODE_STATE_BEGIN;
+        } else {
+            mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
+        }
+    }
+
+    public boolean hasDistinctMultitouch() {
+        return mInputView != null && mInputView.hasDistinctMultitouch();
+    }
+
+    /**
+     * Updates state machine to figure out when to automatically switch back to alpha mode.
+     */
+    public void onKey(int key) {
+        // Switch back to alpha mode if user types one or more non-space/enter
+        // characters followed by a space/enter
+        switch (mSymbolsModeState) {
+        case SYMBOLS_MODE_STATE_BEGIN:
+            if (key != Keyboard.CODE_SPACE && key != Keyboard.CODE_ENTER && key > 0) {
+                mSymbolsModeState = SYMBOLS_MODE_STATE_SYMBOL;
+            }
+            break;
+        case SYMBOLS_MODE_STATE_SYMBOL:
+            if (key == Keyboard.CODE_ENTER || key == Keyboard.CODE_SPACE) {
+                changeKeyboardMode();
+            }
+            break;
+        }
+    }
+
+    public LatinKeyboardView getInputView() {
+        return mInputView;
+    }
+
+    public LatinKeyboardView onCreateInputView() {
+        createInputViewInternal(mLayoutId, true);
+        return mInputView;
+    }
+
+    private void createInputViewInternal(int newLayout, boolean forceReset) {
+        if (mLayoutId != newLayout || mInputView == null || forceReset) {
+            if (mInputView != null) {
+                mInputView.closing();
+            }
+            if (THEMES.length <= newLayout) {
+                newLayout = Integer.valueOf(DEFAULT_LAYOUT_ID);
+            }
+
+            LatinIMEUtil.GCUtils.getInstance().reset();
+            boolean tryGC = true;
+            for (int i = 0; i < LatinIMEUtil.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
+                try {
+                    mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater(
+                            ).inflate(THEMES[newLayout], null);
+                    tryGC = false;
+                } catch (OutOfMemoryError e) {
+                    Log.w(TAG, "load keyboard failed: " + e);
+                    tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait(
+                            mLayoutId + "," + newLayout, e);
+                } catch (InflateException e) {
+                    Log.w(TAG, "load keyboard failed: " + e);
+                    tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait(
+                            mLayoutId + "," + newLayout, e);
+                }
+            }
+            mInputView.setOnKeyboardActionListener(mInputMethodService);
+            mLayoutId = newLayout;
+        }
+    }
+
+    private void postSetInputView() {
+        mInputMethodService.mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mInputView != null) {
+                    mInputMethodService.setInputView(mInputView);
+                }
+                mInputMethodService.updateInputViewShown();
+            }
+        });
+    }
+
+    @Override
+    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+        if (PREF_KEYBOARD_LAYOUT.equals(key)) {
+            final int layoutId = Integer.valueOf(
+                    sharedPreferences.getString(key, DEFAULT_LAYOUT_ID));
+            createInputViewInternal(layoutId, false);
+            postSetInputView();
+        } else if (LatinIMESettings.PREF_SETTINGS_KEY.equals(key)) {
+            mHasSettingsKey = getSettingsKeyMode(sharedPreferences, mInputMethodService);
+            createInputViewInternal(mLayoutId, true);
+            postSetInputView();
+        }
+    }
+
+    private int getColorScheme() {
+        return (mInputView != null)
+                ? mInputView.getColorScheme() : KeyboardView.COLOR_SCHEME_WHITE;
+    }
+
+    public void onAutoCompletionStateChanged(boolean isAutoCompletion) {
+        if (isAutoCompletion != mIsAutoCompletionActive) {
+            LatinKeyboardView keyboardView = getInputView();
+            mIsAutoCompletionActive = isAutoCompletion;
+            keyboardView.invalidateKey(((LatinKeyboard) keyboardView.getKeyboard())
+                    .onAutoCompletionStateChanged(isAutoCompletion));
+        }
+    }
+
+    private static boolean getSettingsKeyMode(SharedPreferences prefs, Context context) {
+        Resources resources = context.getResources();
+        final boolean showSettingsKeyOption = resources.getBoolean(
+                R.bool.config_enable_show_settings_key_option);
+        if (showSettingsKeyOption) {
+            final String settingsKeyMode = prefs.getString(LatinIMESettings.PREF_SETTINGS_KEY,
+                    resources.getString(DEFAULT_SETTINGS_KEY_MODE));
+            // We show the settings key when 1) SETTINGS_KEY_MODE_ALWAYS_SHOW or
+            // 2) SETTINGS_KEY_MODE_AUTO and there are two or more enabled IMEs on the system
+            if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW))
+                    || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO))
+                            && LatinIMEUtil.hasMultipleEnabledIMEsOrSubtypes(
+                                    ((InputMethodManager) context.getSystemService(
+                                            Context.INPUT_METHOD_SERVICE))))) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
similarity index 66%
rename from java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
rename to java/src/com/android/inputmethod/keyboard/KeyboardView.java
index b1ef085..c54b1b4 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -14,7 +14,11 @@
  * limitations under the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.keyboard;
+
+import com.android.inputmethod.latin.LatinImeLogger;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SubtypeSwitcher;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -29,8 +33,6 @@
 import android.graphics.Region.Op;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
-import android.inputmethodservice.Keyboard;
-import android.inputmethodservice.Keyboard.Key;
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
@@ -43,132 +45,56 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
 import android.widget.PopupWindow;
 import android.widget.TextView;
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.WeakHashMap;
 
 /**
- * A view that renders a virtual {@link LatinKeyboard}. It handles rendering of keys and
- * detecting key presses and touch movements.
+ * A view that renders a virtual {@link Keyboard}. It handles rendering of keys and detecting key
+ * presses and touch movements.
  *
- * TODO: References to LatinKeyboard in this class should be replaced with ones to its base class.
- *
- * @attr ref R.styleable#LatinKeyboardBaseView_keyBackground
- * @attr ref R.styleable#LatinKeyboardBaseView_keyPreviewLayout
- * @attr ref R.styleable#LatinKeyboardBaseView_keyPreviewOffset
- * @attr ref R.styleable#LatinKeyboardBaseView_labelTextSize
- * @attr ref R.styleable#LatinKeyboardBaseView_keyTextSize
- * @attr ref R.styleable#LatinKeyboardBaseView_keyTextColor
- * @attr ref R.styleable#LatinKeyboardBaseView_verticalCorrection
- * @attr ref R.styleable#LatinKeyboardBaseView_popupLayout
+ * @attr ref R.styleable#KeyboardView_keyBackground
+ * @attr ref R.styleable#KeyboardView_keyPreviewLayout
+ * @attr ref R.styleable#KeyboardView_keyPreviewOffset
+ * @attr ref R.styleable#KeyboardView_labelTextSize
+ * @attr ref R.styleable#KeyboardView_keyTextSize
+ * @attr ref R.styleable#KeyboardView_keyTextColor
+ * @attr ref R.styleable#KeyboardView_verticalCorrection
+ * @attr ref R.styleable#KeyboardView_popupLayout
  */
-public class LatinKeyboardBaseView extends View implements PointerTracker.UIProxy {
-    private static final String TAG = "LatinKeyboardBaseView";
+public class KeyboardView extends View implements PointerTracker.UIProxy {
+    private static final String TAG = "KeyboardView";
     private static final boolean DEBUG = false;
+    private static final boolean DEBUG_SHOW_ALIGN = false;
+    private static final boolean DEBUG_KEYBOARD_GRID = false;
+
+    private static final boolean ENABLE_CAPSLOCK_BY_LONGPRESS = false;
+    private static final boolean ENABLE_CAPSLOCK_BY_DOUBLETAP = true;
+
+    public static final int COLOR_SCHEME_WHITE = 0;
+    public static final int COLOR_SCHEME_BLACK = 1;
 
     public static final int NOT_A_TOUCH_COORDINATE = -1;
 
-    public interface OnKeyboardActionListener {
-
-        /**
-         * Called when the user presses a key. This is sent before the
-         * {@link #onKey} is called. For keys that repeat, this is only
-         * called once.
-         *
-         * @param primaryCode
-         *            the unicode of the key being pressed. If the touch is
-         *            not on a valid key, the value will be zero.
-         */
-        void onPress(int primaryCode);
-
-        /**
-         * Called when the user releases a key. This is sent after the
-         * {@link #onKey} is called. For keys that repeat, this is only
-         * called once.
-         *
-         * @param primaryCode
-         *            the code of the key that was released
-         */
-        void onRelease(int primaryCode);
-
-        /**
-         * Send a key press to the listener.
-         *
-         * @param primaryCode
-         *            this is the key that was pressed
-         * @param keyCodes
-         *            the codes for all the possible alternative keys with
-         *            the primary code being the first. If the primary key
-         *            code is a single character such as an alphabet or
-         *            number or symbol, the alternatives will include other
-         *            characters that may be on the same key or adjacent
-         *            keys. These codes are useful to correct for
-         *            accidental presses of a key adjacent to the intended
-         *            key.
-         * @param x
-         *            x-coordinate pixel of touched event. If onKey is not called by onTouchEvent,
-         *            the value should be NOT_A_TOUCH_COORDINATE.
-         * @param y
-         *            y-coordinate pixel of touched event. If onKey is not called by onTouchEvent,
-         *            the value should be NOT_A_TOUCH_COORDINATE.
-         */
-        void onKey(int primaryCode, int[] keyCodes, int x, int y);
-
-        /**
-         * Sends a sequence of characters to the listener.
-         *
-         * @param text
-         *            the sequence of characters to be displayed.
-         */
-        void onText(CharSequence text);
-
-        /**
-         * Called when user released a finger outside any key.
-         */
-        void onCancel();
-
-        /**
-         * Called when the user quickly moves the finger from right to
-         * left.
-         */
-        void swipeLeft();
-
-        /**
-         * Called when the user quickly moves the finger from left to
-         * right.
-         */
-        void swipeRight();
-
-        /**
-         * Called when the user quickly moves the finger from up to down.
-         */
-        void swipeDown();
-
-        /**
-         * Called when the user quickly moves the finger from down to up.
-         */
-        void swipeUp();
-    }
-
     // Timing constants
     private final int mKeyRepeatInterval;
 
     // Miscellaneous constants
-    /* package */ static final int NOT_A_KEY = -1;
     private static final int[] LONG_PRESSABLE_STATE_SET = { android.R.attr.state_long_pressable };
-    private static final int NUMBER_HINT_VERTICAL_ADJUSTMENT_PIXEL = -1;
+    private static final int HINT_ICON_VERTICAL_ADJUSTMENT_PIXEL = -1;
 
     // XML attribute
-    private int mKeyTextSize;
+    private int mKeyLetterSize;
     private int mKeyTextColor;
-    private Typeface mKeyTextStyle = Typeface.DEFAULT;
+    private int mKeyTextColorDisabled;
+    private Typeface mKeyLetterStyle = Typeface.DEFAULT;
     private int mLabelTextSize;
-    private int mSymbolColorScheme = 0;
+    private int mColorScheme = COLOR_SCHEME_WHITE;
     private int mShadowColor;
     private float mShadowRadius;
     private Drawable mKeyBackground;
@@ -182,15 +108,14 @@
     // Main keyboard
     private Keyboard mKeyboard;
     private Key[] mKeys;
-    // TODO this attribute should be gotten from Keyboard.
-    private int mKeyboardVerticalGap;
 
     // Key preview popup
+    private boolean mInForeground;
     private TextView mPreviewText;
     private PopupWindow mPreviewPopup;
     private int mPreviewTextSizeLarge;
     private int[] mOffsetInWindow;
-    private int mOldPreviewKeyIndex = NOT_A_KEY;
+    private int mOldPreviewKeyIndex = KeyDetector.NOT_A_KEY;
     private boolean mShowPreview = true;
     private boolean mShowTouchPoints = true;
     private int mPopupPreviewOffsetX;
@@ -202,7 +127,7 @@
 
     // Popup mini keyboard
     private PopupWindow mMiniKeyboardPopup;
-    private LatinKeyboardBaseView mMiniKeyboard;
+    private KeyboardView mMiniKeyboard;
     private View mMiniKeyboardParent;
     private final WeakHashMap<Key, View> mMiniKeyboardCache = new WeakHashMap<Key, View>();
     private int mMiniKeyboardOriginX;
@@ -212,13 +137,13 @@
     private final float mMiniKeyboardSlideAllowance;
     private int mMiniKeyboardTrackerId;
 
-    /** Listener for {@link OnKeyboardActionListener}. */
-    private OnKeyboardActionListener mKeyboardActionListener;
+    /** Listener for {@link KeyboardActionListener}. */
+    private KeyboardActionListener mKeyboardActionListener;
 
     private final ArrayList<PointerTracker> mPointerTrackers = new ArrayList<PointerTracker>();
 
     // TODO: Let the PointerTracker class manage this pointer queue
-    private final PointerQueue mPointerQueue = new PointerQueue();
+    private final PointerTrackerQueue mPointerQueue = new PointerTrackerQueue();
 
     private final boolean mHasDistinctMultitouch;
     private int mOldPointerCount = 1;
@@ -248,9 +173,15 @@
     private final Rect mClipRegion = new Rect(0, 0, 0, 0);
     // This map caches key label text height in pixel as value and key label text size as map key.
     private final HashMap<Integer, Integer> mTextHeightCache = new HashMap<Integer, Integer>();
-    // Distance from horizontal center of the key, proportional to key label text height.
-    private final float KEY_LABEL_VERTICAL_ADJUSTMENT_FACTOR = 0.55f;
-    private final String KEY_LABEL_HEIGHT_REFERENCE_CHAR = "H";
+    // Distance from horizontal center of the key, proportional to key label text height and width.
+    private final float KEY_LABEL_VERTICAL_ADJUSTMENT_FACTOR_CENTER = 0.55f;
+    private final float KEY_LABEL_VERTICAL_PADDING_FACTOR = 1.60f;
+    private final String KEY_LABEL_REFERENCE_CHAR = "H";
+    private final int KEY_LABEL_OPTION_ALIGN_LEFT = 1;
+    private final int KEY_LABEL_OPTION_ALIGN_RIGHT = 2;
+    private final int KEY_LABEL_OPTION_ALIGN_BOTTOM = 8;
+    private final int KEY_LABEL_OPTION_FONT_NORMAL = 16;
+    private final int mKeyLabelHorizontalPadding;
 
     private final UIHandler mHandler = new UIHandler();
 
@@ -259,6 +190,7 @@
         private static final int MSG_DISMISS_PREVIEW = 2;
         private static final int MSG_REPEAT_KEY = 3;
         private static final int MSG_LONGPRESS_KEY = 4;
+        private static final int MSG_LONGPRESS_SHIFT_KEY = 5;
 
         private boolean mInKeyRepeat;
 
@@ -282,6 +214,11 @@
                     openPopupIfRequired(msg.arg1, tracker);
                     break;
                 }
+                case MSG_LONGPRESS_SHIFT_KEY: {
+                    final PointerTracker tracker = (PointerTracker)msg.obj;
+                    onLongPressShiftKey(tracker);
+                    break;
+                }
             }
         }
 
@@ -325,17 +262,26 @@
         }
 
         public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker) {
-            removeMessages(MSG_LONGPRESS_KEY);
+            cancelLongPressTimers();
             sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, keyIndex, 0, tracker), delay);
         }
 
-        public void cancelLongPressTimer() {
+        public void startLongPressShiftTimer(long delay, int keyIndex, PointerTracker tracker) {
+            cancelLongPressTimers();
+            if (ENABLE_CAPSLOCK_BY_LONGPRESS) {
+                sendMessageDelayed(
+                        obtainMessage(MSG_LONGPRESS_SHIFT_KEY, keyIndex, 0, tracker), delay);
+            }
+        }
+
+        public void cancelLongPressTimers() {
             removeMessages(MSG_LONGPRESS_KEY);
+            removeMessages(MSG_LONGPRESS_SHIFT_KEY);
         }
 
         public void cancelKeyTimers() {
             cancelKeyRepeatTimer();
-            cancelLongPressTimer();
+            cancelLongPressTimers();
         }
 
         public void cancelAllMessages() {
@@ -345,63 +291,15 @@
         }
     };
 
-    static class PointerQueue {
-        private LinkedList<PointerTracker> mQueue = new LinkedList<PointerTracker>();
-
-        public void add(PointerTracker tracker) {
-            mQueue.add(tracker);
-        }
-
-        public int lastIndexOf(PointerTracker tracker) {
-            LinkedList<PointerTracker> queue = mQueue;
-            for (int index = queue.size() - 1; index >= 0; index--) {
-                PointerTracker t = queue.get(index);
-                if (t == tracker)
-                    return index;
-            }
-            return -1;
-        }
-
-        public void releaseAllPointersOlderThan(PointerTracker tracker, long eventTime) {
-            LinkedList<PointerTracker> queue = mQueue;
-            int oldestPos = 0;
-            for (PointerTracker t = queue.get(oldestPos); t != tracker; t = queue.get(oldestPos)) {
-                if (t.isModifier()) {
-                    oldestPos++;
-                } else {
-                    t.onUpEvent(t.getLastX(), t.getLastY(), eventTime);
-                    t.setAlreadyProcessed();
-                    queue.remove(oldestPos);
-                }
-            }
-        }
-
-        public void releaseAllPointersExcept(PointerTracker tracker, long eventTime) {
-            for (PointerTracker t : mQueue) {
-                if (t == tracker)
-                    continue;
-                t.onUpEvent(t.getLastX(), t.getLastY(), eventTime);
-                t.setAlreadyProcessed();
-            }
-            mQueue.clear();
-            if (tracker != null)
-                mQueue.add(tracker);
-        }
-
-        public void remove(PointerTracker tracker) {
-            mQueue.remove(tracker);
-        }
-    }
-
-    public LatinKeyboardBaseView(Context context, AttributeSet attrs) {
+    public KeyboardView(Context context, AttributeSet attrs) {
         this(context, attrs, R.attr.keyboardViewStyle);
     }
 
-    public LatinKeyboardBaseView(Context context, AttributeSet attrs, int defStyle) {
+    public KeyboardView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
         TypedArray a = context.obtainStyledAttributes(
-                attrs, R.styleable.LatinKeyboardBaseView, defStyle, R.style.LatinKeyboardBaseView);
+                attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
         LayoutInflater inflate =
                 (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
         int previewLayout = 0;
@@ -413,63 +311,54 @@
             int attr = a.getIndex(i);
 
             switch (attr) {
-            case R.styleable.LatinKeyboardBaseView_keyBackground:
+            case R.styleable.KeyboardView_keyBackground:
                 mKeyBackground = a.getDrawable(attr);
                 break;
-            case R.styleable.LatinKeyboardBaseView_keyHysteresisDistance:
+            case R.styleable.KeyboardView_keyHysteresisDistance:
                 mKeyHysteresisDistance = a.getDimensionPixelOffset(attr, 0);
                 break;
-            case R.styleable.LatinKeyboardBaseView_verticalCorrection:
+            case R.styleable.KeyboardView_verticalCorrection:
                 mVerticalCorrection = a.getDimensionPixelOffset(attr, 0);
                 break;
-            case R.styleable.LatinKeyboardBaseView_keyPreviewLayout:
+            case R.styleable.KeyboardView_keyPreviewLayout:
                 previewLayout = a.getResourceId(attr, 0);
                 break;
-            case R.styleable.LatinKeyboardBaseView_keyPreviewOffset:
+            case R.styleable.KeyboardView_keyPreviewOffset:
                 mPreviewOffset = a.getDimensionPixelOffset(attr, 0);
                 break;
-            case R.styleable.LatinKeyboardBaseView_keyPreviewHeight:
+            case R.styleable.KeyboardView_keyPreviewHeight:
                 mPreviewHeight = a.getDimensionPixelSize(attr, 80);
                 break;
-            case R.styleable.LatinKeyboardBaseView_keyTextSize:
-                mKeyTextSize = a.getDimensionPixelSize(attr, 18);
+            case R.styleable.KeyboardView_keyLetterSize:
+                mKeyLetterSize = a.getDimensionPixelSize(attr, 18);
                 break;
-            case R.styleable.LatinKeyboardBaseView_keyTextColor:
+            case R.styleable.KeyboardView_keyTextColor:
                 mKeyTextColor = a.getColor(attr, 0xFF000000);
                 break;
-            case R.styleable.LatinKeyboardBaseView_labelTextSize:
+            case R.styleable.KeyboardView_keyTextColorDisabled:
+                mKeyTextColorDisabled = a.getColor(attr, 0xFF000000);
+                break;
+            case R.styleable.KeyboardView_labelTextSize:
                 mLabelTextSize = a.getDimensionPixelSize(attr, 14);
                 break;
-            case R.styleable.LatinKeyboardBaseView_popupLayout:
+            case R.styleable.KeyboardView_popupLayout:
                 mPopupLayout = a.getResourceId(attr, 0);
                 break;
-            case R.styleable.LatinKeyboardBaseView_shadowColor:
+            case R.styleable.KeyboardView_shadowColor:
                 mShadowColor = a.getColor(attr, 0);
                 break;
-            case R.styleable.LatinKeyboardBaseView_shadowRadius:
+            case R.styleable.KeyboardView_shadowRadius:
                 mShadowRadius = a.getFloat(attr, 0f);
                 break;
             // TODO: Use Theme (android.R.styleable.Theme_backgroundDimAmount)
-            case R.styleable.LatinKeyboardBaseView_backgroundDimAmount:
+            case R.styleable.KeyboardView_backgroundDimAmount:
                 mBackgroundDimAmount = a.getFloat(attr, 0.5f);
                 break;
-            //case android.R.styleable.
-            case R.styleable.LatinKeyboardBaseView_keyTextStyle:
-                int textStyle = a.getInt(attr, 0);
-                switch (textStyle) {
-                    case 0:
-                        mKeyTextStyle = Typeface.DEFAULT;
-                        break;
-                    case 1:
-                        mKeyTextStyle = Typeface.DEFAULT_BOLD;
-                        break;
-                    default:
-                        mKeyTextStyle = Typeface.defaultFromStyle(textStyle);
-                        break;
-                }
+            case R.styleable.KeyboardView_keyLetterStyle:
+                mKeyLetterStyle = Typeface.defaultFromStyle(a.getInt(attr, Typeface.NORMAL));
                 break;
-            case R.styleable.LatinKeyboardBaseView_symbolColorScheme:
-                mSymbolColorScheme = a.getInt(attr, 0);
+            case R.styleable.KeyboardView_colorScheme:
+                mColorScheme = a.getInt(attr, COLOR_SCHEME_WHITE);
                 break;
             }
         }
@@ -489,6 +378,8 @@
         mPreviewPopup.setAnimationStyle(R.style.KeyPreviewAnimation);
         mDelayBeforePreview = res.getInteger(R.integer.config_delay_before_preview);
         mDelayAfterPreview = res.getInteger(R.integer.config_delay_after_preview);
+        mKeyLabelHorizontalPadding = (int)res.getDimension(
+                R.dimen.key_label_horizontal_alignment_padding);
 
         mMiniKeyboardParent = this;
         mMiniKeyboardPopup = new PopupWindow(context);
@@ -511,6 +402,8 @@
 
         GestureDetector.SimpleOnGestureListener listener =
                 new GestureDetector.SimpleOnGestureListener() {
+            private boolean mProcessingDoubleTapEvent = false;
+
             @Override
             public boolean onFling(MotionEvent me1, MotionEvent me2, float velocityX,
                     float velocityY) {
@@ -546,6 +439,28 @@
                 }
                 return false;
             }
+
+            @Override
+            public boolean onDoubleTap(MotionEvent e) {
+                if (ENABLE_CAPSLOCK_BY_DOUBLETAP && mKeyboard instanceof LatinKeyboard
+                        && ((LatinKeyboard) mKeyboard).isAlphaKeyboard()) {
+                    final int pointerIndex = e.getActionIndex();
+                    final int id = e.getPointerId(pointerIndex);
+                    final PointerTracker tracker = getPointerTracker(id);
+                    if (tracker.isOnShiftKey((int)e.getX(), (int)e.getY())) {
+                        onDoubleTapShiftKey(tracker);
+                        mProcessingDoubleTapEvent = true;
+                        return true;
+                    }
+                }
+                mProcessingDoubleTapEvent = false;
+                return false;
+            }
+
+            @Override
+            public boolean onDoubleTapEvent(MotionEvent e) {
+                return mProcessingDoubleTapEvent;
+            }
         };
 
         final boolean ignoreMultitouch = true;
@@ -557,7 +472,7 @@
         mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval);
     }
 
-    public void setOnKeyboardActionListener(OnKeyboardActionListener listener) {
+    public void setOnKeyboardActionListener(KeyboardActionListener listener) {
         mKeyboardActionListener = listener;
         for (PointerTracker tracker : mPointerTrackers) {
             tracker.setOnKeyboardActionListener(listener);
@@ -565,10 +480,10 @@
     }
 
     /**
-     * Returns the {@link OnKeyboardActionListener} object.
+     * Returns the {@link KeyboardActionListener} object.
      * @return the listener attached to this keyboard
      */
-    protected OnKeyboardActionListener getOnKeyboardActionListener() {
+    protected KeyboardActionListener getOnKeyboardActionListener() {
         return mKeyboardActionListener;
     }
 
@@ -590,15 +505,14 @@
         LatinImeLogger.onSetKeyboard(keyboard);
         mKeys = mKeyDetector.setKeyboard(keyboard, -getPaddingLeft(),
                 -getPaddingTop() + mVerticalCorrection);
-        mKeyboardVerticalGap = (int)getResources().getDimension(R.dimen.key_bottom_gap);
         for (PointerTracker tracker : mPointerTrackers) {
-            tracker.setKeyboard(mKeys, mKeyHysteresisDistance);
+            tracker.setKeyboard(keyboard, mKeys, mKeyHysteresisDistance);
         }
         requestLayout();
         // Hint to reallocate the buffer if the size changed
         mKeyboardChanged = true;
         invalidateAllKeys();
-        computeProximityThreshold(keyboard);
+        computeProximityThreshold(keyboard, mKeys);
         mMiniKeyboardCache.clear();
     }
 
@@ -615,39 +529,12 @@
      * Return whether the device has distinct multi-touch panel.
      * @return true if the device has distinct multi-touch panel.
      */
+    @Override
     public boolean hasDistinctMultitouch() {
         return mHasDistinctMultitouch;
     }
 
     /**
-     * Sets the state of the shift key of the keyboard, if any.
-     * @param shifted whether or not to enable the state of the shift key
-     * @return true if the shift key state changed, false if there was no change
-     */
-    public boolean setShifted(boolean shifted) {
-        if (mKeyboard != null) {
-            if (mKeyboard.setShifted(shifted)) {
-                // The whole keyboard probably needs to be redrawn
-                invalidateAllKeys();
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * Returns the state of the shift key of the keyboard, if any.
-     * @return true if the shift is in a pressed state, false otherwise. If there is
-     * no shift key on the keyboard or there is no keyboard attached, it returns false.
-     */
-    public boolean isShifted() {
-        if (mKeyboard != null) {
-            return mKeyboard.isShifted();
-        }
-        return false;
-    }
-
-    /**
      * Enables or disables the key feedback popup. This is a popup that shows a magnified
      * version of the depressed key. By default the preview is enabled.
      * @param previewEnabled whether or not to enable the key feedback popup
@@ -666,8 +553,8 @@
         return mShowPreview;
     }
 
-    public int getSymbolColorScheme() {
-        return mSymbolColorScheme;
+    public int getColorScheme() {
+        return mColorScheme;
     }
 
     public void setPopupParent(View v) {
@@ -681,7 +568,7 @@
     }
 
     /**
-     * When enabled, calls to {@link OnKeyboardActionListener#onKey} will include key
+     * When enabled, calls to {@link KeyboardActionListener#onKey} will include key
      * codes for adjacent keys.  When disabled, only the primary key code will be
      * reported.
      * @param enabled whether or not the proximity correction is enabled
@@ -698,7 +585,7 @@
     }
 
     protected CharSequence adjustCase(CharSequence label) {
-        if (mKeyboard.isShifted() && label != null && label.length() < 3
+        if (mKeyboard.isShiftedOrShiftLocked() && label != null && label.length() < 3
                 && Character.isLowerCase(label.charAt(0))) {
             label = label.toString().toUpperCase();
         }
@@ -722,23 +609,27 @@
     }
 
     /**
-     * Compute the average distance between adjacent keys (horizontally and vertically)
-     * and square it to get the proximity threshold. We use a square here and in computing
-     * the touch distance from a key's center to avoid taking a square root.
+     * Compute the most common key width and use it as proximity key detection threshold.
      * @param keyboard
+     * @param keys
      */
-    private void computeProximityThreshold(Keyboard keyboard) {
-        if (keyboard == null) return;
-        final Key[] keys = mKeys;
-        if (keys == null) return;
-        int length = keys.length;
-        int dimensionSum = 0;
-        for (int i = 0; i < length; i++) {
-            Key key = keys[i];
-            dimensionSum += Math.min(key.width, key.height + mKeyboardVerticalGap) + key.gap;
+    private void computeProximityThreshold(Keyboard keyboard, Key[] keys) {
+        if (keyboard == null || keys == null || keys.length == 0) return;
+        final HashMap<Integer, Integer> histogram = new HashMap<Integer, Integer>();
+        int maxCount = 0;
+        int mostCommonWidth = 0;
+        for (Key key : keys) {
+            final Integer width = key.mWidth + key.mGap;
+            Integer count = histogram.get(width);
+            if (count == null)
+                count = 0;
+            histogram.put(width, ++count);
+            if (count > maxCount) {
+                maxCount = count;
+                mostCommonWidth = width;
+            }
         }
-        if (dimensionSum < 0 || length == 0) return;
-        mKeyDetector.setProximityThreshold((int) (dimensionSum * 1.4f / length));
+        mKeyDetector.setProximityThreshold(mostCommonWidth);
     }
 
     @Override
@@ -757,6 +648,7 @@
         canvas.drawBitmap(mBuffer, 0, 0, null);
     }
 
+    @SuppressWarnings("unused")
     private void onBufferDraw() {
         if (mBuffer == null || mKeyboardChanged) {
             if (mBuffer == null || mKeyboardChanged &&
@@ -783,16 +675,16 @@
         final int kbdPaddingTop = getPaddingTop();
         final Key[] keys = mKeys;
         final Key invalidKey = mInvalidatedKey;
+        final boolean isManualTemporaryUpperCase = mKeyboard.isManualTemporaryUpperCase();
 
-        paint.setColor(mKeyTextColor);
         boolean drawSingleKey = false;
         if (invalidKey != null && canvas.getClipBounds(clipRegion)) {
             // TODO we should use Rect.inset and Rect.contains here.
             // Is clipRegion completely contained within the invalidated key?
-            if (invalidKey.x + kbdPaddingLeft - 1 <= clipRegion.left &&
-                    invalidKey.y + kbdPaddingTop - 1 <= clipRegion.top &&
-                    invalidKey.x + invalidKey.width + kbdPaddingLeft + 1 >= clipRegion.right &&
-                    invalidKey.y + invalidKey.height + kbdPaddingTop + 1 >= clipRegion.bottom) {
+            if (invalidKey.mX + kbdPaddingLeft - 1 <= clipRegion.left &&
+                    invalidKey.mY + kbdPaddingTop - 1 <= clipRegion.top &&
+                    invalidKey.mX + invalidKey.mWidth + kbdPaddingLeft + 1 >= clipRegion.right &&
+                    invalidKey.mY + invalidKey.mHeight + kbdPaddingTop + 1 >= clipRegion.bottom) {
                 drawSingleKey = true;
             }
         }
@@ -807,77 +699,122 @@
             keyBackground.setState(drawableState);
 
             // Switch the character to uppercase if shift is pressed
-            String label = key.label == null? null : adjustCase(key.label).toString();
+            String label = key.mLabel == null? null : adjustCase(key.mLabel).toString();
 
             final Rect bounds = keyBackground.getBounds();
-            if (key.width != bounds.right || key.height != bounds.bottom) {
-                keyBackground.setBounds(0, 0, key.width, key.height);
+            if (key.mWidth != bounds.right || key.mHeight != bounds.bottom) {
+                keyBackground.setBounds(0, 0, key.mWidth, key.mHeight);
             }
-            canvas.translate(key.x + kbdPaddingLeft, key.y + kbdPaddingTop);
+            canvas.translate(key.mX + kbdPaddingLeft, key.mY + kbdPaddingTop);
             keyBackground.draw(canvas);
 
-            boolean shouldDrawIcon = true;
+            final int rowHeight = padding.top + key.mHeight;
+            // Draw key label
             if (label != null) {
                 // For characters, use large font. For labels like "Done", use small font.
-                final int labelSize;
-                if (label.length() > 1 && key.codes.length < 2) {
-                    labelSize = mLabelTextSize;
-                    paint.setTypeface(Typeface.DEFAULT_BOLD);
-                } else {
-                    labelSize = mKeyTextSize;
-                    paint.setTypeface(mKeyTextStyle);
-                }
-                paint.setTextSize(labelSize);
+                final int labelSize = getLabelSizeAndSetPaint(label, key, paint);
+                final int labelCharHeight = getLabelCharHeight(labelSize, paint);
 
-                Integer labelHeightValue = mTextHeightCache.get(labelSize);
-                final int labelHeight;
-                if (labelHeightValue != null) {
-                    labelHeight = labelHeightValue;
-                } else {
-                    Rect textBounds = new Rect();
-                    paint.getTextBounds(KEY_LABEL_HEIGHT_REFERENCE_CHAR, 0, 1, textBounds);
-                    labelHeight = textBounds.height();
-                    mTextHeightCache.put(labelSize, labelHeight);
+                // Vertical label text alignment.
+                final float baseline;
+                if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_BOTTOM) != 0) {
+                    baseline = key.mHeight -
+                            + labelCharHeight * KEY_LABEL_VERTICAL_PADDING_FACTOR;
+                    if (DEBUG_SHOW_ALIGN)
+                        drawHorizontalLine(canvas, (int)baseline, key.mWidth, 0xc0008000,
+                                new Paint());
+                } else { // Align center
+                    final float centerY = (key.mHeight + padding.top - padding.bottom) / 2;
+                    baseline = centerY
+                            + labelCharHeight * KEY_LABEL_VERTICAL_ADJUSTMENT_FACTOR_CENTER;
                 }
-
-                // Draw a drop shadow for the text
+                // Horizontal label text alignment
+                final int positionX;
+                if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_LEFT) != 0) {
+                    positionX = mKeyLabelHorizontalPadding + padding.left;
+                    paint.setTextAlign(Align.LEFT);
+                    if (DEBUG_SHOW_ALIGN)
+                        drawVerticalLine(canvas, positionX, rowHeight, 0xc0800080, new Paint());
+                } else if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_RIGHT) != 0) {
+                    positionX = key.mWidth - mKeyLabelHorizontalPadding - padding.right;
+                    paint.setTextAlign(Align.RIGHT);
+                    if (DEBUG_SHOW_ALIGN)
+                        drawVerticalLine(canvas, positionX, rowHeight, 0xc0808000, new Paint());
+                } else {
+                    positionX = (key.mWidth + padding.left - padding.right) / 2;
+                    paint.setTextAlign(Align.CENTER);
+                    if (DEBUG_SHOW_ALIGN && label.length() > 1)
+                        drawVerticalLine(canvas, positionX, rowHeight, 0xc0008080, new Paint());
+                }
+                if (key.mManualTemporaryUpperCaseHintIcon != null && isManualTemporaryUpperCase) {
+                    paint.setColor(mKeyTextColorDisabled);
+                } else {
+                    paint.setColor(mKeyTextColor);
+                }
+                // Set a drop shadow for the text
                 paint.setShadowLayer(mShadowRadius, 0, 0, mShadowColor);
-                final int centerX = (key.width + padding.left - padding.right) / 2;
-                final int centerY = (key.height + padding.top - padding.bottom) / 2;
-                final float baseline = centerY
-                        + labelHeight * KEY_LABEL_VERTICAL_ADJUSTMENT_FACTOR;
-                canvas.drawText(label, centerX, baseline, paint);
+                canvas.drawText(label, positionX, baseline, paint);
                 // Turn off drop shadow
                 paint.setShadowLayer(0, 0, 0, 0);
-
-                // Usually don't draw icon if label is not null, but we draw icon for the number
-                // hint and popup hint.
-                shouldDrawIcon = shouldDrawLabelAndIcon(key);
             }
-            if (key.icon != null && shouldDrawIcon) {
-                // Special handing for the upper-right number hint icons
-                final int drawableWidth;
-                final int drawableHeight;
+            // Draw key icon
+            final Drawable icon = key.getIcon();
+            if (key.mLabel == null && icon != null) {
+                final int drawableWidth = icon.getIntrinsicWidth();
+                final int drawableHeight = icon.getIntrinsicHeight();
                 final int drawableX;
-                final int drawableY;
-                if (shouldDrawIconFully(key)) {
-                    drawableWidth = key.width;
-                    drawableHeight = key.height;
-                    drawableX = 0;
-                    drawableY = NUMBER_HINT_VERTICAL_ADJUSTMENT_PIXEL;
-                } else {
-                    drawableWidth = key.icon.getIntrinsicWidth();
-                    drawableHeight = key.icon.getIntrinsicHeight();
-                    drawableX = (key.width + padding.left - padding.right - drawableWidth) / 2;
-                    drawableY = (key.height + padding.top - padding.bottom - drawableHeight) / 2;
+                final int drawableY = (
+                        key.mHeight + padding.top - padding.bottom - drawableHeight) / 2;
+                if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_LEFT) != 0) {
+                    drawableX = padding.left + mKeyLabelHorizontalPadding;
+                    if (DEBUG_SHOW_ALIGN)
+                        drawVerticalLine(canvas, drawableX, rowHeight, 0xc0800080, new Paint());
+                } else if ((key.mLabelOption & KEY_LABEL_OPTION_ALIGN_RIGHT) != 0) {
+                    drawableX = key.mWidth - padding.right - mKeyLabelHorizontalPadding
+                            - drawableWidth;
+                    if (DEBUG_SHOW_ALIGN)
+                        drawVerticalLine(canvas, drawableX + drawableWidth, rowHeight,
+                                0xc0808000, new Paint());
+                } else { // Align center
+                    drawableX = (key.mWidth + padding.left - padding.right - drawableWidth) / 2;
+                    if (DEBUG_SHOW_ALIGN)
+                        drawVerticalLine(canvas, drawableX + drawableWidth / 2, rowHeight,
+                                0xc0008080, new Paint());
                 }
-                canvas.translate(drawableX, drawableY);
-                key.icon.setBounds(0, 0, drawableWidth, drawableHeight);
-                key.icon.draw(canvas);
-                canvas.translate(-drawableX, -drawableY);
+                drawIcon(canvas, icon, drawableX, drawableY, drawableWidth, drawableHeight);
+                if (DEBUG_SHOW_ALIGN)
+                    drawRectangle(canvas, drawableX, drawableY, drawableWidth, drawableHeight,
+                            0x80c00000, new Paint());
             }
-            canvas.translate(-key.x - kbdPaddingLeft, -key.y - kbdPaddingTop);
+            if (key.mHintIcon != null) {
+                final int drawableWidth = key.mWidth;
+                final int drawableHeight = key.mHeight;
+                final int drawableX = 0;
+                final int drawableY = HINT_ICON_VERTICAL_ADJUSTMENT_PIXEL;
+                Drawable hintIcon = (isManualTemporaryUpperCase
+                        && key.mManualTemporaryUpperCaseHintIcon != null)
+                        ? key.mManualTemporaryUpperCaseHintIcon : key.mHintIcon;
+                drawIcon(canvas, hintIcon, drawableX, drawableY, drawableWidth, drawableHeight);
+                if (DEBUG_SHOW_ALIGN)
+                    drawRectangle(canvas, drawableX, drawableY, drawableWidth, drawableHeight,
+                            0x80c0c000, new Paint());
+            }
+            canvas.translate(-key.mX - kbdPaddingLeft, -key.mY - kbdPaddingTop);
         }
+
+        if (DEBUG_KEYBOARD_GRID) {
+            Paint p = new Paint();
+            p.setStyle(Paint.Style.STROKE);
+            p.setStrokeWidth(1.0f);
+            p.setColor(0x800000c0);
+            int cw = (mKeyboard.getMinWidth() + mKeyboard.GRID_WIDTH - 1) / mKeyboard.GRID_WIDTH;
+            int ch = (mKeyboard.getHeight() + mKeyboard.GRID_HEIGHT - 1) / mKeyboard.GRID_HEIGHT;
+            for (int i = 0; i <= mKeyboard.GRID_WIDTH; i++)
+                canvas.drawLine(i * cw, 0, i * cw, ch * mKeyboard.GRID_HEIGHT, p);
+            for (int i = 0; i <= mKeyboard.GRID_HEIGHT; i++)
+                canvas.drawLine(0, i * ch, cw * mKeyboard.GRID_WIDTH, i * ch, p);
+        }
+
         mInvalidatedKey = null;
         // Overlay a dark rectangle to dim the keyboard
         if (mMiniKeyboard != null) {
@@ -908,28 +845,98 @@
         mDirtyRect.setEmpty();
     }
 
+    private int getLabelSizeAndSetPaint(CharSequence label, Key key, Paint paint) {
+        // For characters, use large font. For labels like "Done", use small font.
+        final int labelSize;
+        final Typeface labelStyle;
+        if (label.length() > 1 && key.mCodes.length < 2) {
+            labelSize = mLabelTextSize;
+            if ((key.mLabelOption & KEY_LABEL_OPTION_FONT_NORMAL) != 0) {
+                labelStyle = Typeface.DEFAULT;
+            } else {
+                labelStyle = Typeface.DEFAULT_BOLD;
+            }
+        } else {
+            labelSize = mKeyLetterSize;
+            labelStyle = mKeyLetterStyle;
+        }
+        paint.setTextSize(labelSize);
+        paint.setTypeface(labelStyle);
+        return labelSize;
+    }
+
+    private int getLabelCharHeight(int labelSize, Paint paint) {
+        Integer labelHeightValue = mTextHeightCache.get(labelSize);
+        final int labelCharHeight;
+        if (labelHeightValue != null) {
+            labelCharHeight = labelHeightValue;
+        } else {
+            Rect textBounds = new Rect();
+            paint.getTextBounds(KEY_LABEL_REFERENCE_CHAR, 0, 1, textBounds);
+            labelCharHeight = textBounds.height();
+            mTextHeightCache.put(labelSize, labelCharHeight);
+        }
+        return labelCharHeight;
+    }
+
+    private static void drawIcon(Canvas canvas, Drawable icon, int x, int y, int width,
+            int height) {
+        canvas.translate(x, y);
+        icon.setBounds(0, 0, width, height);
+        icon.draw(canvas);
+        canvas.translate(-x, -y);
+    }
+
+    private static void drawHorizontalLine(Canvas canvas, int y, int w, int color, Paint paint) {
+        paint.setStyle(Paint.Style.STROKE);
+        paint.setStrokeWidth(1.0f);
+        paint.setColor(color);
+        canvas.drawLine(0, y, w, y, paint);
+    }
+
+    private static void drawVerticalLine(Canvas canvas, int x, int h, int color, Paint paint) {
+        paint.setStyle(Paint.Style.STROKE);
+        paint.setStrokeWidth(1.0f);
+        paint.setColor(color);
+        canvas.drawLine(x, 0, x, h, paint);
+    }
+
+    private static void drawRectangle(Canvas canvas, int x, int y, int w, int h, int color,
+            Paint paint) {
+        paint.setStyle(Paint.Style.STROKE);
+        paint.setStrokeWidth(1.0f);
+        paint.setColor(color);
+        canvas.translate(x, y);
+        canvas.drawRect(0, 0, w, h, paint);
+        canvas.translate(-x, -y);
+    }
+
+    public void setForeground(boolean foreground) {
+        mInForeground = foreground;
+    }
+
     // TODO: clean up this method.
     private void dismissKeyPreview() {
         for (PointerTracker tracker : mPointerTrackers)
-            tracker.updateKey(NOT_A_KEY);
-        showPreview(NOT_A_KEY, null);
+            tracker.releaseKey();
+        showPreview(KeyDetector.NOT_A_KEY, null);
     }
 
+    @Override
     public void showPreview(int keyIndex, PointerTracker tracker) {
         int oldKeyIndex = mOldPreviewKeyIndex;
         mOldPreviewKeyIndex = keyIndex;
-        final boolean isLanguageSwitchEnabled = (mKeyboard instanceof LatinKeyboard)
-                && ((LatinKeyboard)mKeyboard).isLanguageSwitchEnabled();
         // We should re-draw popup preview when 1) we need to hide the preview, 2) we will show
         // the space key preview and 3) pointer moves off the space key to other letter key, we
         // should hide the preview of the previous key.
+        @SuppressWarnings("unused")
         final boolean hidePreviewOrShowSpaceKeyPreview = (tracker == null)
-                || tracker.isSpaceKey(keyIndex) || tracker.isSpaceKey(oldKeyIndex);
+                || (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER
+                        && SubtypeSwitcher.getInstance().needsToDisplayLanguage()
+                        && (tracker.isSpaceKey(keyIndex) || tracker.isSpaceKey(oldKeyIndex)));
         // If key changed and preview is on or the key is space (language switch is enabled)
-        if (oldKeyIndex != keyIndex
-                && (mShowPreview
-                        || (hidePreviewOrShowSpaceKeyPreview && isLanguageSwitchEnabled))) {
-            if (keyIndex == NOT_A_KEY) {
+        if (oldKeyIndex != keyIndex && (mShowPreview || (hidePreviewOrShowSpaceKeyPreview))) {
+            if (keyIndex == KeyDetector.NOT_A_KEY) {
                 mHandler.cancelPopupPreview();
                 mHandler.dismissPreview(mDelayAfterPreview);
             } else if (tracker != null) {
@@ -938,29 +945,35 @@
         }
     }
 
+    // TODO Must fix popup preview on xlarge layout
     private void showKey(final int keyIndex, PointerTracker tracker) {
         Key key = tracker.getKey(keyIndex);
-        if (key == null)
+        // If keyIndex is invalid or IME is already closed, we must not show key preview.
+        // Trying to show preview PopupWindow while root window is closed causes
+        // WindowManager.BadTokenException.
+        if (key == null || !mInForeground)
             return;
-        // Should not draw hint icon in key preview
-        if (key.icon != null && !shouldDrawLabelAndIcon(key)) {
-            mPreviewText.setCompoundDrawables(null, null, null,
-                    key.iconPreview != null ? key.iconPreview : key.icon);
-            mPreviewText.setText(null);
-        } else {
+        // What we show as preview should match what we show on key top in onBufferDraw(). 
+        if (key.mLabel != null) {
+            // TODO Should take care of temporaryShiftLabel here.
             mPreviewText.setCompoundDrawables(null, null, null, null);
             mPreviewText.setText(adjustCase(tracker.getPreviewText(key)));
-            if (key.label.length() > 1 && key.codes.length < 2) {
-                mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyTextSize);
+            if (key.mLabel.length() > 1 && key.mCodes.length < 2) {
+                mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyLetterSize);
                 mPreviewText.setTypeface(Typeface.DEFAULT_BOLD);
             } else {
                 mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mPreviewTextSizeLarge);
-                mPreviewText.setTypeface(mKeyTextStyle);
+                mPreviewText.setTypeface(mKeyLetterStyle);
             }
+        } else {
+            final Drawable previewIcon = key.getPreviewIcon();
+            mPreviewText.setCompoundDrawables(null, null, null,
+                   previewIcon != null ? previewIcon : key.getIcon());
+            mPreviewText.setText(null);
         }
         mPreviewText.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                 MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
-        int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.width
+        int popupWidth = Math.max(mPreviewText.getMeasuredWidth(), key.mWidth
                 + mPreviewText.getPaddingLeft() + mPreviewText.getPaddingRight());
         final int popupHeight = mPreviewHeight;
         LayoutParams lp = mPreviewText.getLayoutParams();
@@ -969,8 +982,8 @@
             lp.height = popupHeight;
         }
 
-        int popupPreviewX = key.x - (popupWidth - key.width) / 2;
-        int popupPreviewY = key.y - popupHeight + mPreviewOffset;
+        int popupPreviewX = key.mX - (popupWidth - key.mWidth) / 2;
+        int popupPreviewY = key.mY - popupHeight + mPreviewOffset;
 
         mHandler.cancelDismissPreview();
         if (mOffsetInWindow == null) {
@@ -984,7 +997,7 @@
         }
         // Set the preview background state
         mPreviewText.getBackground().setState(
-                key.popupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET);
+                key.mPopupResId != 0 ? LONG_PRESSABLE_STATE_SET : EMPTY_STATE_SET);
         popupPreviewX += mOffsetInWindow[0];
         popupPreviewY += mOffsetInWindow[1];
 
@@ -992,21 +1005,26 @@
         if (popupPreviewY + mWindowY < 0) {
             // If the key you're pressing is on the left side of the keyboard, show the popup on
             // the right, offset by enough to see at least one key to the left/right.
-            if (key.x + key.width <= getWidth() / 2) {
-                popupPreviewX += (int) (key.width * 2.5);
+            if (key.mX + key.mWidth <= getWidth() / 2) {
+                popupPreviewX += (int) (key.mWidth * 2.5);
             } else {
-                popupPreviewX -= (int) (key.width * 2.5);
+                popupPreviewX -= (int) (key.mWidth * 2.5);
             }
             popupPreviewY += popupHeight;
         }
 
-        if (mPreviewPopup.isShowing()) {
-            mPreviewPopup.update(popupPreviewX, popupPreviewY, popupWidth, popupHeight);
-        } else {
-            mPreviewPopup.setWidth(popupWidth);
-            mPreviewPopup.setHeight(popupHeight);
-            mPreviewPopup.showAtLocation(mMiniKeyboardParent, Gravity.NO_GRAVITY,
-                    popupPreviewX, popupPreviewY);
+        try {
+            if (mPreviewPopup.isShowing()) {
+                mPreviewPopup.update(popupPreviewX, popupPreviewY, popupWidth, popupHeight);
+            } else {
+                mPreviewPopup.setWidth(popupWidth);
+                mPreviewPopup.setHeight(popupHeight);
+                mPreviewPopup.showAtLocation(mMiniKeyboardParent, Gravity.NO_GRAVITY,
+                        popupPreviewX, popupPreviewY);
+            }
+        } catch (WindowManager.BadTokenException e) {
+            // Swallow the exception which will be happened when IME is already closed.
+            Log.w(TAG, "LatinIME is already closed when tried showing key preview.");
         }
         // Record popup preview position to display mini-keyboard later at the same positon
         mPopupPreviewDisplayedY = popupPreviewY;
@@ -1032,16 +1050,17 @@
      * @param key key in the attached {@link Keyboard}.
      * @see #invalidateAllKeys
      */
+    @Override
     public void invalidateKey(Key key) {
         if (key == null)
             return;
         mInvalidatedKey = key;
         // TODO we should clean up this and record key's region to use in onBufferDraw.
-        mDirtyRect.union(key.x + getPaddingLeft(), key.y + getPaddingTop(),
-                key.x + key.width + getPaddingLeft(), key.y + key.height + getPaddingTop());
+        mDirtyRect.union(key.mX + getPaddingLeft(), key.mY + getPaddingTop(),
+                key.mX + key.mWidth + getPaddingLeft(), key.mY + key.mHeight + getPaddingTop());
         onBufferDraw();
-        invalidate(key.x + getPaddingLeft(), key.y + getPaddingTop(),
-                key.x + key.width + getPaddingLeft(), key.y + key.height + getPaddingTop());
+        invalidate(key.mX + getPaddingLeft(), key.mY + getPaddingTop(),
+                key.mX + key.mWidth + getPaddingLeft(), key.mY + key.mHeight + getPaddingTop());
     }
 
     private boolean openPopupIfRequired(int keyIndex, PointerTracker tracker) {
@@ -1064,42 +1083,64 @@
         return result;
     }
 
+    private void onLongPressShiftKey(PointerTracker tracker) {
+        tracker.setAlreadyProcessed();
+        mPointerQueue.remove(tracker);
+        mKeyboardActionListener.onKey(Keyboard.CODE_CAPSLOCK, null, 0, 0);
+    }
+
+    private void onDoubleTapShiftKey(PointerTracker tracker) {
+        // When shift key is double tapped, the first tap is correctly processed as usual tap. And
+        // the second tap is treated as this double tap event, so that we need not mark tracker
+        // calling setAlreadyProcessed() nor remove the tracker from mPointerQueueueue.
+        mKeyboardActionListener.onKey(Keyboard.CODE_CAPSLOCK, null, 0, 0);
+    }
+
     private View inflateMiniKeyboardContainer(Key popupKey) {
-        int popupKeyboardId = popupKey.popupResId;
+        int popupKeyboardId = popupKey.mPopupResId;
         LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
         View container = inflater.inflate(mPopupLayout, null);
         if (container == null)
             throw new NullPointerException();
 
-        LatinKeyboardBaseView miniKeyboard =
-                (LatinKeyboardBaseView)container.findViewById(R.id.LatinKeyboardBaseView);
-        miniKeyboard.setOnKeyboardActionListener(new OnKeyboardActionListener() {
+        KeyboardView miniKeyboard =
+                (KeyboardView)container.findViewById(R.id.KeyboardView);
+        miniKeyboard.setOnKeyboardActionListener(new KeyboardActionListener() {
+            @Override
             public void onKey(int primaryCode, int[] keyCodes, int x, int y) {
                 mKeyboardActionListener.onKey(primaryCode, keyCodes, x, y);
                 dismissPopupKeyboard();
             }
 
+            @Override
             public void onText(CharSequence text) {
                 mKeyboardActionListener.onText(text);
                 dismissPopupKeyboard();
             }
 
+            @Override
             public void onCancel() {
                 dismissPopupKeyboard();
             }
 
+            @Override
             public void swipeLeft() {
             }
+            @Override
             public void swipeRight() {
             }
+            @Override
             public void swipeUp() {
             }
+            @Override
             public void swipeDown() {
             }
+            @Override
             public void onPress(int primaryCode) {
                 mKeyboardActionListener.onPress(primaryCode);
             }
+            @Override
             public void onRelease(int primaryCode) {
                 mKeyboardActionListener.onRelease(primaryCode);
             }
@@ -1110,8 +1151,8 @@
         miniKeyboard.mGestureDetector = null;
 
         Keyboard keyboard;
-        if (popupKey.popupCharacters != null) {
-            keyboard = new Keyboard(getContext(), popupKeyboardId, popupKey.popupCharacters,
+        if (popupKey.mPopupCharacters != null) {
+            keyboard = new Keyboard(getContext(), popupKeyboardId, popupKey.mPopupCharacters,
                     -1, getPaddingLeft() + getPaddingRight());
         } else {
             keyboard = new Keyboard(getContext(), popupKeyboardId);
@@ -1127,14 +1168,15 @@
 
     private static boolean isOneRowKeys(List<Key> keys) {
         if (keys.size() == 0) return false;
-        final int edgeFlags = keys.get(0).edgeFlags;
+        final int edgeFlags = keys.get(0).mEdgeFlags;
         // HACK: The first key of mini keyboard which was inflated from xml and has multiple rows,
         // does not have both top and bottom edge flags on at the same time.  On the other hand,
         // the first key of mini keyboard that was created with popupCharacters must have both top
         // and bottom edge flags on.
         // When you want to use one row mini-keyboard from xml file, make sure that the row has
         // both top and bottom edge flags set.
-        return (edgeFlags & Keyboard.EDGE_TOP) != 0 && (edgeFlags & Keyboard.EDGE_BOTTOM) != 0;
+        return (edgeFlags & Keyboard.EDGE_TOP) != 0
+                && (edgeFlags & Keyboard.EDGE_BOTTOM) != 0;
     }
 
     /**
@@ -1148,7 +1190,7 @@
         // TODO if popupKey.popupCharacters has only one letter, send it as key without opening
         // mini keyboard.
 
-        if (popupKey.popupResId == 0)
+        if (popupKey.mPopupResId == 0)
             return false;
 
         View container = mMiniKeyboardCache.get(popupKey);
@@ -1156,7 +1198,7 @@
             container = inflateMiniKeyboardContainer(popupKey);
             mMiniKeyboardCache.put(popupKey, container);
         }
-        mMiniKeyboard = (LatinKeyboardBaseView)container.findViewById(R.id.LatinKeyboardBaseView);
+        mMiniKeyboard = (KeyboardView)container.findViewById(R.id.KeyboardView);
         if (mWindowOffset == null) {
             mWindowOffset = new int[2];
             getLocationInWindow(mWindowOffset);
@@ -1170,22 +1212,22 @@
         //  b) When we have the rightmost key in popup keyboard directly above the pressed key
         //     Left edges of both keys should be aligned for consistent default selection
         final List<Key> miniKeys = mMiniKeyboard.getKeyboard().getKeys();
-        final int miniKeyWidth = miniKeys.size() > 0 ? miniKeys.get(0).width : 0;
+        final int miniKeyWidth = miniKeys.size() > 0 ? miniKeys.get(0).mWidth : 0;
 
         // HACK: Have the leftmost number in the popup characters right above the key
         boolean isNumberAtLeftmost =
                 hasMultiplePopupChars(popupKey) && isNumberAtLeftmostPopupChar(popupKey);
-        int popupX = popupKey.x + mWindowOffset[0];
+        int popupX = popupKey.mX + mWindowOffset[0];
         popupX += getPaddingLeft();
         if (isNumberAtLeftmost) {
-            popupX += popupKey.width - miniKeyWidth;  // adjustment for a) described above
+            popupX += popupKey.mWidth - miniKeyWidth;  // adjustment for a) described above
             popupX -= container.getPaddingLeft();
         } else {
             popupX += miniKeyWidth;  // adjustment for b) described above
             popupX -= container.getMeasuredWidth();
             popupX += container.getPaddingRight();
         }
-        int popupY = popupKey.y + mWindowOffset[1];
+        int popupY = popupKey.mY + mWindowOffset[1];
         popupY += getPaddingTop();
         popupY -= container.getMeasuredHeight();
         popupY += container.getPaddingBottom();
@@ -1201,7 +1243,11 @@
         mMiniKeyboardOriginX = adjustedX + container.getPaddingLeft() - mWindowOffset[0];
         mMiniKeyboardOriginY = y + container.getPaddingTop() - mWindowOffset[1];
         mMiniKeyboard.setPopupOffset(adjustedX, y);
-        mMiniKeyboard.setShifted(isShifted());
+        Keyboard baseMiniKeyboard = mMiniKeyboard.getKeyboard();
+        if (baseMiniKeyboard != null && baseMiniKeyboard.setShifted(mKeyboard == null
+                ? false : mKeyboard.isShiftedOrShiftLocked())) {
+            mMiniKeyboard.invalidateAllKeys();
+        }
         // Mini keyboard needs no pop-up key preview displayed.
         mMiniKeyboard.setPreviewEnabled(false);
         mMiniKeyboardPopup.setContentView(container);
@@ -1212,8 +1258,8 @@
         // Inject down event on the key to mini keyboard.
         long eventTime = SystemClock.uptimeMillis();
         mMiniKeyboardPopupTime = eventTime;
-        MotionEvent downEvent = generateMiniKeyboardMotionEvent(MotionEvent.ACTION_DOWN, popupKey.x
-                + popupKey.width / 2, popupKey.y + popupKey.height / 2, eventTime);
+        MotionEvent downEvent = generateMiniKeyboardMotionEvent(MotionEvent.ACTION_DOWN, popupKey.mX
+                + popupKey.mWidth / 2, popupKey.mY + popupKey.mHeight / 2, eventTime);
         mMiniKeyboard.onTouchEvent(downEvent);
         downEvent.recycle();
 
@@ -1222,45 +1268,15 @@
     }
 
     private static boolean hasMultiplePopupChars(Key key) {
-        if (key.popupCharacters != null && key.popupCharacters.length() > 1) {
+        if (key.mPopupCharacters != null && key.mPopupCharacters.length() > 1) {
             return true;
         }
         return false;
     }
 
-    private boolean shouldDrawIconFully(Key key) {
-        return isNumberAtEdgeOfPopupChars(key) || isLatinF1Key(key)
-                || LatinKeyboard.hasPuncOrSmileysPopup(key);
-    }
-
-    private boolean shouldDrawLabelAndIcon(Key key) {
-        return isNumberAtEdgeOfPopupChars(key) || isNonMicLatinF1Key(key)
-                || LatinKeyboard.hasPuncOrSmileysPopup(key);
-    }
-
-    private boolean isLatinF1Key(Key key) {
-        return (mKeyboard instanceof LatinKeyboard) && ((LatinKeyboard)mKeyboard).isF1Key(key);
-    }
-
-    private boolean isNonMicLatinF1Key(Key key) {
-        return isLatinF1Key(key) && key.label != null;
-    }
-
-    private static boolean isNumberAtEdgeOfPopupChars(Key key) {
-        return isNumberAtLeftmostPopupChar(key) || isNumberAtRightmostPopupChar(key);
-    }
-
-    /* package */ static boolean isNumberAtLeftmostPopupChar(Key key) {
-        if (key.popupCharacters != null && key.popupCharacters.length() > 0
-                && isAsciiDigit(key.popupCharacters.charAt(0))) {
-            return true;
-        }
-        return false;
-    }
-
-    /* package */ static boolean isNumberAtRightmostPopupChar(Key key) {
-        if (key.popupCharacters != null && key.popupCharacters.length() > 0
-                && isAsciiDigit(key.popupCharacters.charAt(key.popupCharacters.length() - 1))) {
+    private static boolean isNumberAtLeftmostPopupChar(Key key) {
+        if (key.mPopupCharacters != null && key.mPopupCharacters.length() > 0
+                && isAsciiDigit(key.mPopupCharacters.charAt(0))) {
             return true;
         }
         return false;
@@ -1278,14 +1294,14 @@
     private PointerTracker getPointerTracker(final int id) {
         final ArrayList<PointerTracker> pointers = mPointerTrackers;
         final Key[] keys = mKeys;
-        final OnKeyboardActionListener listener = mKeyboardActionListener;
+        final KeyboardActionListener listener = mKeyboardActionListener;
 
         // Create pointer trackers until we can get 'id+1'-th tracker, if needed.
         for (int i = pointers.size(); i <= id; i++) {
             final PointerTracker tracker =
                 new PointerTracker(i, mHandler, mKeyDetector, this, getResources());
             if (keys != null)
-                tracker.setKeyboard(keys, mKeyHysteresisDistance);
+                tracker.setKeyboard(mKeyboard, keys, mKeyHysteresisDistance);
             if (listener != null)
                 tracker.setOnKeyboardActionListener(listener);
             pointers.add(tracker);
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
new file mode 100644
index 0000000..e612b52
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2008 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 com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SubtypeSwitcher;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Align;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+
+import java.util.List;
+import java.util.Locale;
+
+// TODO: We should remove this class
+public class LatinKeyboard extends Keyboard {
+
+    private static final boolean DEBUG_PREFERRED_LETTER = false;
+    private static final String TAG = "LatinKeyboard";
+
+    public static final int OPACITY_FULLY_OPAQUE = 255;
+    private static final int SPACE_LED_LENGTH_PERCENT = 80;
+
+    private Drawable mShiftLockPreviewIcon;
+    private Drawable mSpaceAutoCompletionIndicator;
+    private final Drawable mButtonArrowLeftIcon;
+    private final Drawable mButtonArrowRightIcon;
+    private final int mSpaceBarTextShadowColor;
+    private int mSpaceKeyIndex = -1;
+    private int mSpaceDragStartX;
+    private int mSpaceDragLastDiff;
+    private final Resources mRes;
+    private final Context mContext;
+    private boolean mCurrentlyInSpace;
+    private SlidingLocaleDrawable mSlidingLocaleIcon;
+    private int[] mPrefLetterFrequencies;
+    private int mPrefLetter;
+    private int mPrefLetterX;
+    private int mPrefLetterY;
+    private int mPrefDistance;
+
+    private static final float SPACEBAR_DRAG_THRESHOLD = 0.8f;
+    private static final float OVERLAP_PERCENTAGE_LOW_PROB = 0.70f;
+    private static final float OVERLAP_PERCENTAGE_HIGH_PROB = 0.85f;
+    // Minimum width of space key preview (proportional to keyboard width)
+    private static final float SPACEBAR_POPUP_MIN_RATIO = 0.4f;
+    // Height in space key the language name will be drawn. (proportional to space key height)
+    public static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f;
+    // If the full language name needs to be smaller than this value to be drawn on space key,
+    // its short language name will be used instead.
+    private static final float MINIMUM_SCALE_OF_LANGUAGE_NAME = 0.8f;
+
+    private static int sSpacebarVerticalCorrection;
+
+    public LatinKeyboard(Context context, KeyboardId id) {
+        super(context, id);
+        final Resources res = context.getResources();
+        mContext = context;
+        mRes = res;
+        if (id.mColorScheme == KeyboardView.COLOR_SCHEME_BLACK) {
+            mSpaceBarTextShadowColor = res.getColor(
+                    R.color.latinkeyboard_bar_language_shadow_black);
+        } else { // default color scheme is KeyboardView.COLOR_SCHEME_WHITE
+            mSpaceBarTextShadowColor = res.getColor(
+                    R.color.latinkeyboard_bar_language_shadow_white);
+        }
+        mShiftLockPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_shift_locked);
+        setDefaultBounds(mShiftLockPreviewIcon);
+        mSpaceAutoCompletionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led);
+        mButtonArrowLeftIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_left);
+        mButtonArrowRightIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_right);
+        sSpacebarVerticalCorrection = res.getDimensionPixelOffset(
+                R.dimen.spacebar_vertical_correction);
+        mSpaceKeyIndex = indexOf(CODE_SPACE);
+    }
+
+    /**
+     * @return a key which should be invalidated.
+     */
+    public Key onAutoCompletionStateChanged(boolean isAutoCompletion) {
+        updateSpaceBarForLocale(isAutoCompletion);
+        return mSpaceKey;
+    }
+
+    private void updateSpaceBarForLocale(boolean isAutoCompletion) {
+        final Resources res = mRes;
+        // If application locales are explicitly selected.
+        if (SubtypeSwitcher.getInstance().needsToDisplayLanguage()) {
+            mSpaceKey.setIcon(new BitmapDrawable(res,
+                    drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCompletion)));
+        } else {
+            // sym_keyboard_space_led can be shared with Black and White symbol themes.
+            if (isAutoCompletion) {
+                mSpaceKey.setIcon(new BitmapDrawable(res,
+                        drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCompletion)));
+            } else {
+                mSpaceKey.setIcon(mSpaceIcon);
+            }
+        }
+    }
+
+    // Compute width of text with specified text size using paint.
+    private static int getTextWidth(Paint paint, String text, float textSize, Rect bounds) {
+        paint.setTextSize(textSize);
+        paint.getTextBounds(text, 0, text.length(), bounds);
+        return bounds.width();
+    }
+
+    // Layout local language name and left and right arrow on space bar.
+    private static String layoutSpaceBar(Paint paint, Locale locale, Drawable lArrow,
+            Drawable rArrow, int width, int height, float origTextSize,
+            boolean allowVariableTextSize) {
+        final float arrowWidth = lArrow.getIntrinsicWidth();
+        final float arrowHeight = lArrow.getIntrinsicHeight();
+        final float maxTextWidth = width - (arrowWidth + arrowWidth);
+        final Rect bounds = new Rect();
+
+        // Estimate appropriate language name text size to fit in maxTextWidth.
+        String language = SubtypeSwitcher.getDisplayLanguage(locale);
+        int textWidth = getTextWidth(paint, language, origTextSize, bounds);
+        // Assuming text width and text size are proportional to each other.
+        float textSize = origTextSize * Math.min(maxTextWidth / textWidth, 1.0f);
+
+        final boolean useShortName;
+        if (allowVariableTextSize) {
+            textWidth = getTextWidth(paint, language, textSize, bounds);
+            // If text size goes too small or text does not fit, use short name
+            useShortName = textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME
+                    || textWidth > maxTextWidth;
+        } else {
+            useShortName = textWidth > maxTextWidth;
+            textSize = origTextSize;
+        }
+        if (useShortName) {
+            language = SubtypeSwitcher.getShortDisplayLanguage(locale);
+            textWidth = getTextWidth(paint, language, origTextSize, bounds);
+            textSize = origTextSize * Math.min(maxTextWidth / textWidth, 1.0f);
+        }
+        paint.setTextSize(textSize);
+
+        // Place left and right arrow just before and after language text.
+        final float baseline = height * SPACEBAR_LANGUAGE_BASELINE;
+        final int top = (int)(baseline - arrowHeight);
+        final float remains = (width - textWidth) / 2;
+        lArrow.setBounds((int)(remains - arrowWidth), top, (int)remains, (int)baseline);
+        rArrow.setBounds((int)(remains + textWidth), top, (int)(remains + textWidth + arrowWidth),
+                (int)baseline);
+
+        return language;
+    }
+
+    @SuppressWarnings("unused")
+    private Bitmap drawSpaceBar(int opacity, boolean isAutoCompletion) {
+        final int width = mSpaceKey.mWidth;
+        final int height = mSpaceIcon.getIntrinsicHeight();
+        final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        final Canvas canvas = new Canvas(buffer);
+        final Resources res = mRes;
+        canvas.drawColor(res.getColor(R.color.latinkeyboard_transparent), PorterDuff.Mode.CLEAR);
+
+        SubtypeSwitcher subtypeSwitcher = SubtypeSwitcher.getInstance();
+        // If application locales are explicitly selected.
+        if (subtypeSwitcher.needsToDisplayLanguage()) {
+            final Paint paint = new Paint();
+            paint.setAlpha(opacity);
+            paint.setAntiAlias(true);
+            paint.setTextAlign(Align.CENTER);
+
+            final boolean allowVariableTextSize = true;
+            final String language = layoutSpaceBar(paint, subtypeSwitcher.getInputLocale(),
+                    mButtonArrowLeftIcon, mButtonArrowRightIcon, width, height,
+                    getTextSizeFromTheme(android.R.style.TextAppearance_Small, 14),
+                    allowVariableTextSize);
+
+            // Draw language text with shadow
+            final float baseline = height * SPACEBAR_LANGUAGE_BASELINE;
+            final float descent = paint.descent();
+            paint.setColor(mSpaceBarTextShadowColor);
+            canvas.drawText(language, width / 2, baseline - descent - 1, paint);
+            paint.setColor(res.getColor(R.color.latinkeyboard_bar_language_text));
+            canvas.drawText(language, width / 2, baseline - descent, paint);
+
+            // Put arrows that are already layed out on either side of the text
+            if (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER
+                    && subtypeSwitcher.getEnabledKeyboardLocaleCount() > 1) {
+                mButtonArrowLeftIcon.draw(canvas);
+                mButtonArrowRightIcon.draw(canvas);
+            }
+        }
+
+        // Draw the spacebar icon at the bottom
+        if (isAutoCompletion) {
+            final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100;
+            final int iconHeight = mSpaceAutoCompletionIndicator.getIntrinsicHeight();
+            int x = (width - iconWidth) / 2;
+            int y = height - iconHeight;
+            mSpaceAutoCompletionIndicator.setBounds(x, y, x + iconWidth, y + iconHeight);
+            mSpaceAutoCompletionIndicator.draw(canvas);
+        } else {
+            final int iconWidth = mSpaceIcon.getIntrinsicWidth();
+            final int iconHeight = mSpaceIcon.getIntrinsicHeight();
+            int x = (width - iconWidth) / 2;
+            int y = height - iconHeight;
+            mSpaceIcon.setBounds(x, y, x + iconWidth, y + iconHeight);
+            mSpaceIcon.draw(canvas);
+        }
+        return buffer;
+    }
+
+    private void updateLocaleDrag(int diff) {
+        if (mSlidingLocaleIcon == null) {
+            final int width = Math.max(mSpaceKey.mWidth,
+                    (int)(getMinWidth() * SPACEBAR_POPUP_MIN_RATIO));
+            final int height = mSpacePreviewIcon.getIntrinsicHeight();
+            mSlidingLocaleIcon =
+                    new SlidingLocaleDrawable(mContext, mSpacePreviewIcon, width, height);
+            mSlidingLocaleIcon.setBounds(0, 0, width, height);
+            mSpaceKey.setPreviewIcon(mSlidingLocaleIcon);
+        }
+        mSlidingLocaleIcon.setDiff(diff);
+        if (Math.abs(diff) == Integer.MAX_VALUE) {
+            mSpaceKey.setPreviewIcon(mSpacePreviewIcon);
+        } else {
+            mSpaceKey.setPreviewIcon(mSlidingLocaleIcon);
+        }
+        mSpaceKey.getPreviewIcon().invalidateSelf();
+    }
+
+    public int getLanguageChangeDirection() {
+        if (mSpaceKey == null || SubtypeSwitcher.getInstance().getEnabledKeyboardLocaleCount() <= 1
+                || Math.abs(mSpaceDragLastDiff) < mSpaceKey.mWidth * SPACEBAR_DRAG_THRESHOLD) {
+            return 0; // No change
+        }
+        return mSpaceDragLastDiff > 0 ? 1 : -1;
+    }
+
+    public void setPreferredLetters(int[] frequencies) {
+        mPrefLetterFrequencies = frequencies;
+        mPrefLetter = 0;
+    }
+
+    public void keyReleased() {
+        mCurrentlyInSpace = false;
+        mSpaceDragLastDiff = 0;
+        mPrefLetter = 0;
+        mPrefLetterX = 0;
+        mPrefLetterY = 0;
+        mPrefDistance = Integer.MAX_VALUE;
+        if (mSpaceKey != null) {
+            updateLocaleDrag(Integer.MAX_VALUE);
+        }
+    }
+
+    /**
+     * Does the magic of locking the touch gesture into the spacebar when
+     * switching input languages.
+     */
+    @Override
+    @SuppressWarnings("unused") // SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER is constant
+    public boolean isInside(Key key, int x, int y) {
+        final int code = key.mCodes[0];
+        if (code == CODE_SHIFT || code == CODE_DELETE) {
+            y -= key.mHeight / 10;
+            if (code == CODE_SHIFT) x += key.mWidth / 6;
+            if (code == CODE_DELETE) x -= key.mWidth / 6;
+        } else if (code == CODE_SPACE) {
+            y += LatinKeyboard.sSpacebarVerticalCorrection;
+            if (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER
+                    && SubtypeSwitcher.getInstance().getEnabledKeyboardLocaleCount() > 1) {
+                if (mCurrentlyInSpace) {
+                    int diff = x - mSpaceDragStartX;
+                    if (Math.abs(diff - mSpaceDragLastDiff) > 0) {
+                        updateLocaleDrag(diff);
+                    }
+                    mSpaceDragLastDiff = diff;
+                    return true;
+                } else {
+                    boolean isOnSpace = key.isOnKey(x, y);
+                    if (isOnSpace) {
+                        mCurrentlyInSpace = true;
+                        mSpaceDragStartX = x;
+                        updateLocaleDrag(0);
+                    }
+                    return isOnSpace;
+                }
+            }
+        } else if (mPrefLetterFrequencies != null) {
+            // New coordinate? Reset
+            if (mPrefLetterX != x || mPrefLetterY != y) {
+                mPrefLetter = 0;
+                mPrefDistance = Integer.MAX_VALUE;
+            }
+            // Handle preferred next letter
+            final int[] pref = mPrefLetterFrequencies;
+            if (mPrefLetter > 0) {
+                if (DEBUG_PREFERRED_LETTER) {
+                    if (mPrefLetter == code && !key.isOnKey(x, y)) {
+                        Log.d(TAG, "CORRECTED !!!!!!");
+                    }
+                }
+                return mPrefLetter == code;
+            } else {
+                final boolean isOnKey = key.isOnKey(x, y);
+                int[] nearby = getNearestKeys(x, y);
+                List<Key> nearbyKeys = getKeys();
+                if (isOnKey) {
+                    // If it's a preferred letter
+                    if (inPrefList(code, pref)) {
+                        // Check if its frequency is much lower than a nearby key
+                        mPrefLetter = code;
+                        mPrefLetterX = x;
+                        mPrefLetterY = y;
+                        for (int i = 0; i < nearby.length; i++) {
+                            Key k = nearbyKeys.get(nearby[i]);
+                            if (k != key && inPrefList(k.mCodes[0], pref)) {
+                                final int dist = distanceFrom(k, x, y);
+                                if (dist < (int) (k.mWidth * OVERLAP_PERCENTAGE_LOW_PROB) &&
+                                        (pref[k.mCodes[0]] > pref[mPrefLetter] * 3))  {
+                                    mPrefLetter = k.mCodes[0];
+                                    mPrefDistance = dist;
+                                    if (DEBUG_PREFERRED_LETTER) {
+                                        Log.d(TAG, "CORRECTED ALTHOUGH PREFERRED !!!!!!");
+                                    }
+                                    break;
+                                }
+                            }
+                        }
+
+                        return mPrefLetter == code;
+                    }
+                }
+
+                // Get the surrounding keys and intersect with the preferred list
+                // For all in the intersection
+                //   if distance from touch point is within a reasonable distance
+                //       make this the pref letter
+                // If no pref letter
+                //   return inside;
+                // else return thiskey == prefletter;
+
+                for (int i = 0; i < nearby.length; i++) {
+                    Key k = nearbyKeys.get(nearby[i]);
+                    if (inPrefList(k.mCodes[0], pref)) {
+                        final int dist = distanceFrom(k, x, y);
+                        if (dist < (int) (k.mWidth * OVERLAP_PERCENTAGE_HIGH_PROB)
+                                && dist < mPrefDistance)  {
+                            mPrefLetter = k.mCodes[0];
+                            mPrefLetterX = x;
+                            mPrefLetterY = y;
+                            mPrefDistance = dist;
+                        }
+                    }
+                }
+                // Didn't find any
+                if (mPrefLetter == 0) {
+                    return isOnKey;
+                } else {
+                    return mPrefLetter == code;
+                }
+            }
+        }
+
+        // Lock into the spacebar
+        if (mCurrentlyInSpace) return false;
+
+        return key.isOnKey(x, y);
+    }
+
+    private boolean inPrefList(int code, int[] pref) {
+        if (code < pref.length && code >= 0) return pref[code] > 0;
+        return false;
+    }
+
+    private int distanceFrom(Key k, int x, int y) {
+        if (y > k.mY && y < k.mY + k.mHeight) {
+            return Math.abs(k.mX + k.mWidth / 2 - x);
+        } else {
+            return Integer.MAX_VALUE;
+        }
+    }
+
+    @Override
+    public int[] getNearestKeys(int x, int y) {
+        if (mCurrentlyInSpace) {
+            return new int[] { mSpaceKeyIndex };
+        } else {
+            // Avoid dead pixels at edges of the keyboard
+            return super.getNearestKeys(Math.max(0, Math.min(x, getMinWidth() - 1)),
+                    Math.max(0, Math.min(y, getHeight() - 1)));
+        }
+    }
+
+    private int indexOf(int code) {
+        List<Key> keys = getKeys();
+        int count = keys.size();
+        for (int i = 0; i < count; i++) {
+            if (keys.get(i).mCodes[0] == code) return i;
+        }
+        return -1;
+    }
+
+    private int getTextSizeFromTheme(int style, int defValue) {
+        TypedArray array = mContext.getTheme().obtainStyledAttributes(
+                style, new int[] { android.R.attr.textSize });
+        int textSize = array.getDimensionPixelSize(array.getResourceId(0, 0), defValue);
+        return textSize;
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
similarity index 84%
rename from java/src/com/android/inputmethod/latin/LatinKeyboardView.java
rename to java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 22d39f7..5c1c62b 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -1,12 +1,12 @@
 /*
  * Copyright (C) 2008 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
@@ -14,13 +14,14 @@
  * the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.keyboard;
+
+import com.android.inputmethod.latin.LatinIMEUtil;
+import com.android.inputmethod.voice.VoiceIMEConnector;
 
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Paint;
-import android.inputmethodservice.Keyboard;
-import android.inputmethodservice.Keyboard.Key;
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
@@ -30,16 +31,8 @@
 
 import java.util.List;
 
-public class LatinKeyboardView extends LatinKeyboardBaseView {
-
-    static final int KEYCODE_OPTIONS = -100;
-    static final int KEYCODE_OPTIONS_LONGPRESS = -101;
-    static final int KEYCODE_VOICE = -102;
-    static final int KEYCODE_F1 = -103;
-    static final int KEYCODE_NEXT_LANGUAGE = -104;
-    static final int KEYCODE_PREV_LANGUAGE = -105;
-
-    private Keyboard mPhoneKeyboard;
+// TODO: We should remove this class
+public class LatinKeyboardView extends KeyboardView {
 
     /** Whether we've started dropping move events because we found a big jump */
     private boolean mDroppingEvents;
@@ -61,22 +54,19 @@
         super(context, attrs, defStyle);
     }
 
-    public void setPhoneKeyboard(Keyboard phoneKeyboard) {
-        mPhoneKeyboard = phoneKeyboard;
-    }
-
     @Override
     public void setPreviewEnabled(boolean previewEnabled) {
-        if (getKeyboard() == mPhoneKeyboard) {
-            // Phone keyboard never shows popup preview (except language switch).
+        LatinKeyboard latinKeyboard = getLatinKeyboard();
+        if (latinKeyboard != null
+                && (latinKeyboard.isPhoneKeyboard() || latinKeyboard.isNumberKeyboard())) {
+            // Phone and number keyboard never shows popup preview (except language switch).
             super.setPreviewEnabled(false);
         } else {
             super.setPreviewEnabled(previewEnabled);
         }
     }
 
-    @Override
-    public void setKeyboard(Keyboard k) {
+    public void setLatinKeyboard(LatinKeyboard k) {
         super.setKeyboard(k);
         // One-seventh of the keyboard width seems like a reasonable threshold
         mJumpThresholdSquare = k.getMinWidth() / 7;
@@ -86,12 +76,21 @@
         setKeyboardLocal(k);
     }
 
+    public LatinKeyboard getLatinKeyboard() {
+        Keyboard keyboard = getKeyboard();
+        if (keyboard instanceof LatinKeyboard) {
+            return (LatinKeyboard)keyboard;
+        } else {
+            return null;
+        }
+    }
+
     @Override
     protected boolean onLongPress(Key key) {
-        int primaryCode = key.codes[0];
-        if (primaryCode == KEYCODE_OPTIONS) {
-            return invokeOnKey(KEYCODE_OPTIONS_LONGPRESS);
-        } else if (primaryCode == '0' && getKeyboard() == mPhoneKeyboard) {
+        int primaryCode = key.mCodes[0];
+        if (primaryCode == Keyboard.CODE_SETTINGS) {
+            return invokeOnKey(Keyboard.CODE_SETTINGS_LONGPRESS);
+        } else if (primaryCode == '0' && getLatinKeyboard().isPhoneKeyboard()) {
             // Long pressing on 0 in phone number keypad gives you a '+'.
             return invokeOnKey('+');
         } else {
@@ -101,17 +100,16 @@
 
     private boolean invokeOnKey(int primaryCode) {
         getOnKeyboardActionListener().onKey(primaryCode, null,
-                LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE,
-                LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE);
+                KeyboardView.NOT_A_TOUCH_COORDINATE,
+                KeyboardView.NOT_A_TOUCH_COORDINATE);
         return true;
     }
 
     @Override
     protected CharSequence adjustCase(CharSequence label) {
-        Keyboard keyboard = getKeyboard();
-        if (keyboard.isShifted()
-                && keyboard instanceof LatinKeyboard
-                && ((LatinKeyboard) keyboard).isAlphaKeyboard()
+        LatinKeyboard keyboard = getLatinKeyboard();
+        if (keyboard.isAlphaKeyboard()
+                && keyboard.isShiftedOrShiftLocked()
                 && !TextUtils.isEmpty(label) && label.length() < 3
                 && Character.isLowerCase(label.charAt(0))) {
             label = label.toString().toUpperCase();
@@ -119,16 +117,6 @@
         return label;
     }
 
-    public boolean setShiftLocked(boolean shiftLocked) {
-        Keyboard keyboard = getKeyboard();
-        if (keyboard instanceof LatinKeyboard) {
-            ((LatinKeyboard)keyboard).setShiftLocked(shiftLocked);
-            invalidateAllKeys();
-            return true;
-        }
-        return false;
-    }
-
     /**
      * This function checks to see if we need to handle any sudden jumps in the pointer location
      * that could be due to a multi-touch being treated as a move by the firmware or hardware.
@@ -208,7 +196,7 @@
 
     @Override
     public boolean onTouchEvent(MotionEvent me) {
-        LatinKeyboard keyboard = (LatinKeyboard) getKeyboard();
+        LatinKeyboard keyboard = getLatinKeyboard();
         if (DEBUG_LINE) {
             mLastX = (int) me.getX();
             mLastY = (int) me.getY();
@@ -228,7 +216,8 @@
             int languageDirection = keyboard.getLanguageChangeDirection();
             if (languageDirection != 0) {
                 getOnKeyboardActionListener().onKey(
-                        languageDirection == 1 ? KEYCODE_NEXT_LANGUAGE : KEYCODE_PREV_LANGUAGE,
+                        languageDirection == 1
+                        ? Keyboard.CODE_NEXT_LANGUAGE : Keyboard.CODE_PREV_LANGUAGE,
                         null, mLastX, mLastY);
                 me.setAction(MotionEvent.ACTION_CANCEL);
                 keyboard.keyReleased();
@@ -241,8 +230,8 @@
 
     /****************************  INSTRUMENTATION  *******************************/
 
-    static final boolean DEBUG_AUTO_PLAY = false;
-    static final boolean DEBUG_LINE = false;
+    public static final boolean DEBUG_AUTO_PLAY = false;
+    public static final boolean DEBUG_LINE = false;
     private static final int MSG_TOUCH_DOWN = 1;
     private static final int MSG_TOUCH_UP = 2;
 
@@ -257,7 +246,7 @@
     private int mLastY;
     private Paint mPaint;
 
-    private void setKeyboardLocal(Keyboard k) {
+    private void setKeyboardLocal(LatinKeyboard k) {
         if (DEBUG_AUTO_PLAY) {
             findKeys();
             if (mHandler2 == null) {
@@ -283,8 +272,8 @@
                                     }
                                     c = mStringToPlay.charAt(mStringIndex);
                                 }
-                                int x = mAsciiKeys[c].x + 10;
-                                int y = mAsciiKeys[c].y + 26;
+                                int x = mAsciiKeys[c].mX + 10;
+                                int y = mAsciiKeys[c].mY + 26;
                                 MotionEvent me = MotionEvent.obtain(SystemClock.uptimeMillis(),
                                         SystemClock.uptimeMillis(),
                                         MotionEvent.ACTION_DOWN, x, y, 0);
@@ -296,8 +285,8 @@
                                 break;
                             case MSG_TOUCH_UP:
                                 char cUp = mStringToPlay.charAt(mStringIndex);
-                                int x2 = mAsciiKeys[cUp].x + 10;
-                                int y2 = mAsciiKeys[cUp].y + 26;
+                                int x2 = mAsciiKeys[cUp].mX + 10;
+                                int y2 = mAsciiKeys[cUp].mY + 26;
                                 mStringIndex++;
 
                                 MotionEvent me2 = MotionEvent.obtain(SystemClock.uptimeMillis(),
@@ -318,10 +307,10 @@
     }
 
     private void findKeys() {
-        List<Key> keys = getKeyboard().getKeys();
+        List<Key> keys = getLatinKeyboard().getKeys();
         // Get the keys on this keyboard
         for (int i = 0; i < keys.size(); i++) {
-            int code = keys.get(i).codes[0];
+            int code = keys.get(i).mCodes[0];
             if (code >= 0 && code <= 255) {
                 mAsciiKeys[code] = keys.get(i);
             }
@@ -372,4 +361,10 @@
             c.drawLine(0, mLastY, getWidth(), mLastY, mPaint);
         }
     }
+
+    @Override
+    protected void onAttachedToWindow() {
+        // Token is available from here.
+        VoiceIMEConnector.getInstance().onAttachedToWindow();
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/MiniKeyboardKeyDetector.java b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
similarity index 75%
rename from java/src/com/android/inputmethod/latin/MiniKeyboardKeyDetector.java
rename to java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
index 356e62d..774b39a 100644
--- a/java/src/com/android/inputmethod/latin/MiniKeyboardKeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/MiniKeyboardKeyDetector.java
@@ -14,11 +14,9 @@
  * the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.keyboard;
 
-import android.inputmethodservice.Keyboard.Key;
-
-class MiniKeyboardKeyDetector extends KeyDetector {
+public class MiniKeyboardKeyDetector extends KeyDetector {
     private static final int MAX_NEARBY_KEYS = 1;
 
     private final int mSlideAllowanceSquare;
@@ -41,19 +39,20 @@
         final Key[] keys = getKeys();
         final int touchX = getTouchX(x);
         final int touchY = getTouchY(y);
-        int closestKeyIndex = LatinKeyboardBaseView.NOT_A_KEY;
+
+        int closestKeyIndex = NOT_A_KEY;
         int closestKeyDist = (y < 0) ? mSlideAllowanceSquareTop : mSlideAllowanceSquare;
         final int keyCount = keys.length;
-        for (int i = 0; i < keyCount; i++) {
-            final Key key = keys[i];
-            int dist = key.squaredDistanceFrom(touchX, touchY);
+        for (int index = 0; index < keyCount; index++) {
+            final int dist = keys[index].squaredDistanceToEdge(touchX, touchY);
             if (dist < closestKeyDist) {
-                closestKeyIndex = i;
+                closestKeyIndex = index;
                 closestKeyDist = dist;
             }
         }
-        if (allKeys != null && closestKeyIndex != LatinKeyboardBaseView.NOT_A_KEY)
-            allKeys[0] = keys[closestKeyIndex].codes[0];
+
+        if (allKeys != null && closestKeyIndex != NOT_A_KEY)
+            allKeys[0] = keys[closestKeyIndex].mCodes[0];
         return closestKeyIndex;
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/ModifierKeyState.java b/java/src/com/android/inputmethod/keyboard/ModifierKeyState.java
new file mode 100644
index 0000000..1bd3d80
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/ModifierKeyState.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.util.Log;
+
+public class ModifierKeyState {
+    protected static final String TAG = "ModifierKeyState";
+    protected static final boolean DEBUG = KeyboardSwitcher.DEBUG_STATE;
+
+    protected static final int RELEASING = 0;
+    protected static final int PRESSING = 1;
+    protected static final int MOMENTARY = 2;
+
+    protected final String mName;
+    protected int mState = RELEASING;
+
+    public ModifierKeyState(String name) {
+        mName = name;
+    }
+
+    public void onPress() {
+        final int oldState = mState;
+        mState = PRESSING;
+        if (DEBUG)
+            Log.d(TAG, mName + ".onPress: " + toString(oldState) + " > " + this);
+    }
+
+    public void onRelease() {
+        final int oldState = mState;
+        mState = RELEASING;
+        if (DEBUG)
+            Log.d(TAG, mName + ".onRelease: " + toString(oldState) + " > " + this);
+    }
+
+    public void onOtherKeyPressed() {
+        final int oldState = mState;
+        if (oldState == PRESSING)
+            mState = MOMENTARY;
+        if (DEBUG)
+            Log.d(TAG, mName + ".onOtherKeyPressed: " + toString(oldState) + " > " + this);
+    }
+
+    public boolean isReleasing() {
+        return mState == RELEASING;
+    }
+
+    public boolean isMomentary() {
+        return mState == MOMENTARY;
+    }
+
+    @Override
+    public String toString() {
+        return toString(mState);
+    }
+
+    protected String toString(int state) {
+        switch (state) {
+        case RELEASING: return "RELEASING";
+        case PRESSING: return "PRESSING";
+        case MOMENTARY: return "MOMENTARY";
+        default: return "UNKNOWN";
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
similarity index 80%
rename from java/src/com/android/inputmethod/latin/PointerTracker.java
rename to java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 90218e4..8570491 100644
--- a/java/src/com/android/inputmethod/latin/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -14,14 +14,12 @@
  * the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.keyboard;
 
-import com.android.inputmethod.latin.LatinKeyboardBaseView.OnKeyboardActionListener;
-import com.android.inputmethod.latin.LatinKeyboardBaseView.UIHandler;
+import com.android.inputmethod.keyboard.KeyboardView.UIHandler;
+import com.android.inputmethod.latin.R;
 
 import android.content.res.Resources;
-import android.inputmethodservice.Keyboard;
-import android.inputmethodservice.Keyboard.Key;
 import android.util.Log;
 import android.view.MotionEvent;
 
@@ -41,18 +39,20 @@
     // Timing constants
     private final int mDelayBeforeKeyRepeatStart;
     private final int mLongPressKeyTimeout;
+    private final int mLongPressShiftKeyTimeout;
     private final int mMultiTapKeyTimeout;
 
     // Miscellaneous constants
-    private static final int NOT_A_KEY = LatinKeyboardBaseView.NOT_A_KEY;
-    private static final int[] KEY_DELETE = { Keyboard.KEYCODE_DELETE };
+    private static final int NOT_A_KEY = KeyDetector.NOT_A_KEY;
+    private static final int[] KEY_DELETE = { Keyboard.CODE_DELETE };
 
     private final UIProxy mProxy;
     private final UIHandler mHandler;
     private final KeyDetector mKeyDetector;
-    private OnKeyboardActionListener mListener;
+    private KeyboardActionListener mListener;
     private final boolean mHasDistinctMultitouch;
 
+    private Keyboard mKeyboard;
     private Key[] mKeys;
     private int mKeyHysteresisDistanceSquared = -1;
 
@@ -175,17 +175,19 @@
         mHasDistinctMultitouch = proxy.hasDistinctMultitouch();
         mDelayBeforeKeyRepeatStart = res.getInteger(R.integer.config_delay_before_key_repeat_start);
         mLongPressKeyTimeout = res.getInteger(R.integer.config_long_press_key_timeout);
+        mLongPressShiftKeyTimeout = res.getInteger(R.integer.config_long_press_shift_key_timeout);
         mMultiTapKeyTimeout = res.getInteger(R.integer.config_multi_tap_key_timeout);
         resetMultiTap();
     }
 
-    public void setOnKeyboardActionListener(OnKeyboardActionListener listener) {
+    public void setOnKeyboardActionListener(KeyboardActionListener listener) {
         mListener = listener;
     }
 
-    public void setKeyboard(Key[] keys, float keyHysteresisDistance) {
-        if (keys == null || keyHysteresisDistance < 0)
+    public void setKeyboard(Keyboard keyboard, Key[] keys, float keyHysteresisDistance) {
+        if (keyboard == null || keys == null || keyHysteresisDistance < 0)
             throw new IllegalArgumentException();
+        mKeyboard = keyboard;
         mKeys = keys;
         mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance);
         // Update current key index because keyboard layout has been changed.
@@ -204,9 +206,9 @@
         Key key = getKey(keyIndex);
         if (key == null)
             return false;
-        int primaryCode = key.codes[0];
-        return primaryCode == Keyboard.KEYCODE_SHIFT
-                || primaryCode == Keyboard.KEYCODE_MODE_CHANGE;
+        int primaryCode = key.mCodes[0];
+        return primaryCode == Keyboard.CODE_SHIFT
+                || primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL;
     }
 
     public boolean isModifier() {
@@ -217,14 +219,21 @@
         return isModifierInternal(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null));
     }
 
-    public boolean isSpaceKey(int keyIndex) {
-        Key key = getKey(keyIndex);
-        return key != null && key.codes[0] == LatinIME.KEYCODE_SPACE;
+    public boolean isOnShiftKey(int x, int y) {
+        final Key key = getKey(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null));
+        return key != null && key.mCodes[0] == Keyboard.CODE_SHIFT;
     }
 
-    public void updateKey(int keyIndex) {
-        if (mKeyAlreadyProcessed)
-            return;
+    public boolean isSpaceKey(int keyIndex) {
+        Key key = getKey(keyIndex);
+        return key != null && key.mCodes[0] == Keyboard.CODE_SPACE;
+    }
+
+    public void releaseKey() {
+        updateKeyGraphics(NOT_A_KEY);
+    }
+
+    private void updateKeyGraphics(int keyIndex) {
         int oldKeyIndex = mPreviousKey;
         mPreviousKey = keyIndex;
         if (keyIndex != oldKeyIndex) {
@@ -273,21 +282,21 @@
         checkMultiTap(eventTime, keyIndex);
         if (mListener != null) {
             if (isValidKeyIndex(keyIndex)) {
-                mListener.onPress(mKeys[keyIndex].codes[0]);
+                mListener.onPress(mKeys[keyIndex].mCodes[0]);
                 // This onPress call may have changed keyboard layout and have updated mKeyIndex.
                 // If that's the case, mKeyIndex has been updated in setKeyboard().
                 keyIndex = mKeyState.getKeyIndex();
             }
         }
         if (isValidKeyIndex(keyIndex)) {
-            if (mKeys[keyIndex].repeatable) {
+            if (mKeys[keyIndex].mRepeatable) {
                 repeatKey(keyIndex);
                 mHandler.startKeyRepeatTimer(mDelayBeforeKeyRepeatStart, keyIndex, this);
                 mIsRepeatableKey = true;
             }
-            mHandler.startLongPressTimer(mLongPressKeyTimeout, keyIndex, this);
+            startLongPressTimer(keyIndex);
         }
-        showKeyPreviewAndUpdateKey(keyIndex);
+        showKeyPreviewAndUpdateKeyGraphics(keyIndex);
     }
 
     public void onMoveEvent(int x, int y, long eventTime) {
@@ -301,32 +310,33 @@
         if (isValidKeyIndex(keyIndex)) {
             if (oldKey == null) {
                 keyState.onMoveToNewKey(keyIndex, x, y);
-                mHandler.startLongPressTimer(mLongPressKeyTimeout, keyIndex, this);
+                startLongPressTimer(keyIndex);
             } else if (!isMinorMoveBounce(x, y, keyIndex)) {
                 if (mListener != null)
-                    mListener.onRelease(oldKey.codes[0]);
+                    mListener.onRelease(oldKey.mCodes[0]);
                 resetMultiTap();
                 keyState.onMoveToNewKey(keyIndex, x, y);
-                mHandler.startLongPressTimer(mLongPressKeyTimeout, keyIndex, this);
+                startLongPressTimer(keyIndex);
             }
         } else {
             if (oldKey != null) {
                 if (mListener != null)
-                    mListener.onRelease(oldKey.codes[0]);
+                    mListener.onRelease(oldKey.mCodes[0]);
                 keyState.onMoveToNewKey(keyIndex, x ,y);
-                mHandler.cancelLongPressTimer();
+                mHandler.cancelLongPressTimers();
             } else if (!isMinorMoveBounce(x, y, keyIndex)) {
                 resetMultiTap();
                 keyState.onMoveToNewKey(keyIndex, x ,y);
-                mHandler.cancelLongPressTimer();
+                mHandler.cancelLongPressTimers();
             }
         }
-        showKeyPreviewAndUpdateKey(mKeyState.getKeyIndex());
+        showKeyPreviewAndUpdateKeyGraphics(mKeyState.getKeyIndex());
     }
 
     public void onUpEvent(int x, int y, long eventTime) {
         if (DEBUG)
             debugLog("onUpEvent  :", x, y);
+        showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY);
         if (mKeyAlreadyProcessed)
             return;
         mHandler.cancelKeyTimers();
@@ -338,7 +348,6 @@
             x = mKeyState.getKeyX();
             y = mKeyState.getKeyY();
         }
-        showKeyPreviewAndUpdateKey(NOT_A_KEY);
         if (!mIsRepeatableKey) {
             detectAndSendKey(keyIndex, x, y, eventTime);
         }
@@ -352,7 +361,7 @@
             debugLog("onCancelEvt:", x, y);
         mHandler.cancelKeyTimers();
         mHandler.cancelPopupPreview();
-        showKeyPreviewAndUpdateKey(NOT_A_KEY);
+        showKeyPreviewAndUpdateKeyGraphics(NOT_A_KEY);
         int keyIndex = mKeyState.getKeyIndex();
         if (isValidKeyIndex(keyIndex))
            mProxy.invalidateKey(mKeys[keyIndex]);
@@ -363,7 +372,7 @@
         if (key != null) {
             // While key is repeating, because there is no need to handle multi-tap key, we can
             // pass -1 as eventTime argument.
-            detectAndSendKey(keyIndex, key.x, key.y, -1);
+            detectAndSendKey(keyIndex, key.mX, key.mY, -1);
         }
     }
 
@@ -395,26 +404,14 @@
         if (newKey == curKey) {
             return true;
         } else if (isValidKeyIndex(curKey)) {
-            return getSquareDistanceToKeyEdge(x, y, mKeys[curKey]) < mKeyHysteresisDistanceSquared;
+            return mKeys[curKey].squaredDistanceToEdge(x, y) < mKeyHysteresisDistanceSquared;
         } else {
             return false;
         }
     }
 
-    private static int getSquareDistanceToKeyEdge(int x, int y, Key key) {
-        final int left = key.x;
-        final int right = key.x + key.width;
-        final int top = key.y;
-        final int bottom = key.y + key.height;
-        final int edgeX = x < left ? left : (x > right ? right : x);
-        final int edgeY = y < top ? top : (y > bottom ? bottom : y);
-        final int dx = x - edgeX;
-        final int dy = y - edgeY;
-        return dx * dx + dy * dy;
-    }
-
-    private void showKeyPreviewAndUpdateKey(int keyIndex) {
-        updateKey(keyIndex);
+    private void showKeyPreviewAndUpdateKeyGraphics(int keyIndex) {
+        updateKeyGraphics(keyIndex);
         // The modifier key, such as shift key, should not be shown as preview when multi-touch is
         // supported. On the other hand, if multi-touch is not supported, the modifier key should
         // be shown as preview.
@@ -425,33 +422,51 @@
         }
     }
 
+    private void startLongPressTimer(int keyIndex) {
+        Key key = getKey(keyIndex);
+        if (key.mCodes[0] == Keyboard.CODE_SHIFT) {
+            mHandler.startLongPressShiftTimer(mLongPressShiftKeyTimeout, keyIndex, this);
+        } else {
+            mHandler.startLongPressTimer(mLongPressKeyTimeout, keyIndex, this);
+        }
+    }
+
     private void detectAndSendKey(int index, int x, int y, long eventTime) {
-        final OnKeyboardActionListener listener = mListener;
+        final KeyboardActionListener listener = mListener;
         final Key key = getKey(index);
 
         if (key == null) {
             if (listener != null)
                 listener.onCancel();
         } else {
-            if (key.text != null) {
+            if (key.mOutputText != null) {
                 if (listener != null) {
-                    listener.onText(key.text);
+                    listener.onText(key.mOutputText);
                     listener.onRelease(NOT_A_KEY);
                 }
             } else {
-                int code = key.codes[0];
+                int code = key.mCodes[0];
                 //TextEntryState.keyPressedAt(key, x, y);
                 int[] codes = mKeyDetector.newCodeArray();
                 mKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes);
                 // Multi-tap
                 if (mInMultiTap) {
                     if (mTapCount != -1) {
-                        mListener.onKey(Keyboard.KEYCODE_DELETE, KEY_DELETE, x, y);
+                        mListener.onKey(Keyboard.CODE_DELETE, KEY_DELETE, x, y);
                     } else {
                         mTapCount = 0;
                     }
-                    code = key.codes[mTapCount];
+                    code = key.mCodes[mTapCount];
                 }
+
+                // If keyboard is in manual temporary upper case state and key has manual temporary
+                // shift code, alternate character code should be sent.
+                if (mKeyboard.isManualTemporaryUpperCase()
+                        && key.mManualTemporaryUpperCaseCode != 0) {
+                    code = key.mManualTemporaryUpperCaseCode;
+                    codes[0] = code;
+                }
+
                 /*
                  * Swap the first and second values in the codes array if the primary code is not
                  * the first value but the second value in the array. This happens when key
@@ -478,10 +493,10 @@
         if (mInMultiTap) {
             // Multi-tap
             mPreviewLabel.setLength(0);
-            mPreviewLabel.append((char) key.codes[mTapCount < 0 ? 0 : mTapCount]);
+            mPreviewLabel.append((char) key.mCodes[mTapCount < 0 ? 0 : mTapCount]);
             return mPreviewLabel;
         } else {
-            return key.label;
+            return key.mLabel;
         }
     }
 
@@ -499,10 +514,10 @@
 
         final boolean isMultiTap =
                 (eventTime < mLastTapTime + mMultiTapKeyTimeout && keyIndex == mLastSentIndex);
-        if (key.codes.length > 1) {
+        if (key.mCodes.length > 1) {
             mInMultiTap = true;
             if (isMultiTap) {
-                mTapCount = (mTapCount + 1) % key.codes.length;
+                mTapCount = (mTapCount + 1) % key.mCodes.length;
                 return;
             } else {
                 mTapCount = -1;
@@ -521,7 +536,7 @@
         if (key == null) {
             code = "----";
         } else {
-            int primaryCode = key.codes[0];
+            int primaryCode = key.mCodes[0];
             code = String.format((primaryCode < 0) ? "%4d" : "0x%02x", primaryCode);
         }
         Log.d(TAG, String.format("%s%s[%d] %3d,%3d %3d(%s) %s", title,
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/PointerTrackerQueue.java
new file mode 100644
index 0000000..e559b4c
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/PointerTrackerQueue.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 java.util.LinkedList;
+
+public class PointerTrackerQueue {
+    private LinkedList<PointerTracker> mQueue = new LinkedList<PointerTracker>();
+
+    public void add(PointerTracker tracker) {
+        mQueue.add(tracker);
+    }
+
+    public int lastIndexOf(PointerTracker tracker) {
+        LinkedList<PointerTracker> queue = mQueue;
+        for (int index = queue.size() - 1; index >= 0; index--) {
+            PointerTracker t = queue.get(index);
+            if (t == tracker)
+                return index;
+        }
+        return -1;
+    }
+
+    public void releaseAllPointersOlderThan(PointerTracker tracker, long eventTime) {
+        LinkedList<PointerTracker> queue = mQueue;
+        int oldestPos = 0;
+        for (PointerTracker t = queue.get(oldestPos); t != tracker; t = queue.get(oldestPos)) {
+            if (t.isModifier()) {
+                oldestPos++;
+            } else {
+                t.onUpEvent(t.getLastX(), t.getLastY(), eventTime);
+                t.setAlreadyProcessed();
+                queue.remove(oldestPos);
+            }
+        }
+    }
+
+    public void releaseAllPointersExcept(PointerTracker tracker, long eventTime) {
+        for (PointerTracker t : mQueue) {
+            if (t == tracker)
+                continue;
+            t.onUpEvent(t.getLastX(), t.getLastY(), eventTime);
+            t.setAlreadyProcessed();
+        }
+        mQueue.clear();
+        if (tracker != null)
+            mQueue.add(tracker);
+    }
+
+    public void remove(PointerTracker tracker) {
+        mQueue.remove(tracker);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder("[");
+        for (PointerTracker tracker : mQueue) {
+            if (sb.length() > 1)
+                sb.append(" ");
+            sb.append(String.format("%d", tracker.mPointerId));
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java b/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java
new file mode 100644
index 0000000..43596ae
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/ProximityKeyDetector.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 java.util.Arrays;
+
+public class ProximityKeyDetector extends KeyDetector {
+    private static final int MAX_NEARBY_KEYS = 12;
+
+    // working area
+    private int[] mDistances = new int[MAX_NEARBY_KEYS];
+
+    @Override
+    protected int getMaxNearbyKeys() {
+        return MAX_NEARBY_KEYS;
+    }
+
+    @Override
+    public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) {
+        final Key[] keys = getKeys();
+        final int touchX = getTouchX(x);
+        final int touchY = getTouchY(y);
+
+        int primaryIndex = NOT_A_KEY;
+        int closestKeyIndex = NOT_A_KEY;
+        int closestKeyDist = mProximityThresholdSquare + 1;
+        final int[] distances = mDistances;
+        Arrays.fill(distances, Integer.MAX_VALUE);
+        for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) {
+            final Key key = keys[index];
+            final boolean isInside = key.isInside(touchX, touchY);
+            if (isInside)
+                primaryIndex = index;
+            final int dist = key.squaredDistanceToEdge(touchX, touchY);
+            if (isInside || (mProximityCorrectOn && dist < mProximityThresholdSquare)) {
+                if (dist < closestKeyDist) {
+                    closestKeyDist = dist;
+                    closestKeyIndex = index;
+                }
+
+                if (allKeys == null) continue;
+                final int nCodes = key.mCodes.length;
+                // Find insertion point
+                for (int j = 0; j < distances.length; j++) {
+                    if (distances[j] > dist) {
+                        // Make space for nCodes codes
+                        System.arraycopy(distances, j, distances, j + nCodes,
+                                distances.length - (j + nCodes));
+                        System.arraycopy(allKeys, j, allKeys, j + nCodes,
+                                allKeys.length - (j + nCodes));
+                        System.arraycopy(key.mCodes, 0, allKeys, j, nCodes);
+                        Arrays.fill(distances, j, j + nCodes, dist);
+                        break;
+                    }
+                }
+            }
+        }
+
+        return primaryIndex == NOT_A_KEY ? closestKeyIndex : primaryIndex;
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/Row.java b/java/src/com/android/inputmethod/keyboard/Row.java
new file mode 100644
index 0000000..37fa4e3
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/Row.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 com.android.inputmethod.latin.R;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.Xml;
+
+/**
+ * Container for keys in the keyboard. All keys in a row are at the same Y-coordinate.
+ * Some of the key size defaults can be overridden per row from what the {@link Keyboard}
+ * defines.
+ */
+public class Row {
+    /** Default width of a key in this row. */
+    public final int mDefaultWidth;
+    /** Default height of a key in this row. */
+    public final int mDefaultHeight;
+    /** Default horizontal gap between keys in this row. */
+    public final int mDefaultHorizontalGap;
+    /** Vertical gap following this row. */
+    public final int mVerticalGap;
+    /**
+     * Edge flags for this row of keys. Possible values that can be assigned are
+     * {@link Keyboard#EDGE_TOP EDGE_TOP} and {@link Keyboard#EDGE_BOTTOM EDGE_BOTTOM}
+     */
+    public final int mRowEdgeFlags;
+
+    private final Keyboard mKeyboard;
+
+    public Row(Keyboard keyboard) {
+        this.mKeyboard = keyboard;
+        mDefaultHeight = keyboard.getKeyHeight();
+        mDefaultWidth = keyboard.getKeyWidth();
+        mDefaultHorizontalGap = keyboard.getHorizontalGap();
+        mVerticalGap = keyboard.getVerticalGap();
+        mRowEdgeFlags = Keyboard.EDGE_TOP | Keyboard.EDGE_BOTTOM;
+    }
+
+    public Row(Resources res, Keyboard keyboard, XmlResourceParser parser) {
+        this.mKeyboard = keyboard;
+        final int keyboardWidth = keyboard.getKeyboardWidth();
+        final int keyboardHeight = keyboard.getKeyboardHeight();
+        TypedArray a = res.obtainAttributes(Xml.asAttributeSet(parser),
+                R.styleable.Keyboard);
+        mDefaultWidth = KeyboardParser.getDimensionOrFraction(a,
+                R.styleable.Keyboard_keyWidth, keyboardWidth, keyboard.getKeyWidth());
+        mDefaultHeight = KeyboardParser.getDimensionOrFraction(a,
+                R.styleable.Keyboard_keyHeight, keyboardHeight, keyboard.getKeyHeight());
+        mDefaultHorizontalGap = KeyboardParser.getDimensionOrFraction(a,
+                R.styleable.Keyboard_horizontalGap, keyboardWidth, keyboard.getHorizontalGap());
+        mVerticalGap = KeyboardParser.getDimensionOrFraction(a,
+                R.styleable.Keyboard_verticalGap, keyboardHeight, keyboard.getVerticalGap());
+        a.recycle();
+        a = res.obtainAttributes(Xml.asAttributeSet(parser),
+                R.styleable.Keyboard_Row);
+        mRowEdgeFlags = a.getInt(R.styleable.Keyboard_Row_rowEdgeFlags, 0);
+        a.recycle();
+    }
+
+    public Keyboard getKeyboard() {
+        return mKeyboard;
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/ShiftKeyState.java b/java/src/com/android/inputmethod/keyboard/ShiftKeyState.java
new file mode 100644
index 0000000..9229208
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/ShiftKeyState.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.util.Log;
+
+public class ShiftKeyState extends ModifierKeyState {
+    private static final int PRESSING_ON_SHIFTED = 3; // both temporary shifted & shift locked
+    private static final int IGNORING = 4;
+
+    public ShiftKeyState(String name) {
+        super(name);
+    }
+
+    @Override
+    public void onOtherKeyPressed() {
+        int oldState = mState;
+        if (oldState == PRESSING) {
+            mState = MOMENTARY;
+        } else if (oldState == PRESSING_ON_SHIFTED) {
+            mState = IGNORING;
+        }
+        if (DEBUG)
+            Log.d(TAG, mName + ".onOtherKeyPressed: " + toString(oldState) + " > " + this);
+    }
+
+    public void onPressOnShifted() {
+        int oldState = mState;
+        mState = PRESSING_ON_SHIFTED;
+        if (DEBUG)
+            Log.d(TAG, mName + ".onPressOnShifted: " + toString(oldState) + " > " + this);
+    }
+
+    public boolean isPressingOnShifted() {
+        return mState == PRESSING_ON_SHIFTED;
+    }
+
+    public boolean isIgnoring() {
+        return mState == IGNORING;
+    }
+
+    @Override
+    public String toString() {
+        return toString(mState);
+    }
+
+    @Override
+    protected String toString(int state) {
+        switch (state) {
+        case PRESSING_ON_SHIFTED: return "PRESSING_ON_SHIFTED";
+        case IGNORING: return "IGNORING";
+        default: return super.toString(state);
+        }
+    }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/SlidingLocaleDrawable.java b/java/src/com/android/inputmethod/keyboard/SlidingLocaleDrawable.java
new file mode 100644
index 0000000..689791c
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/SlidingLocaleDrawable.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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 com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SubtypeSwitcher;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Paint.Align;
+import android.graphics.drawable.Drawable;
+import android.text.TextPaint;
+import android.view.ViewConfiguration;
+
+/**
+ * Animation to be displayed on the spacebar preview popup when switching languages by swiping the
+ * spacebar. It draws the current, previous and next languages and moves them by the delta of touch
+ * movement on the spacebar.
+ */
+public class SlidingLocaleDrawable extends Drawable {
+
+    private final Context mContext;
+    private final Resources mRes;
+    private final int mWidth;
+    private final int mHeight;
+    private final Drawable mBackground;
+    private final TextPaint mTextPaint;
+    private final int mMiddleX;
+    private final Drawable mLeftDrawable;
+    private final Drawable mRightDrawable;
+    private final int mThreshold;
+    private int mDiff;
+    private boolean mHitThreshold;
+    private String mCurrentLanguage;
+    private String mNextLanguage;
+    private String mPrevLanguage;
+
+    public SlidingLocaleDrawable(Context context, Drawable background, int width, int height) {
+        mContext = context;
+        mRes = context.getResources();
+        mBackground = background;
+        LatinKeyboard.setDefaultBounds(mBackground);
+        mWidth = width;
+        mHeight = height;
+        final TextPaint textPaint = new TextPaint();
+        textPaint.setTextSize(getTextSizeFromTheme(android.R.style.TextAppearance_Medium, 18));
+        textPaint.setColor(R.color.latinkeyboard_transparent);
+        textPaint.setTextAlign(Align.CENTER);
+        textPaint.setAlpha(LatinKeyboard.OPACITY_FULLY_OPAQUE);
+        textPaint.setAntiAlias(true);
+        mTextPaint = textPaint;
+        mMiddleX = (mWidth - mBackground.getIntrinsicWidth()) / 2;
+        final Resources res = mRes;
+        mLeftDrawable = res.getDrawable(
+                R.drawable.sym_keyboard_feedback_language_arrows_left);
+        mRightDrawable = res.getDrawable(
+                R.drawable.sym_keyboard_feedback_language_arrows_right);
+        mThreshold = ViewConfiguration.get(mContext).getScaledTouchSlop();
+    }
+
+    private int getTextSizeFromTheme(int style, int defValue) {
+        TypedArray array = mContext.getTheme().obtainStyledAttributes(
+                style, new int[] { android.R.attr.textSize });
+        int textSize = array.getDimensionPixelSize(array.getResourceId(0, 0), defValue);
+        return textSize;
+    }
+
+    void setDiff(int diff) {
+        if (diff == Integer.MAX_VALUE) {
+            mHitThreshold = false;
+            mCurrentLanguage = null;
+            return;
+        }
+        mDiff = diff;
+        if (mDiff > mWidth) mDiff = mWidth;
+        if (mDiff < -mWidth) mDiff = -mWidth;
+        if (Math.abs(mDiff) > mThreshold) mHitThreshold = true;
+        invalidateSelf();
+    }
+
+
+    @Override
+    public void draw(Canvas canvas) {
+        canvas.save();
+        if (mHitThreshold) {
+            Paint paint = mTextPaint;
+            final int width = mWidth;
+            final int height = mHeight;
+            final int diff = mDiff;
+            final Drawable lArrow = mLeftDrawable;
+            final Drawable rArrow = mRightDrawable;
+            canvas.clipRect(0, 0, width, height);
+            if (mCurrentLanguage == null) {
+                SubtypeSwitcher subtypeSwitcher = SubtypeSwitcher.getInstance();
+                mCurrentLanguage = subtypeSwitcher.getInputLanguageName();
+                mNextLanguage = subtypeSwitcher.getNextInputLanguageName();
+                mPrevLanguage = subtypeSwitcher.getPreviousInputLanguageName();
+            }
+            // Draw language text with shadow
+            final float baseline = mHeight * LatinKeyboard.SPACEBAR_LANGUAGE_BASELINE
+                    - paint.descent();
+            paint.setColor(mRes.getColor(R.color.latinkeyboard_feedback_language_text));
+            canvas.drawText(mCurrentLanguage, width / 2 + diff, baseline, paint);
+            canvas.drawText(mNextLanguage, diff - width / 2, baseline, paint);
+            canvas.drawText(mPrevLanguage, diff + width + width / 2, baseline, paint);
+
+            LatinKeyboard.setDefaultBounds(lArrow);
+            rArrow.setBounds(width - rArrow.getIntrinsicWidth(), 0, width,
+                    rArrow.getIntrinsicHeight());
+            lArrow.draw(canvas);
+            rArrow.draw(canvas);
+        }
+        if (mBackground != null) {
+            canvas.translate(mMiddleX, 0);
+            mBackground.draw(canvas);
+        }
+        canvas.restore();
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        // Ignore
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter cf) {
+        // Ignore
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mWidth;
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mHeight;
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/SwipeTracker.java b/java/src/com/android/inputmethod/keyboard/SwipeTracker.java
similarity index 97%
rename from java/src/com/android/inputmethod/latin/SwipeTracker.java
rename to java/src/com/android/inputmethod/keyboard/SwipeTracker.java
index 970e919..730cdc3 100644
--- a/java/src/com/android/inputmethod/latin/SwipeTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/SwipeTracker.java
@@ -14,11 +14,11 @@
  * the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.keyboard;
 
 import android.view.MotionEvent;
 
-class SwipeTracker {
+public class SwipeTracker {
     private static final int NUM_PAST = 4;
     private static final int LONGEST_PAST_TIME = 200;
 
@@ -91,7 +91,7 @@
         return mYVelocity;
     }
 
-    static class EventRingBuffer {
+    public static class EventRingBuffer {
         private final int bufSize;
         private final float xBuf[];
         private final float yBuf[];
@@ -154,4 +154,4 @@
             end = advance(end);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/java/src/com/android/inputmethod/latin/AutoDictionary.java b/java/src/com/android/inputmethod/latin/AutoDictionary.java
index 4fbb5b0..a3bf256 100644
--- a/java/src/com/android/inputmethod/latin/AutoDictionary.java
+++ b/java/src/com/android/inputmethod/latin/AutoDictionary.java
@@ -16,10 +16,6 @@
 
 package com.android.inputmethod.latin;
 
-import java.util.HashMap;
-import java.util.Set;
-import java.util.Map.Entry;
-
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
@@ -30,6 +26,10 @@
 import android.provider.BaseColumns;
 import android.util.Log;
 
+import java.util.HashMap;
+import java.util.Map.Entry;
+import java.util.Set;
+
 /**
  * Stores new words temporarily until they are promoted to the user dictionary
  * for longevity. Words in the auto dictionary are used to determine if it's ok
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index d0e143d..c7f629f 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -16,16 +16,16 @@
 
 package com.android.inputmethod.latin;
 
-import java.io.InputStream;
+import android.content.Context;
+import android.util.Log;
+
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.channels.Channels;
 import java.util.Arrays;
 
-import android.content.Context;
-import android.util.Log;
-
 /**
  * Implements a static, compacted, binary dictionary of standard words.
  */
@@ -45,16 +45,15 @@
     private static final int MAX_BIGRAMS = 60;
 
     private static final int TYPED_LETTER_MULTIPLIER = 2;
-    private static final boolean ENABLE_MISSED_CHARACTERS = true;
 
     private int mDicTypeId;
     private int mNativeDict;
     private int mDictLength;
-    private int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_ALTERNATIVES];
-    private char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS];
-    private char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS];
-    private int[] mFrequencies = new int[MAX_WORDS];
-    private int[] mFrequencies_bigrams = new int[MAX_BIGRAMS];
+    private final int[] mInputCodes = new int[MAX_WORD_LENGTH * MAX_ALTERNATIVES];
+    private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS];
+    private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS];
+    private final int[] mFrequencies = new int[MAX_WORDS];
+    private final int[] mFrequencies_bigrams = new int[MAX_BIGRAMS];
     // Keep a reference to the native dict direct buffer in Java to avoid
     // unexpected deallocation of the direct buffer.
     private ByteBuffer mNativeDictDirectBuffer;
@@ -95,18 +94,19 @@
             }
             mDictLength = byteBuffer.capacity();
             mNativeDict = openNative(mNativeDictDirectBuffer,
-                    TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER);
+                    TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER,
+                    MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES);
         }
         mDicTypeId = dicTypeId;
     }
 
     private native int openNative(ByteBuffer bb, int typedLetterMultiplier,
-            int fullWordMultiplier);
+            int fullWordMultiplier, int maxWordLength, int maxWords, int maxAlternatives);
     private native void closeNative(int dict);
     private native boolean isValidWordNative(int nativeData, char[] word, int wordLength);
     private native int getSuggestionsNative(int dict, int[] inputCodes, int codesSize, 
-            char[] outputChars, int[] frequencies, int maxWordLength, int maxWords,
-            int maxAlternatives, int skipPos, int[] nextLettersFrequencies, int nextLettersSize);
+            char[] outputChars, int[] frequencies,
+            int[] nextLettersFrequencies, int nextLettersSize);
     private native int getBigramsNative(int dict, char[] prevWord, int prevWordLength,
             int[] inputCodes, int inputCodesLength, char[] outputChars, int[] frequencies,
             int maxWordLength, int maxBigrams, int maxAlternatives);
@@ -132,7 +132,8 @@
                 Log.e(TAG, "Read " + got + " bytes, expected " + total);
             } else {
                 mNativeDict = openNative(mNativeDictDirectBuffer,
-                        TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER);
+                        TYPED_LETTER_MULTIPLIER, FULL_WORD_FREQ_MULTIPLIER,
+                        MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES);
                 mDictLength = total;
             }
         } catch (IOException e) {
@@ -189,7 +190,7 @@
         final int codesSize = codes.size();
         // Won't deal with really long words.
         if (codesSize > MAX_WORD_LENGTH - 1) return;
-        
+
         Arrays.fill(mInputCodes, -1);
         for (int i = 0; i < codesSize; i++) {
             int[] alternatives = codes.getCodesAt(i);
@@ -199,27 +200,10 @@
         Arrays.fill(mOutputChars, (char) 0);
         Arrays.fill(mFrequencies, 0);
 
-        int count = getSuggestionsNative(mNativeDict, mInputCodes, codesSize,
-                mOutputChars, mFrequencies,
-                MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES, -1,
-                nextLettersFrequencies,
+        int count = getSuggestionsNative(mNativeDict, mInputCodes, codesSize, mOutputChars,
+                mFrequencies, nextLettersFrequencies,
                 nextLettersFrequencies != null ? nextLettersFrequencies.length : 0);
 
-        // If there aren't sufficient suggestions, search for words by allowing wild cards at
-        // the different character positions. This feature is not ready for prime-time as we need
-        // to figure out the best ranking for such words compared to proximity corrections and
-        // completions.
-        if (ENABLE_MISSED_CHARACTERS && count < 5) {
-            for (int skip = 0; skip < codesSize; skip++) {
-                int tempCount = getSuggestionsNative(mNativeDict, mInputCodes, codesSize,
-                        mOutputChars, mFrequencies,
-                        MAX_WORD_LENGTH, MAX_WORDS, MAX_ALTERNATIVES, skip,
-                        null, 0);
-                count = Math.max(count, tempCount);
-                if (tempCount > 0) break;
-            }
-        }
-
         for (int j = 0; j < count; j++) {
             if (mFrequencies[j] < 1) break;
             int start = j * MAX_WORD_LENGTH;
diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java
old mode 100755
new mode 100644
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index e954c08..2a7767d 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -16,11 +16,11 @@
 
 package com.android.inputmethod.latin;
 
-import java.util.LinkedList;
-
 import android.content.Context;
 import android.os.AsyncTask;
 
+import java.util.LinkedList;
+
 /**
  * Base class for an in-memory dictionary that can grow dynamically and can
  * be searched for suggestions and valid words.
diff --git a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java
index e811a2c..ad3f1db 100644
--- a/java/src/com/android/inputmethod/latin/InputLanguageSelection.java
+++ b/java/src/com/android/inputmethod/latin/InputLanguageSelection.java
@@ -16,11 +16,6 @@
 
 package com.android.inputmethod.latin;
 
-import java.text.Collator;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Locale;
-
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 import android.content.res.Configuration;
@@ -32,12 +27,18 @@
 import android.preference.PreferenceManager;
 import android.text.TextUtils;
 
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Locale;
+
 public class InputLanguageSelection extends PreferenceActivity {
 
+    private SharedPreferences mPrefs;
     private String mSelectedLanguages;
     private ArrayList<Loc> mAvailableLanguages = new ArrayList<Loc>();
     private static final String[] BLACKLIST_LANGUAGES = {
-        "ko", "ja", "zh", "el"
+        "ko", "ja", "zh", "el", "zz"
     };
 
     private static class Loc implements Comparable<Object> {
@@ -56,6 +57,7 @@
             return this.label;
         }
 
+        @Override
         public int compareTo(Object o) {
             return sCollator.compare(this.label, ((Loc) o).label);
         }
@@ -66,15 +68,15 @@
         super.onCreate(icicle);
         addPreferencesFromResource(R.xml.language_prefs);
         // Get the settings preferences
-        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
-        mSelectedLanguages = sp.getString(LatinIME.PREF_SELECTED_LANGUAGES, "");
+        mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+        mSelectedLanguages = mPrefs.getString(LatinIME.PREF_SELECTED_LANGUAGES, "");
         String[] languageList = mSelectedLanguages.split(",");
         mAvailableLanguages = getUniqueLocales();
         PreferenceGroup parent = getPreferenceScreen();
         for (int i = 0; i < mAvailableLanguages.size(); i++) {
             CheckBoxPreference pref = new CheckBoxPreference(this);
             Locale locale = mAvailableLanguages.get(i).locale;
-            pref.setTitle(LanguageSwitcher.toTitleCase(locale.getDisplayName(locale)));
+            pref.setTitle(SubtypeSwitcher.getFullDisplayName(locale, true));
             boolean checked = isLocaleIn(locale, languageList);
             pref.setChecked(checked);
             if (hasDictionary(locale)) {
@@ -140,8 +142,7 @@
             }
         }
         if (checkedLanguages.length() < 1) checkedLanguages = null; // Save null
-        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
-        Editor editor = sp.edit();
+        Editor editor = mPrefs.edit();
         editor.putString(LatinIME.PREF_SELECTED_LANGUAGES, checkedLanguages);
         SharedPreferencesCompat.apply(editor);
     }
@@ -167,7 +168,7 @@
 
                 if (finalSize == 0) {
                     preprocess[finalSize++] =
-                            new Loc(LanguageSwitcher.toTitleCase(l.getDisplayName(l)), l);
+                            new Loc(SubtypeSwitcher.getFullDisplayName(l, true), l);
                 } else {
                     // check previous entry:
                     //  same lang and a country -> upgrade to full name and
@@ -175,15 +176,15 @@
                     //  diff lang -> insert ours with lang-only name
                     if (preprocess[finalSize-1].locale.getLanguage().equals(
                             language)) {
-                        preprocess[finalSize-1].label = LanguageSwitcher.toTitleCase(
-                                preprocess[finalSize-1].locale.getDisplayName());
+                        preprocess[finalSize-1].label = SubtypeSwitcher.getFullDisplayName(
+                                preprocess[finalSize-1].locale, false);
                         preprocess[finalSize++] =
-                                new Loc(LanguageSwitcher.toTitleCase(l.getDisplayName()), l);
+                                new Loc(SubtypeSwitcher.getFullDisplayName(l, false), l);
                     } else {
                         String displayName;
                         if (s.equals("zz_ZZ")) {
                         } else {
-                            displayName = LanguageSwitcher.toTitleCase(l.getDisplayName(l));
+                            displayName = SubtypeSwitcher.getFullDisplayName(l, true);
                             preprocess[finalSize++] = new Loc(displayName, l);
                         }
                     }
diff --git a/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java b/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java
deleted file mode 100644
index a7b695e..0000000
--- a/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java
+++ /dev/null
@@ -1,538 +0,0 @@
-/*
- * Copyright (C) 2008 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.content.SharedPreferences;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.preference.PreferenceManager;
-import android.view.InflateException;
-
-import java.lang.ref.SoftReference;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Locale;
-
-public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener {
-
-    public static final int MODE_NONE = 0;
-    public static final int MODE_TEXT = 1;
-    public static final int MODE_SYMBOLS = 2;
-    public static final int MODE_PHONE = 3;
-    public static final int MODE_URL = 4;
-    public static final int MODE_EMAIL = 5;
-    public static final int MODE_IM = 6;
-    public static final int MODE_WEB = 7;
-
-    // Main keyboard layouts without the settings key
-    public static final int KEYBOARDMODE_NORMAL = R.id.mode_normal;
-    public static final int KEYBOARDMODE_URL = R.id.mode_url;
-    public static final int KEYBOARDMODE_EMAIL = R.id.mode_email;
-    public static final int KEYBOARDMODE_IM = R.id.mode_im;
-    public static final int KEYBOARDMODE_WEB = R.id.mode_webentry;
-    // Main keyboard layouts with the settings key
-    public static final int KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY =
-            R.id.mode_normal_with_settings_key;
-    public static final int KEYBOARDMODE_URL_WITH_SETTINGS_KEY =
-            R.id.mode_url_with_settings_key;
-    public static final int KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY =
-            R.id.mode_email_with_settings_key;
-    public static final int KEYBOARDMODE_IM_WITH_SETTINGS_KEY =
-            R.id.mode_im_with_settings_key;
-    public static final int KEYBOARDMODE_WEB_WITH_SETTINGS_KEY =
-            R.id.mode_webentry_with_settings_key;
-
-    // Symbols keyboard layout without the settings key
-    public static final int KEYBOARDMODE_SYMBOLS = R.id.mode_symbols;
-    // Symbols keyboard layout with the settings key
-    public static final int KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY =
-            R.id.mode_symbols_with_settings_key;
-
-    public static final String DEFAULT_LAYOUT_ID = "4";
-    public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902";
-    private static final int[] THEMES = new int [] {
-        R.layout.input_basic, R.layout.input_basic_highcontrast, R.layout.input_stone_normal,
-        R.layout.input_stone_bold, R.layout.input_gingerbread};
-
-    // Ids for each characters' color in the keyboard
-    private static final int CHAR_THEME_COLOR_WHITE = 0;
-    private static final int CHAR_THEME_COLOR_BLACK = 1;
-
-    // Tables which contains resource ids for each character theme color
-    private static final int[] KBD_PHONE = new int[] {R.xml.kbd_phone, R.xml.kbd_phone_black};
-    private static final int[] KBD_PHONE_SYMBOLS = new int[] {
-        R.xml.kbd_phone_symbols, R.xml.kbd_phone_symbols_black};
-    private static final int[] KBD_SYMBOLS = new int[] {
-        R.xml.kbd_symbols, R.xml.kbd_symbols_black};
-    private static final int[] KBD_SYMBOLS_SHIFT = new int[] {
-        R.xml.kbd_symbols_shift, R.xml.kbd_symbols_shift_black};
-    private static final int[] KBD_QWERTY = new int[] {R.xml.kbd_qwerty, R.xml.kbd_qwerty_black};
-
-    private static final int SYMBOLS_MODE_STATE_NONE = 0;
-    private static final int SYMBOLS_MODE_STATE_BEGIN = 1;
-    private static final int SYMBOLS_MODE_STATE_SYMBOL = 2;
-
-    private LatinKeyboardView mInputView;
-    private static final int[] ALPHABET_MODES = {
-        KEYBOARDMODE_NORMAL,
-        KEYBOARDMODE_URL,
-        KEYBOARDMODE_EMAIL,
-        KEYBOARDMODE_IM,
-        KEYBOARDMODE_WEB,
-        KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY,
-        KEYBOARDMODE_URL_WITH_SETTINGS_KEY,
-        KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY,
-        KEYBOARDMODE_IM_WITH_SETTINGS_KEY,
-        KEYBOARDMODE_WEB_WITH_SETTINGS_KEY };
-
-    private final LatinIME mInputMethodService;
-
-    private KeyboardId mSymbolsId;
-    private KeyboardId mSymbolsShiftedId;
-
-    private KeyboardId mCurrentId;
-    private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboards;
-
-    private int mMode = MODE_NONE; /** One of the MODE_XXX values */
-    private int mImeOptions;
-    private boolean mIsSymbols;
-    /** mIsAutoCompletionActive indicates that auto completed word will be input instead of
-     * what user actually typed. */
-    private boolean mIsAutoCompletionActive;
-    private boolean mHasVoice;
-    private boolean mVoiceOnPrimary;
-    private boolean mPreferSymbols;
-    private int mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
-
-    // Indicates whether or not we have the settings key
-    private boolean mHasSettingsKey;
-    private static final int SETTINGS_KEY_MODE_AUTO = R.string.settings_key_mode_auto;
-    private static final int SETTINGS_KEY_MODE_ALWAYS_SHOW = R.string.settings_key_mode_always_show;
-    // NOTE: No need to have SETTINGS_KEY_MODE_ALWAYS_HIDE here because it's not being referred to
-    // in the source code now.
-    // Default is SETTINGS_KEY_MODE_AUTO.
-    private static final int DEFAULT_SETTINGS_KEY_MODE = SETTINGS_KEY_MODE_AUTO;
-
-    private int mLastDisplayWidth;
-    private LanguageSwitcher mLanguageSwitcher;
-    private Locale mInputLocale;
-
-    private int mLayoutId;
-
-    public KeyboardSwitcher(LatinIME ims) {
-        mInputMethodService = ims;
-
-        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ims);
-        mLayoutId = Integer.valueOf(prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID));
-        updateSettingsKeyState(prefs);
-        prefs.registerOnSharedPreferenceChangeListener(this);
-
-        mKeyboards = new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
-        mSymbolsId = makeSymbolsId(false);
-        mSymbolsShiftedId = makeSymbolsShiftedId(false);
-    }
-
-    /**
-     * Sets the input locale, when there are multiple locales for input.
-     * If no locale switching is required, then the locale should be set to null.
-     * @param locale the current input locale, or null for default locale with no locale 
-     * button.
-     */
-    public void setLanguageSwitcher(LanguageSwitcher languageSwitcher) {
-        mLanguageSwitcher = languageSwitcher;
-        mInputLocale = mLanguageSwitcher.getInputLocale();
-    }
-
-    private KeyboardId makeSymbolsId(boolean hasVoice) {
-        return new KeyboardId(KBD_SYMBOLS[getCharColorId()], mHasSettingsKey ?
-                KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS,
-                false, hasVoice);
-    }
-
-    private KeyboardId makeSymbolsShiftedId(boolean hasVoice) {
-        return new KeyboardId(KBD_SYMBOLS_SHIFT[getCharColorId()], mHasSettingsKey ?
-                KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS,
-                false, hasVoice);
-    }
-
-    public void makeKeyboards(boolean forceCreate) {
-        mSymbolsId = makeSymbolsId(mHasVoice && !mVoiceOnPrimary);
-        mSymbolsShiftedId = makeSymbolsShiftedId(mHasVoice && !mVoiceOnPrimary);
-
-        if (forceCreate) mKeyboards.clear();
-        // Configuration change is coming after the keyboard gets recreated. So don't rely on that.
-        // If keyboards have already been made, check if we have a screen width change and 
-        // create the keyboard layouts again at the correct orientation
-        int displayWidth = mInputMethodService.getMaxWidth();
-        if (displayWidth == mLastDisplayWidth) return;
-        mLastDisplayWidth = displayWidth;
-        if (!forceCreate) mKeyboards.clear();
-    }
-
-    /**
-     * Represents the parameters necessary to construct a new LatinKeyboard,
-     * which also serve as a unique identifier for each keyboard type.
-     */
-    private static class KeyboardId {
-        // TODO: should have locale and portrait/landscape orientation?
-        public final int mXml;
-        public final int mKeyboardMode; /** A KEYBOARDMODE_XXX value */
-        public final boolean mEnableShiftLock;
-        public final boolean mHasVoice;
-
-        private final int mHashCode;
-
-        public KeyboardId(int xml, int mode, boolean enableShiftLock, boolean hasVoice) {
-            this.mXml = xml;
-            this.mKeyboardMode = mode;
-            this.mEnableShiftLock = enableShiftLock;
-            this.mHasVoice = hasVoice;
-
-            this.mHashCode = Arrays.hashCode(new Object[] {
-               xml, mode, enableShiftLock, hasVoice
-            });
-        }
-
-        public KeyboardId(int xml, boolean hasVoice) {
-            this(xml, 0, false, hasVoice);
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            return other instanceof KeyboardId && equals((KeyboardId) other);
-        }
-
-        private boolean equals(KeyboardId other) {
-            return other.mXml == this.mXml
-                && other.mKeyboardMode == this.mKeyboardMode
-                && other.mEnableShiftLock == this.mEnableShiftLock
-                && other.mHasVoice == this.mHasVoice;
-        }
-
-        @Override
-        public int hashCode() {
-            return mHashCode;
-        }
-    }
-
-    public void setVoiceMode(boolean enableVoice, boolean voiceOnPrimary) {
-        if (enableVoice != mHasVoice || voiceOnPrimary != mVoiceOnPrimary) {
-            mKeyboards.clear();
-        }
-        mHasVoice = enableVoice;
-        mVoiceOnPrimary = voiceOnPrimary;
-        setKeyboardMode(mMode, mImeOptions, mHasVoice, mIsSymbols);
-    }
-
-    private boolean hasVoiceButton(boolean isSymbols) {
-        return mHasVoice && (isSymbols != mVoiceOnPrimary);
-    }
-
-    public void setKeyboardMode(int mode, int imeOptions, boolean enableVoice) {
-        mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
-        mPreferSymbols = mode == MODE_SYMBOLS;
-        if (mode == MODE_SYMBOLS) {
-            mode = MODE_TEXT;
-        }
-        try {
-            setKeyboardMode(mode, imeOptions, enableVoice, mPreferSymbols);
-        } catch (RuntimeException e) {
-            LatinImeLogger.logOnException(mode + "," + imeOptions + "," + mPreferSymbols, e);
-        }
-    }
-
-    private void setKeyboardMode(int mode, int imeOptions, boolean enableVoice, boolean isSymbols) {
-        if (mInputView == null) return;
-        mMode = mode;
-        mImeOptions = imeOptions;
-        if (enableVoice != mHasVoice) {
-            // TODO clean up this unnecessary recursive call.
-            setVoiceMode(enableVoice, mVoiceOnPrimary);
-        }
-        mIsSymbols = isSymbols;
-
-        mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
-        KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
-        LatinKeyboard keyboard = null;
-        keyboard = getKeyboard(id);
-
-        if (mode == MODE_PHONE) {
-            mInputView.setPhoneKeyboard(keyboard);
-        }
-
-        mCurrentId = id;
-        mInputView.setKeyboard(keyboard);
-        keyboard.setShifted(false);
-        keyboard.setShiftLocked(keyboard.isShiftLocked());
-        keyboard.setImeOptions(mInputMethodService.getResources(), mMode, imeOptions);
-        keyboard.setColorOfSymbolIcons(mIsAutoCompletionActive, isBlackSym());
-        // Update the settings key state because number of enabled IMEs could have been changed
-        updateSettingsKeyState(PreferenceManager.getDefaultSharedPreferences(mInputMethodService));
-    }
-
-    private LatinKeyboard getKeyboard(KeyboardId id) {
-        SoftReference<LatinKeyboard> ref = mKeyboards.get(id);
-        LatinKeyboard keyboard = (ref == null) ? null : ref.get();
-        if (keyboard == null) {
-            Resources orig = mInputMethodService.getResources();
-            Configuration conf = orig.getConfiguration();
-            Locale saveLocale = conf.locale;
-            conf.locale = mInputLocale;
-            orig.updateConfiguration(conf, null);
-            keyboard = new LatinKeyboard(mInputMethodService, id.mXml, id.mKeyboardMode);
-            keyboard.setVoiceMode(hasVoiceButton(id.mXml == R.xml.kbd_symbols
-                    || id.mXml == R.xml.kbd_symbols_black), mHasVoice);
-            keyboard.setLanguageSwitcher(mLanguageSwitcher, mIsAutoCompletionActive, isBlackSym());
-
-            if (id.mEnableShiftLock) {
-                keyboard.enableShiftLock();
-            }
-            mKeyboards.put(id, new SoftReference<LatinKeyboard>(keyboard));
-
-            conf.locale = saveLocale;
-            orig.updateConfiguration(conf, null);
-        }
-        return keyboard;
-    }
-
-    private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) {
-        boolean hasVoice = hasVoiceButton(isSymbols);
-        int charColorId = getCharColorId();
-        // TODO: generalize for any KeyboardId
-        int keyboardRowsResId = KBD_QWERTY[charColorId];
-        if (isSymbols) {
-            if (mode == MODE_PHONE) {
-                return new KeyboardId(KBD_PHONE_SYMBOLS[charColorId], hasVoice);
-            } else {
-                return new KeyboardId(KBD_SYMBOLS[charColorId], mHasSettingsKey ?
-                        KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS,
-                        false, hasVoice);
-            }
-        }
-        switch (mode) {
-            case MODE_NONE:
-                LatinImeLogger.logOnWarning(
-                        "getKeyboardId:" + mode + "," + imeOptions + "," + isSymbols);
-                /* fall through */
-            case MODE_TEXT:
-                return new KeyboardId(keyboardRowsResId, mHasSettingsKey ?
-                        KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY : KEYBOARDMODE_NORMAL,
-                        true, hasVoice);
-            case MODE_SYMBOLS:
-                return new KeyboardId(KBD_SYMBOLS[charColorId], mHasSettingsKey ?
-                        KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS,
-                        false, hasVoice);
-            case MODE_PHONE:
-                return new KeyboardId(KBD_PHONE[charColorId], hasVoice);
-            case MODE_URL:
-                return new KeyboardId(keyboardRowsResId, mHasSettingsKey ?
-                        KEYBOARDMODE_URL_WITH_SETTINGS_KEY : KEYBOARDMODE_URL, true, hasVoice);
-            case MODE_EMAIL:
-                return new KeyboardId(keyboardRowsResId, mHasSettingsKey ?
-                        KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY : KEYBOARDMODE_EMAIL, true, hasVoice);
-            case MODE_IM:
-                return new KeyboardId(keyboardRowsResId, mHasSettingsKey ?
-                        KEYBOARDMODE_IM_WITH_SETTINGS_KEY : KEYBOARDMODE_IM, true, hasVoice);
-            case MODE_WEB:
-                return new KeyboardId(keyboardRowsResId, mHasSettingsKey ?
-                        KEYBOARDMODE_WEB_WITH_SETTINGS_KEY : KEYBOARDMODE_WEB, true, hasVoice);
-        }
-        return null;
-    }
-
-    public int getKeyboardMode() {
-        return mMode;
-    }
-    
-    public boolean isAlphabetMode() {
-        if (mCurrentId == null) {
-            return false;
-        }
-        int currentMode = mCurrentId.mKeyboardMode;
-        for (Integer mode : ALPHABET_MODES) {
-            if (currentMode == mode) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public void setShifted(boolean shifted) {
-        if (mInputView != null) {
-            mInputView.setShifted(shifted);
-        }
-    }
-
-    public void setShiftLocked(boolean shiftLocked) {
-        if (mInputView != null) {
-            mInputView.setShiftLocked(shiftLocked);
-        }
-    }
-
-    public void toggleShift() {
-        if (isAlphabetMode())
-            return;
-        if (mCurrentId.equals(mSymbolsId) || !mCurrentId.equals(mSymbolsShiftedId)) {
-            LatinKeyboard symbolsShiftedKeyboard = getKeyboard(mSymbolsShiftedId);
-            mCurrentId = mSymbolsShiftedId;
-            mInputView.setKeyboard(symbolsShiftedKeyboard);
-            // Symbol shifted keyboard has an ALT key that has a caps lock style indicator. To
-            // enable the indicator, we need to call enableShiftLock() and setShiftLocked(true).
-            // Thus we can keep the ALT key's Key.on value true while LatinKey.onRelease() is
-            // called.
-            symbolsShiftedKeyboard.enableShiftLock();
-            symbolsShiftedKeyboard.setShiftLocked(true);
-            symbolsShiftedKeyboard.setImeOptions(mInputMethodService.getResources(),
-                    mMode, mImeOptions);
-        } else {
-            LatinKeyboard symbolsKeyboard = getKeyboard(mSymbolsId);
-            mCurrentId = mSymbolsId;
-            mInputView.setKeyboard(symbolsKeyboard);
-            // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the
-            // indicator, we need to call enableShiftLock() and setShiftLocked(false).
-            symbolsKeyboard.enableShiftLock();
-            symbolsKeyboard.setShifted(false);
-            symbolsKeyboard.setImeOptions(mInputMethodService.getResources(), mMode, mImeOptions);
-        }
-    }
-
-    public void toggleSymbols() {
-        setKeyboardMode(mMode, mImeOptions, mHasVoice, !mIsSymbols);
-        if (mIsSymbols && !mPreferSymbols) {
-            mSymbolsModeState = SYMBOLS_MODE_STATE_BEGIN;
-        } else {
-            mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
-        }
-    }
-
-    public boolean hasDistinctMultitouch() {
-        return mInputView != null && mInputView.hasDistinctMultitouch();
-    }
-
-    /**
-     * Updates state machine to figure out when to automatically switch back to alpha mode.
-     * Returns true if the keyboard needs to switch back 
-     */
-    public boolean onKey(int key) {
-        // Switch back to alpha mode if user types one or more non-space/enter characters
-        // followed by a space/enter
-        switch (mSymbolsModeState) {
-            case SYMBOLS_MODE_STATE_BEGIN:
-                if (key != LatinIME.KEYCODE_SPACE && key != LatinIME.KEYCODE_ENTER && key > 0) {
-                    mSymbolsModeState = SYMBOLS_MODE_STATE_SYMBOL;
-                }
-                break;
-            case SYMBOLS_MODE_STATE_SYMBOL:
-                if (key == LatinIME.KEYCODE_ENTER || key == LatinIME.KEYCODE_SPACE) return true;
-                break;
-        }
-        return false;
-    }
-
-    public LatinKeyboardView getInputView() {
-        return mInputView;
-    }
-
-    public void recreateInputView() {
-        changeLatinKeyboardView(mLayoutId, true);
-    }
-
-    private void changeLatinKeyboardView(int newLayout, boolean forceReset) {
-        if (mLayoutId != newLayout || mInputView == null || forceReset) {
-            if (mInputView != null) {
-                mInputView.closing();
-            }
-            if (THEMES.length <= newLayout) {
-                newLayout = Integer.valueOf(DEFAULT_LAYOUT_ID);
-            }
-
-            LatinIMEUtil.GCUtils.getInstance().reset();
-            boolean tryGC = true;
-            for (int i = 0; i < LatinIMEUtil.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
-                try {
-                    mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater(
-                            ).inflate(THEMES[newLayout], null);
-                    tryGC = false;
-                } catch (OutOfMemoryError e) {
-                    tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait(
-                            mLayoutId + "," + newLayout, e);
-                } catch (InflateException e) {
-                    tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait(
-                            mLayoutId + "," + newLayout, e);
-                }
-            }
-            mInputView.setOnKeyboardActionListener(mInputMethodService);
-            mLayoutId = newLayout;
-        }
-        mInputMethodService.mHandler.post(new Runnable() {
-            public void run() {
-                if (mInputView != null) {
-                    mInputMethodService.setInputView(mInputView);
-                }
-                mInputMethodService.updateInputViewShown();
-            }});
-    }
-
-    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
-        if (PREF_KEYBOARD_LAYOUT.equals(key)) {
-            changeLatinKeyboardView(
-                    Integer.valueOf(sharedPreferences.getString(key, DEFAULT_LAYOUT_ID)), false);
-        } else if (LatinIMESettings.PREF_SETTINGS_KEY.equals(key)) {
-            updateSettingsKeyState(sharedPreferences);
-            recreateInputView();
-        }
-    }
-
-    public boolean isBlackSym () {
-        if (mInputView != null && mInputView.getSymbolColorScheme() == 1) {
-            return true;
-        }
-        return false;
-    }
-
-    private int getCharColorId () {
-        if (isBlackSym()) {
-            return CHAR_THEME_COLOR_BLACK;
-        } else {
-            return CHAR_THEME_COLOR_WHITE;
-        }
-    }
-
-    public void onAutoCompletionStateChanged(boolean isAutoCompletion) {
-        if (isAutoCompletion != mIsAutoCompletionActive) {
-            LatinKeyboardView keyboardView = getInputView();
-            mIsAutoCompletionActive = isAutoCompletion;
-            keyboardView.invalidateKey(((LatinKeyboard) keyboardView.getKeyboard())
-                    .onAutoCompletionStateChanged(isAutoCompletion));
-        }
-    }
-
-    private void updateSettingsKeyState(SharedPreferences prefs) {
-        Resources resources = mInputMethodService.getResources();
-        final String settingsKeyMode = prefs.getString(LatinIMESettings.PREF_SETTINGS_KEY,
-                resources.getString(DEFAULT_SETTINGS_KEY_MODE));
-        // We show the settings key when 1) SETTINGS_KEY_MODE_ALWAYS_SHOW or
-        // 2) SETTINGS_KEY_MODE_AUTO and there are two or more enabled IMEs on the system
-        if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW))
-                || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO))
-                        && LatinIMEUtil.hasMultipleEnabledIMEs(mInputMethodService))) {
-            mHasSettingsKey = true;
-        } else {
-            mHasSettingsKey = false;
-        }
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/LanguageSwitcher.java b/java/src/com/android/inputmethod/latin/LanguageSwitcher.java
index 7b5c304..fc725bf 100644
--- a/java/src/com/android/inputmethod/latin/LanguageSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/LanguageSwitcher.java
@@ -16,21 +16,21 @@
 
 package com.android.inputmethod.latin;
 
-import java.util.Locale;
-
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
-import android.preference.PreferenceManager;
 import android.text.TextUtils;
 
+import java.util.ArrayList;
+import java.util.Locale;
+
 /**
  * Keeps track of list of selected input languages and the current
  * input language that the user has selected.
  */
 public class LanguageSwitcher {
 
-    private Locale[] mLocales;
-    private LatinIME mIme;
+    private final ArrayList<Locale> mLocales = new ArrayList<Locale>();
+    private final LatinIME mIme;
     private String[] mSelectedLanguageArray;
     private String   mSelectedLanguages;
     private int      mCurrentIndex = 0;
@@ -40,15 +40,10 @@
 
     public LanguageSwitcher(LatinIME ime) {
         mIme = ime;
-        mLocales = new Locale[0];
-    }
-
-    public Locale[]  getLocales() {
-        return mLocales;
     }
 
     public int getLocaleCount() {
-        return mLocales.length;
+        return mLocales.size();
     }
 
     /**
@@ -61,10 +56,10 @@
         String currentLanguage   = sp.getString(LatinIME.PREF_INPUT_LANGUAGE, null);
         if (selectedLanguages == null || selectedLanguages.length() < 1) {
             loadDefaults();
-            if (mLocales.length == 0) {
+            if (mLocales.size() == 0) {
                 return false;
             }
-            mLocales = new Locale[0];
+            mLocales.clear();
             return true;
         }
         if (selectedLanguages.equals(mSelectedLanguages)) {
@@ -77,7 +72,7 @@
         if (currentLanguage != null) {
             // Find the index
             mCurrentIndex = 0;
-            for (int i = 0; i < mLocales.length; i++) {
+            for (int i = 0; i < mLocales.size(); i++) {
                 if (mSelectedLanguageArray[i].equals(currentLanguage)) {
                     mCurrentIndex = i;
                     break;
@@ -96,11 +91,11 @@
     }
 
     private void constructLocales() {
-        mLocales = new Locale[mSelectedLanguageArray.length];
-        for (int i = 0; i < mLocales.length; i++) {
-            final String lang = mSelectedLanguageArray[i];
-            mLocales[i] = new Locale(lang.substring(0, 2),
+        mLocales.clear();
+        for (final String lang : mSelectedLanguageArray) {
+            final Locale locale = new Locale(lang.substring(0, 2),
                     lang.length() > 4 ? lang.substring(3, 5) : "");
+            mLocales.add(locale);
         }
     }
 
@@ -129,7 +124,17 @@
     public Locale getInputLocale() {
         if (getLocaleCount() == 0) return mDefaultInputLocale;
 
-        return mLocales[mCurrentIndex];
+        return mLocales.get(mCurrentIndex);
+    }
+
+    private int nextLocaleIndex() {
+        final int size = mLocales.size();
+        return (mCurrentIndex + 1) % size;
+    }
+
+    private int prevLocaleIndex() {
+        final int size = mLocales.size();
+        return (mCurrentIndex - 1 + size) % size;
     }
 
     /**
@@ -139,8 +144,7 @@
      */
     public Locale getNextInputLocale() {
         if (getLocaleCount() == 0) return mDefaultInputLocale;
-
-        return mLocales[(mCurrentIndex + 1) % mLocales.length];
+        return mLocales.get(nextLocaleIndex());
     }
 
     /**
@@ -166,8 +170,7 @@
      */
     public Locale getPrevInputLocale() {
         if (getLocaleCount() == 0) return mDefaultInputLocale;
-
-        return mLocales[(mCurrentIndex - 1 + mLocales.length) % mLocales.length];
+        return mLocales.get(prevLocaleIndex());
     }
 
     public void reset() {
@@ -175,27 +178,16 @@
     }
 
     public void next() {
-        mCurrentIndex++;
-        if (mCurrentIndex >= mLocales.length) mCurrentIndex = 0; // Wrap around
+        mCurrentIndex = nextLocaleIndex();
     }
 
     public void prev() {
-        mCurrentIndex--;
-        if (mCurrentIndex < 0) mCurrentIndex = mLocales.length - 1; // Wrap around
+        mCurrentIndex = prevLocaleIndex();
     }
 
-    public void persist() {
-        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mIme);
-        Editor editor = sp.edit();
+    public void persist(SharedPreferences prefs) {
+        Editor editor = prefs.edit();
         editor.putString(LatinIME.PREF_INPUT_LANGUAGE, getInputLanguage());
         SharedPreferencesCompat.apply(editor);
     }
-
-    static String toTitleCase(String s) {
-        if (s.length() == 0) {
-            return s;
-        }
-
-        return Character.toUpperCase(s.charAt(0)) + s.substring(1);
-    }
 }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index b6fee11..3089153 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -16,10 +16,14 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.keyboard.KeyboardActionListener;
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.KeyboardSwitcher;
+import com.android.inputmethod.keyboard.KeyboardView;
+import com.android.inputmethod.keyboard.LatinKeyboardView;
 import com.android.inputmethod.latin.LatinIMEUtil.RingCharBuffer;
-import com.android.inputmethod.voice.FieldContext;
-import com.android.inputmethod.voice.SettingsUtil;
-import com.android.inputmethod.voice.VoiceInput;
+import com.android.inputmethod.voice.VoiceIMEConnector;
 
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -34,16 +38,14 @@
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.inputmethodservice.InputMethodService;
-import android.inputmethodservice.Keyboard;
 import android.media.AudioManager;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
+import android.os.Vibrator;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceManager;
-import android.speech.SpeechRecognizer;
-import android.text.ClipboardManager;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -51,7 +53,6 @@
 import android.util.Printer;
 import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewParent;
@@ -63,128 +64,93 @@
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
 import android.widget.LinearLayout;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 
 /**
  * Input method implementation for Qwerty'ish keyboard.
  */
 public class LatinIME extends InputMethodService
-        implements LatinKeyboardBaseView.OnKeyboardActionListener,
-        VoiceInput.UiListener,
-        SharedPreferences.OnSharedPreferenceChangeListener {
+        implements KeyboardActionListener,
+        SharedPreferences.OnSharedPreferenceChangeListener,
+        Tutorial.TutorialListener {
     private static final String TAG = "LatinIME";
     private static final boolean PERF_DEBUG = false;
-    static final boolean DEBUG = false;
-    static final boolean TRACE = false;
-    static final boolean VOICE_INSTALLED = true;
-    static final boolean ENABLE_VOICE_BUTTON = true;
+    private static final boolean DEBUG = false;
+    private static final boolean TRACE = false;
 
-    private static final String PREF_VIBRATE_ON = "vibrate_on";
     private static final String PREF_SOUND_ON = "sound_on";
     private static final String PREF_POPUP_ON = "popup_on";
     private static final String PREF_AUTO_CAP = "auto_cap";
     private static final String PREF_QUICK_FIXES = "quick_fixes";
-    private static final String PREF_SHOW_SUGGESTIONS = "show_suggestions";
-    private static final String PREF_AUTO_COMPLETE = "auto_complete";
-    //private static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion";
-    private static final String PREF_VOICE_MODE = "voice_mode";
-
-    // Whether or not the user has used voice input before (and thus, whether to show the
-    // first-run warning dialog or not).
-    private static final String PREF_HAS_USED_VOICE_INPUT = "has_used_voice_input";
-
-    // Whether or not the user has used voice input from an unsupported locale UI before.
-    // For example, the user has a Chinese UI but activates voice input.
-    private static final String PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE =
-            "has_used_voice_input_unsupported_locale";
-
-    // A list of locales which are supported by default for voice input, unless we get a
-    // different list from Gservices.
-    public static final String DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES =
-            "en " +
-            "en_US " +
-            "en_GB " +
-            "en_AU " +
-            "en_CA " +
-            "en_IE " +
-            "en_IN " +
-            "en_NZ " +
-            "en_SG " +
-            "en_ZA ";
-
-    // The private IME option used to indicate that no microphone should be shown for a
-    // given text field. For instance this is specified by the search dialog when the
-    // dialog is already showing a voice search button.
-    private static final String IME_OPTION_NO_MICROPHONE = "nm";
+    private static final String PREF_SHOW_SUGGESTIONS_SETTING = "show_suggestions_setting";
+    private static final String PREF_AUTO_COMPLETION_THRESHOLD = "auto_completion_threshold";
+    private static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion";
 
     public static final String PREF_SELECTED_LANGUAGES = "selected_languages";
     public static final String PREF_INPUT_LANGUAGE = "input_language";
     private static final String PREF_RECORRECTION_ENABLED = "recorrection_enabled";
 
-    private static final int MSG_UPDATE_SUGGESTIONS = 0;
-    private static final int MSG_START_TUTORIAL = 1;
-    private static final int MSG_UPDATE_SHIFT_STATE = 2;
-    private static final int MSG_VOICE_RESULTS = 3;
-    private static final int MSG_UPDATE_OLD_SUGGESTIONS = 4;
+    private static final int DELAY_UPDATE_SUGGESTIONS = 180;
+    private static final int DELAY_UPDATE_OLD_SUGGESTIONS = 300;
+    private static final int DELAY_UPDATE_SHIFT_STATE = 300;
+    private static final int DELAY_START_TUTORIAL = 500;
 
     // How many continuous deletes at which to start deleting at a higher speed.
     private static final int DELETE_ACCELERATE_AT = 20;
     // Key events coming any faster than this are long-presses.
     private static final int QUICK_PRESS = 200;
 
-    static final int KEYCODE_ENTER = '\n';
-    static final int KEYCODE_SPACE = ' ';
-    static final int KEYCODE_PERIOD = '.';
-
     // Contextual menu positions
     private static final int POS_METHOD = 0;
     private static final int POS_SETTINGS = 1;
 
-    //private LatinKeyboardView mInputView;
+    private int mSuggestionVisibility;
+    private static final int SUGGESTION_VISIBILILTY_SHOW_VALUE
+            = R.string.prefs_suggestion_visibility_show_value;
+    private static final int SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
+            = R.string.prefs_suggestion_visibility_show_only_portrait_value;
+    private static final int SUGGESTION_VISIBILILTY_HIDE_VALUE
+            = R.string.prefs_suggestion_visibility_hide_value;
+
+    private static final int[] SUGGESTION_VISIBILITY_VALUE_ARRAY = new int[] {
+        SUGGESTION_VISIBILILTY_SHOW_VALUE,
+        SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE,
+        SUGGESTION_VISIBILILTY_HIDE_VALUE
+    };
+
     private LinearLayout mCandidateViewContainer;
     private CandidateView mCandidateView;
     private Suggest mSuggest;
     private CompletionInfo[] mCompletions;
 
     private AlertDialog mOptionsDialog;
-    private AlertDialog mVoiceWarningDialog;
 
-    /* package */ KeyboardSwitcher mKeyboardSwitcher;
+    private InputMethodManager mImm;
+    private KeyboardSwitcher mKeyboardSwitcher;
+    private SubtypeSwitcher mSubtypeSwitcher;
+    private VoiceIMEConnector mVoiceConnector;
 
     private UserDictionary mUserDictionary;
     private UserBigramDictionary mUserBigramDictionary;
     private ContactsDictionary mContactsDictionary;
     private AutoDictionary mAutoDictionary;
 
-    private Hints mHints;
-
     private Resources mResources;
+    private SharedPreferences mPrefs;
 
-    private String mInputLocale;
-    private String mSystemLocale;
-    private LanguageSwitcher mLanguageSwitcher;
-
-    private StringBuilder mComposing = new StringBuilder();
+    private final StringBuilder mComposing = new StringBuilder();
     private WordComposer mWord = new WordComposer();
-    private int mCommittedLength;
-    private boolean mPredicting;
-    private boolean mRecognizing;
-    private boolean mAfterVoiceInput;
-    private boolean mImmediatelyAfterVoiceInput;
-    private boolean mShowingVoiceSuggestions;
-    private boolean mVoiceInputHighlighted;
-    private boolean mEnableVoiceButton;
     private CharSequence mBestWord;
+    private boolean mPredicting;
     private boolean mPredictionOn;
     private boolean mCompletionOn;
     private boolean mHasDictionary;
@@ -192,72 +158,49 @@
     private boolean mJustAddedAutoSpace;
     private boolean mAutoCorrectEnabled;
     private boolean mReCorrectionEnabled;
-    // Bigram Suggestion is disabled in this version.
-    private final boolean mBigramSuggestionEnabled = false;
+    private boolean mBigramSuggestionEnabled;
     private boolean mAutoCorrectOn;
-    // TODO move this state variable outside LatinIME
-    private boolean mCapsLock;
-    private boolean mPasswordText;
     private boolean mVibrateOn;
     private boolean mSoundOn;
     private boolean mPopupOn;
     private boolean mAutoCap;
     private boolean mQuickFixes;
-    private boolean mHasUsedVoiceInput;
-    private boolean mHasUsedVoiceInputUnsupportedLocale;
-    private boolean mLocaleSupportedForVoiceInput;
-    private boolean mShowSuggestions;
-    private boolean mIsShowingHint;
-    private int     mCorrectionMode;
-    private boolean mEnableVoice = true;
-    private boolean mVoiceOnPrimary;
-    private int     mOrientation;
-    private List<CharSequence> mSuggestPuncList;
+
+    private int mCorrectionMode;
+    private int mCommittedLength;
+    private int mOrientation;
     // Keep track of the last selection range to decide if we need to show word alternatives
-    private int     mLastSelectionStart;
-    private int     mLastSelectionEnd;
+    private int mLastSelectionStart;
+    private int mLastSelectionEnd;
+    private List<CharSequence> mSuggestPuncList;
 
     // Input type is such that we should not auto-correct
     private boolean mInputTypeNoAutoCorrect;
 
     // Indicates whether the suggestion strip is to be on in landscape
     private boolean mJustAccepted;
-    private CharSequence mJustRevertedSeparator;
+    private boolean mJustReverted;
     private int mDeleteCount;
     private long mLastKeyTime;
 
-    // Modifier keys state
-    private ModifierKeyState mShiftKeyState = new ModifierKeyState();
-    private ModifierKeyState mSymbolKeyState = new ModifierKeyState();
-
     private Tutorial mTutorial;
 
     private AudioManager mAudioManager;
     // Align sound effect volume on music volume
-    private final float FX_VOLUME = -1.0f;
+    private static final float FX_VOLUME = -1.0f;
     private boolean mSilentMode;
 
     /* package */ String mWordSeparators;
     private String mSentenceSeparators;
     private String mSuggestPuncs;
-    private VoiceInput mVoiceInput;
-    private VoiceResults mVoiceResults = new VoiceResults();
+    // TODO: Move this flag to VoiceIMEConnector
     private boolean mConfigurationChanging;
 
     // Keeps track of most recently inserted text (multi-character key) for reverting
     private CharSequence mEnteredText;
     private boolean mRefreshKeyboardRequired;
 
-    // For each word, a list of potential replacements, usually from voice.
-    private Map<String, List<CharSequence>> mWordToSuggestions =
-            new HashMap<String, List<CharSequence>>();
-
-    private ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>();
-
-    private class VoiceResults {
-        List<String> candidates;
-        Map<String, List<CharSequence>> alternatives;
-    }
+    private final ArrayList<WordAlternatives> mWordHistory = new ArrayList<WordAlternatives>();
 
     public abstract static class WordAlternatives {
         protected CharSequence mChosenWord;
@@ -307,56 +250,101 @@
         }
     }
 
-    /* package */ Handler mHandler = new Handler() {
+    public final UIHandler mHandler = new UIHandler();
+
+    public class UIHandler extends Handler {
+        private static final int MSG_UPDATE_SUGGESTIONS = 0;
+        private static final int MSG_UPDATE_OLD_SUGGESTIONS = 1;
+        private static final int MSG_UPDATE_SHIFT_STATE = 2;
+        private static final int MSG_VOICE_RESULTS = 3;
+        private static final int MSG_START_TUTORIAL = 4;
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
-                case MSG_UPDATE_SUGGESTIONS:
-                    updateSuggestions();
-                    break;
-                case MSG_UPDATE_OLD_SUGGESTIONS:
-                    setOldSuggestions();
-                    break;
-                case MSG_START_TUTORIAL:
-                    if (mTutorial == null) {
-                        if (mKeyboardSwitcher.getInputView().isShown()) {
-                            mTutorial = new Tutorial(
-                                    LatinIME.this, mKeyboardSwitcher.getInputView());
-                            mTutorial.start();
-                        } else {
-                            // Try again soon if the view is not yet showing
-                            sendMessageDelayed(obtainMessage(MSG_START_TUTORIAL), 100);
-                        }
+            case MSG_UPDATE_SUGGESTIONS:
+                updateSuggestions();
+                break;
+            case MSG_UPDATE_OLD_SUGGESTIONS:
+                setOldSuggestions();
+                break;
+            case MSG_UPDATE_SHIFT_STATE:
+                mKeyboardSwitcher.updateShiftState();
+                break;
+            case MSG_VOICE_RESULTS:
+                mVoiceConnector.handleVoiceResults(mKeyboardSwitcher, preferCapitalization()
+                        || (mKeyboardSwitcher.isAlphabetMode()
+                                && mKeyboardSwitcher.isShiftedOrShiftLocked()));
+                break;
+            case MSG_START_TUTORIAL:
+                if (mTutorial == null) {
+                    if (mKeyboardSwitcher.isInputViewShown()) {
+                        mTutorial = new Tutorial(LatinIME.this, mKeyboardSwitcher);
+                        mTutorial.start();
+                    } else {
+                        // Try again soon if the view is not yet showing
+                        sendMessageDelayed(obtainMessage(MSG_START_TUTORIAL), 100);
                     }
-                    break;
-                case MSG_UPDATE_SHIFT_STATE:
-                    updateShiftKeyState(getCurrentInputEditorInfo());
-                    break;
-                case MSG_VOICE_RESULTS:
-                    handleVoiceResults();
-                    break;
+                }
+                break;
             }
         }
-    };
+
+        public void postUpdateSuggestions() {
+            removeMessages(MSG_UPDATE_SUGGESTIONS);
+            sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTIONS), DELAY_UPDATE_SUGGESTIONS);
+        }
+
+        public void cancelUpdateSuggestions() {
+            removeMessages(MSG_UPDATE_SUGGESTIONS);
+        }
+
+        public boolean hasPendingUpdateSuggestions() {
+            return hasMessages(MSG_UPDATE_SUGGESTIONS);
+        }
+
+        public void postUpdateOldSuggestions() {
+            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
+            sendMessageDelayed(obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS),
+                    DELAY_UPDATE_OLD_SUGGESTIONS);
+        }
+
+        public void cancelUpdateOldSuggestions() {
+            removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
+        }
+
+        public void postUpdateShiftKeyState() {
+            removeMessages(MSG_UPDATE_SHIFT_STATE);
+            sendMessageDelayed(obtainMessage(MSG_UPDATE_SHIFT_STATE), DELAY_UPDATE_SHIFT_STATE);
+        }
+
+        public void cancelUpdateShiftState() {
+            removeMessages(MSG_UPDATE_SHIFT_STATE);
+        }
+
+        public void updateVoiceResults() {
+            sendMessage(obtainMessage(MSG_VOICE_RESULTS));
+        }
+
+        public void startTutorial() {
+            sendMessageDelayed(obtainMessage(MSG_START_TUTORIAL), DELAY_START_TUTORIAL);
+        }
+    }
 
     @Override
     public void onCreate() {
-        LatinImeLogger.init(this);
+        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+        mPrefs = prefs;
+        LatinImeLogger.init(this, prefs);
+        SubtypeSwitcher.init(this, prefs);
+        KeyboardSwitcher.init(this, prefs);
         super.onCreate();
         //setStatusIcon(R.drawable.ime_qwerty);
         mResources = getResources();
+        mImm = ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE));
         final Configuration conf = mResources.getConfiguration();
-        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
-        mLanguageSwitcher = new LanguageSwitcher(this);
-        mLanguageSwitcher.loadLocales(prefs);
-        mKeyboardSwitcher = new KeyboardSwitcher(this);
-        mKeyboardSwitcher.setLanguageSwitcher(mLanguageSwitcher);
-        mSystemLocale = conf.locale.toString();
-        mLanguageSwitcher.setSystemLocale(conf.locale);
-        String inputLanguage = mLanguageSwitcher.getInputLanguage();
-        if (inputLanguage == null) {
-            inputLanguage = conf.locale.toString();
-        }
+        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
+        mKeyboardSwitcher = KeyboardSwitcher.getInstance();
         mReCorrectionEnabled = prefs.getBoolean(PREF_RECORRECTION_ENABLED,
                 getResources().getBoolean(R.bool.default_recorrection_enabled));
 
@@ -364,10 +352,10 @@
         boolean tryGC = true;
         for (int i = 0; i < LatinIMEUtil.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
             try {
-                initSuggest(inputLanguage);
+                initSuggest();
                 tryGC = false;
             } catch (OutOfMemoryError e) {
-                tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait(inputLanguage, e);
+                tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait("InitSuggest", e);
             }
         }
 
@@ -377,19 +365,7 @@
         // register to receive ringer mode changes for silent mode
         IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
         registerReceiver(mReceiver, filter);
-        if (VOICE_INSTALLED) {
-            mVoiceInput = new VoiceInput(this, this);
-            mHints = new Hints(this, new Hints.Display() {
-                public void showHint(int viewResource) {
-                    LayoutInflater inflater = (LayoutInflater) getSystemService(
-                            Context.LAYOUT_INFLATER_SERVICE);
-                    View view = inflater.inflate(viewResource, null);
-                    setCandidatesView(view);
-                    setCandidatesViewShown(true);
-                    mIsShowingHint = true;
-                }
-              });
-        }
+        mVoiceConnector = VoiceIMEConnector.init(this, prefs, mHandler);
         prefs.registerOnSharedPreferenceChangeListener(this);
     }
 
@@ -397,7 +373,7 @@
      * Loads a dictionary or multiple separated dictionary
      * @return returns array of dictionary resource ids
      */
-    /* package */ static int[] getDictionary(Resources res) {
+    public static int[] getDictionary(Resources res) {
         String packageName = LatinIME.class.getPackage().getName();
         XmlResourceParser xrp = res.getXml(R.xml.dictionary);
         ArrayList<Integer> dictionaries = new ArrayList<Integer>();
@@ -432,37 +408,34 @@
         return dict;
     }
 
-    private void initSuggest(String locale) {
-        mInputLocale = locale;
+    private void initSuggest() {
+        updateAutoTextEnabled();
+        String locale = mSubtypeSwitcher.getInputLocaleStr();
 
         Resources orig = getResources();
-        Configuration conf = orig.getConfiguration();
-        Locale saveLocale = conf.locale;
-        conf.locale = new Locale(locale);
-        orig.updateConfiguration(conf, orig.getDisplayMetrics());
+        Locale savedLocale = mSubtypeSwitcher.changeSystemLocale(new Locale(locale));
         if (mSuggest != null) {
             mSuggest.close();
         }
-        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
-        mQuickFixes = sp.getBoolean(PREF_QUICK_FIXES, true);
+        final SharedPreferences prefs = mPrefs;
+        mQuickFixes = prefs.getBoolean(PREF_QUICK_FIXES, true);
 
         int[] dictionaries = getDictionary(orig);
         mSuggest = new Suggest(this, dictionaries);
-        updateAutoTextEnabled(saveLocale);
+        loadAndSetAutoCompletionThreshold(prefs);
         if (mUserDictionary != null) mUserDictionary.close();
-        mUserDictionary = new UserDictionary(this, mInputLocale);
+        mUserDictionary = new UserDictionary(this, locale);
         if (mContactsDictionary == null) {
             mContactsDictionary = new ContactsDictionary(this, Suggest.DIC_CONTACTS);
         }
         if (mAutoDictionary != null) {
             mAutoDictionary.close();
         }
-        mAutoDictionary = new AutoDictionary(this, this, mInputLocale, Suggest.DIC_AUTO);
+        mAutoDictionary = new AutoDictionary(this, this, locale, Suggest.DIC_AUTO);
         if (mUserBigramDictionary != null) {
             mUserBigramDictionary.close();
         }
-        mUserBigramDictionary = new UserBigramDictionary(this, this, mInputLocale,
-                Suggest.DIC_USER);
+        mUserBigramDictionary = new UserBigramDictionary(this, this, locale, Suggest.DIC_USER);
         mSuggest.setUserBigramDictionary(mUserBigramDictionary);
         mSuggest.setUserDictionary(mUserDictionary);
         mSuggest.setContactsDictionary(mContactsDictionary);
@@ -471,8 +444,7 @@
         mWordSeparators = mResources.getString(R.string.word_separators);
         mSentenceSeparators = mResources.getString(R.string.sentence_separators);
 
-        conf.locale = saveLocale;
-        orig.updateConfiguration(conf, orig.getDisplayMetrics());
+        mSubtypeSwitcher.changeSystemLocale(savedLocale);
     }
 
     @Override
@@ -484,9 +456,7 @@
             mContactsDictionary.close();
         }
         unregisterReceiver(mReceiver);
-        if (VOICE_INSTALLED && mVoiceInput != null) {
-            mVoiceInput.destroy();
-        }
+        mVoiceConnector.destroy();
         LatinImeLogger.commit();
         LatinImeLogger.onDestroy();
         super.onDestroy();
@@ -494,51 +464,38 @@
 
     @Override
     public void onConfigurationChanged(Configuration conf) {
-        // If the system locale changes and is different from the saved
-        // locale (mSystemLocale), then reload the input locale list from the
-        // latin ime settings (shared prefs) and reset the input locale
-        // to the first one.
-        final String systemLocale = conf.locale.toString();
-        if (!TextUtils.equals(systemLocale, mSystemLocale)) {
-            mSystemLocale = systemLocale;
-            if (mLanguageSwitcher != null) {
-                mLanguageSwitcher.loadLocales(
-                        PreferenceManager.getDefaultSharedPreferences(this));
-                mLanguageSwitcher.setSystemLocale(conf.locale);
-                toggleLanguage(true, true);
-            } else {
-                reloadKeyboards();
-            }
-        }
+        mSubtypeSwitcher.onConfigurationChanged(conf);
+        if (mSubtypeSwitcher.isKeyboardMode())
+            onKeyboardLanguageChanged();
+        updateAutoTextEnabled();
+
         // If orientation changed while predicting, commit the change
         if (conf.orientation != mOrientation) {
             InputConnection ic = getCurrentInputConnection();
             commitTyped(ic);
             if (ic != null) ic.finishComposingText(); // For voice input
             mOrientation = conf.orientation;
-            reloadKeyboards();
+            final int mode = mKeyboardSwitcher.getKeyboardMode();
+            final EditorInfo attribute = getCurrentInputEditorInfo();
+            final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
+            mKeyboardSwitcher.loadKeyboard(mode, imeOptions,
+                    mVoiceConnector.isVoiceButtonEnabled(),
+                    mVoiceConnector.isVoiceButtonOnPrimary());
         }
+
         mConfigurationChanging = true;
         super.onConfigurationChanged(conf);
-        if (mRecognizing) {
-            switchToRecognitionStatusView();
-        }
+        mVoiceConnector.onConfigurationChanged(mConfigurationChanging);
         mConfigurationChanging = false;
     }
 
     @Override
     public View onCreateInputView() {
-        mKeyboardSwitcher.recreateInputView();
-        mKeyboardSwitcher.makeKeyboards(true);
-        mKeyboardSwitcher.setKeyboardMode(
-                KeyboardSwitcher.MODE_TEXT, 0,
-                shouldShowVoiceButton(makeFieldContext(), getCurrentInputEditorInfo()));
-        return mKeyboardSwitcher.getInputView();
+        return mKeyboardSwitcher.onCreateInputView();
     }
 
     @Override
     public View onCreateCandidatesView() {
-        mKeyboardSwitcher.makeKeyboards(true);
         mCandidateViewContainer = (LinearLayout) getLayoutInflater().inflate(
                 R.layout.candidates, null);
         mCandidateView = (CandidateView) mCandidateViewContainer.findViewById(R.id.candidates);
@@ -547,95 +504,89 @@
         return mCandidateViewContainer;
     }
 
+    private static boolean isPasswordVariation(int variation) {
+        return variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD
+                || variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
+                || variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD;
+    }
+
+    private static boolean isEmailVariation(int variation) {
+        return variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+                || variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS;
+    }
+
     @Override
     public void onStartInputView(EditorInfo attribute, boolean restarting) {
-        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
+        final KeyboardSwitcher switcher = mKeyboardSwitcher;
+        LatinKeyboardView inputView = switcher.getInputView();
+
         // In landscape mode, this method gets called without the input view being created.
         if (inputView == null) {
             return;
         }
 
+        mSubtypeSwitcher.updateParametersOnStartInputView();
+
         if (mRefreshKeyboardRequired) {
             mRefreshKeyboardRequired = false;
-            toggleLanguage(true, true);
+            onKeyboardLanguageChanged();
         }
 
-        mKeyboardSwitcher.makeKeyboards(false);
-
         TextEntryState.newSession(this);
 
         // Most such things we decide below in the switch statement, but we need to know
         // now whether this is a password text field, because we need to know now (before
         // the switch statement) whether we want to enable the voice button.
-        mPasswordText = false;
         int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION;
-        if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD ||
-                variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
-            mPasswordText = true;
-        }
-
-        mEnableVoiceButton = shouldShowVoiceButton(makeFieldContext(), attribute);
-        final boolean enableVoiceButton = mEnableVoiceButton && mEnableVoice;
-
-        mAfterVoiceInput = false;
-        mImmediatelyAfterVoiceInput = false;
-        mShowingVoiceSuggestions = false;
-        mVoiceInputHighlighted = false;
+        mVoiceConnector.resetVoiceStates(isPasswordVariation(variation));
         mInputTypeNoAutoCorrect = false;
         mPredictionOn = false;
         mCompletionOn = false;
         mCompletions = null;
-        mCapsLock = false;
         mEnteredText = null;
 
+        final int mode;
         switch (attribute.inputType & EditorInfo.TYPE_MASK_CLASS) {
             case EditorInfo.TYPE_CLASS_NUMBER:
             case EditorInfo.TYPE_CLASS_DATETIME:
-                // fall through
-                // NOTE: For now, we use the phone keyboard for NUMBER and DATETIME until we get
-                // a dedicated number entry keypad.
-                // TODO: Use a dedicated number entry keypad here when we get one.
+                mode = KeyboardId.MODE_NUMBER;
+                break;
             case EditorInfo.TYPE_CLASS_PHONE:
-                mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_PHONE,
-                        attribute.imeOptions, enableVoiceButton);
+                mode = KeyboardId.MODE_PHONE;
                 break;
             case EditorInfo.TYPE_CLASS_TEXT:
-                mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT,
-                        attribute.imeOptions, enableVoiceButton);
                 //startPrediction();
                 mPredictionOn = true;
                 // Make sure that passwords are not displayed in candidate view
-                if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD ||
-                        variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD ) {
+                if (isPasswordVariation(variation)) {
                     mPredictionOn = false;
                 }
-                if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+                if (isEmailVariation(variation)
                         || variation == EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME) {
                     mAutoSpace = false;
                 } else {
                     mAutoSpace = true;
                 }
-                if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) {
+                if (isEmailVariation(variation)) {
                     mPredictionOn = false;
-                    mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_EMAIL,
-                            attribute.imeOptions, enableVoiceButton);
+                    mode = KeyboardId.MODE_EMAIL;
                 } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_URI) {
                     mPredictionOn = false;
-                    mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_URL,
-                            attribute.imeOptions, enableVoiceButton);
+                    mode = KeyboardId.MODE_URL;
                 } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
-                    mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_IM,
-                            attribute.imeOptions, enableVoiceButton);
+                    mode = KeyboardId.MODE_IM;
                 } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) {
                     mPredictionOn = false;
+                    mode = KeyboardId.MODE_TEXT;
                 } else if (variation == EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) {
-                    mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_WEB,
-                            attribute.imeOptions, enableVoiceButton);
+                    mode = KeyboardId.MODE_WEB;
                     // If it's a browser edit field and auto correct is not ON explicitly, then
                     // disable auto correction, but keep suggestions on.
                     if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT) == 0) {
                         mInputTypeNoAutoCorrect = true;
                     }
+                } else {
+                    mode = KeyboardId.MODE_TEXT;
                 }
 
                 // If NO_SUGGESTIONS is set, don't do prediction.
@@ -654,18 +605,24 @@
                 }
                 break;
             default:
-                mKeyboardSwitcher.setKeyboardMode(KeyboardSwitcher.MODE_TEXT,
-                        attribute.imeOptions, enableVoiceButton);
+                mode = KeyboardId.MODE_TEXT;
+                break;
         }
         inputView.closing();
         mComposing.setLength(0);
         mPredicting = false;
         mDeleteCount = 0;
         mJustAddedAutoSpace = false;
-        loadSettings();
-        updateShiftKeyState(attribute);
 
-        setCandidatesViewShownInternal(isCandidateStripVisible() || mCompletionOn,
+        loadSettings(attribute);
+        if (mSubtypeSwitcher.isKeyboardMode()) {
+            switcher.loadKeyboard(mode, attribute.imeOptions,
+                    mVoiceConnector.isVoiceButtonEnabled(),
+                    mVoiceConnector.isVoiceButtonOnPrimary());
+            switcher.updateShiftState();
+        }
+
+        setCandidatesViewShownInternal(isCandidateStripVisible(),
                 false /* needsInputViewShown */ );
         updateSuggestions();
 
@@ -676,21 +633,30 @@
 
         inputView.setPreviewEnabled(mPopupOn);
         inputView.setProximityCorrectionEnabled(true);
-        mPredictionOn = mPredictionOn && (mCorrectionMode > 0 || mShowSuggestions);
+        mPredictionOn = mPredictionOn && (mCorrectionMode > 0 || isSuggestionShown());
         // If we just entered a text field, maybe it has some old text that requires correction
         checkReCorrectionOnStart();
         checkTutorial(attribute.privateImeOptions);
+        inputView.setForeground(true);
+
+        mVoiceConnector.onStartInputView(mKeyboardSwitcher.getInputView().getWindowToken());
+
         if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
     }
 
     private void checkReCorrectionOnStart() {
-        if (mReCorrectionEnabled && isPredictionOn()) {
+        if (!mReCorrectionEnabled) return;
+
+        final InputConnection ic = getCurrentInputConnection();
+        if (ic == null) return;
+        // There could be a pending composing span.  Clean it up first.
+        ic.finishComposingText();
+
+        if (isSuggestionShown() && isPredictionOn()) {
             // First get the cursor position. This is required by setOldSuggestions(), so that
             // it can pass the correct range to setComposingRegion(). At this point, we don't
             // have valid values for mLastSelectionStart/Stop because onUpdateSelection() has
             // not been called yet.
-            InputConnection ic = getCurrentInputConnection();
-            if (ic == null) return;
             ExtractedTextRequest etr = new ExtractedTextRequest();
             etr.token = 0; // anything is fine here
             ExtractedText et = ic.getExtractedText(etr, 0);
@@ -701,7 +667,7 @@
 
             // Then look for possible corrections in a delayed fashion
             if (!TextUtils.isEmpty(et.text) && isCursorTouchingWord()) {
-                postUpdateOldSuggestions();
+                mHandler.postUpdateOldSuggestions();
             }
         }
     }
@@ -713,17 +679,10 @@
         LatinImeLogger.commit();
         onAutoCompletionStateChanged(false);
 
-        if (VOICE_INSTALLED && !mConfigurationChanging) {
-            if (mAfterVoiceInput) {
-                mVoiceInput.flushAllTextModificationCounters();
-                mVoiceInput.logInputEnded();
-            }
-            mVoiceInput.flushLogs();
-            mVoiceInput.cancel();
-        }
-        if (mKeyboardSwitcher.getInputView() != null) {
-            mKeyboardSwitcher.getInputView().closing();
-        }
+        mVoiceConnector.flushVoiceInputLogs(mConfigurationChanging);
+
+        KeyboardView inputView = mKeyboardSwitcher.getInputView();
+        if (inputView != null) inputView.closing();
         if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites();
         if (mUserBigramDictionary != null) mUserBigramDictionary.flushPendingWrites();
     }
@@ -731,21 +690,17 @@
     @Override
     public void onFinishInputView(boolean finishingInput) {
         super.onFinishInputView(finishingInput);
-        // Remove penging messages related to update suggestions
-        mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS);
-        mHandler.removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
+        KeyboardView inputView = mKeyboardSwitcher.getInputView();
+        if (inputView != null) inputView.setForeground(false);
+        // Remove pending messages related to update suggestions
+        mHandler.cancelUpdateSuggestions();
+        mHandler.cancelUpdateOldSuggestions();
     }
 
     @Override
     public void onUpdateExtractedText(int token, ExtractedText text) {
         super.onUpdateExtractedText(token, text);
-        InputConnection ic = getCurrentInputConnection();
-        if (!mImmediatelyAfterVoiceInput && mAfterVoiceInput && ic != null) {
-            if (mHints.showPunctuationHintIfNecessary(ic)) {
-                mVoiceInput.logPunctuationHintDisplayed();
-            }
-        }
-        mImmediatelyAfterVoiceInput = false;
+        mVoiceConnector.showPunctuationHintIfNecessary();
     }
 
     @Override
@@ -764,26 +719,22 @@
                     + ", ce=" + candidatesEnd);
         }
 
-        if (mAfterVoiceInput) {
-            mVoiceInput.setCursorPos(newSelEnd);
-            mVoiceInput.setSelectionSpan(newSelEnd - newSelStart);
-        }
+        mVoiceConnector.setCursorAndSelection(newSelEnd, newSelStart);
 
         // If the current selection in the text view changes, we should
         // clear whatever candidate text we have.
-        if ((((mComposing.length() > 0 && mPredicting) || mVoiceInputHighlighted)
-                && (newSelStart != candidatesEnd
-                    || newSelEnd != candidatesEnd)
-                && mLastSelectionStart != newSelStart)) {
+        if ((((mComposing.length() > 0 && mPredicting)
+                || mVoiceConnector.isVoiceInputHighlighted()) && (newSelStart != candidatesEnd
+                        || newSelEnd != candidatesEnd) && mLastSelectionStart != newSelStart)) {
             mComposing.setLength(0);
             mPredicting = false;
-            postUpdateSuggestions();
+            mHandler.postUpdateSuggestions();
             TextEntryState.reset();
             InputConnection ic = getCurrentInputConnection();
             if (ic != null) {
                 ic.finishComposingText();
             }
-            mVoiceInputHighlighted = false;
+            mVoiceConnector.setVoiceInputHighlighted(false);
         } else if (!mPredicting && !mJustAccepted) {
             switch (TextEntryState.getState()) {
                 case ACCEPTED_DEFAULT:
@@ -795,33 +746,29 @@
             }
         }
         mJustAccepted = false;
-        postUpdateShiftKeyState();
+        mHandler.postUpdateShiftKeyState();
 
         // Make a note of the cursor position
         mLastSelectionStart = newSelStart;
         mLastSelectionEnd = newSelEnd;
 
-        if (mReCorrectionEnabled) {
+        if (mReCorrectionEnabled && isSuggestionShown()) {
             // Don't look for corrections if the keyboard is not visible
-            if (mKeyboardSwitcher != null && mKeyboardSwitcher.getInputView() != null
-                    && mKeyboardSwitcher.getInputView().isShown()) {
+            if (mKeyboardSwitcher.isInputViewShown()) {
                 // Check if we should go in or out of correction mode.
-                if (isPredictionOn()
-                        && mJustRevertedSeparator == null
+                if (isPredictionOn() && !mJustReverted
                         && (candidatesStart == candidatesEnd || newSelStart != oldSelStart
                                 || TextEntryState.isCorrecting())
-                                && (newSelStart < newSelEnd - 1 || (!mPredicting))
-                                && !mVoiceInputHighlighted) {
+                                && (newSelStart < newSelEnd - 1 || (!mPredicting))) {
                     if (isCursorTouchingWord() || mLastSelectionStart < mLastSelectionEnd) {
-                        postUpdateOldSuggestions();
+                        mHandler.postUpdateOldSuggestions();
                     } else {
                         abortCorrection(false);
                         // Show the punctuation suggestions list if the current one is not
                         // and if not showing "Touch again to save".
-                        if (mCandidateView != null
-                                && !mSuggestPuncList.equals(mCandidateView.getSuggestions())
-                                        && !mCandidateView.isShowingAddToDictionaryHint()) {
-                            setNextSuggestions();
+                        if (mCandidateView != null && !isShowingPunctuationList()
+                                && !mCandidateView.isShowingAddToDictionaryHint()) {
+                            setPunctuationSuggestions();
                         }
                     }
                 }
@@ -870,18 +817,7 @@
             mOptionsDialog.dismiss();
             mOptionsDialog = null;
         }
-        if (!mConfigurationChanging) {
-            if (mAfterVoiceInput) mVoiceInput.logInputEnded();
-            if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
-                mVoiceInput.logKeyboardWarningDialogDismissed();
-                mVoiceWarningDialog.dismiss();
-                mVoiceWarningDialog = null;
-            }
-            if (VOICE_INSTALLED & mRecognizing) {
-                mVoiceInput.cancel();
-            }
-        }
-        mWordToSuggestions.clear();
+        mVoiceConnector.hideVoiceWindow(mConfigurationChanging);
         mWordHistory.clear();
         super.hideWindow();
         TextEntryState.endSession();
@@ -917,8 +853,8 @@
     private void setCandidatesViewShownInternal(boolean shown, boolean needsInputViewShown) {
         // TODO: Remove this if we support candidates with hard keyboard
         if (onEvaluateInputViewShown()) {
-            super.setCandidatesViewShown(shown && mKeyboardSwitcher.getInputView() != null
-                    && (needsInputViewShown ? mKeyboardSwitcher.getInputView().isShown() : true));
+            super.setCandidatesViewShown(shown
+                    && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true));
         }
     }
 
@@ -985,10 +921,9 @@
                 if (mTutorial != null) {
                     return true;
                 }
-                LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
                 // Enable shift key and DPAD to do selections
-                if (inputView != null && inputView.isShown()
-                        && inputView.isShifted()) {
+                if (mKeyboardSwitcher.isInputViewShown()
+                        && mKeyboardSwitcher.isShiftedOrShiftLocked()) {
                     event = new KeyEvent(event.getDownTime(), event.getEventTime(),
                             event.getAction(), event.getKeyCode(), event.getRepeatCount(),
                             event.getDeviceId(), event.getScanCode(),
@@ -1002,30 +937,7 @@
         return super.onKeyUp(keyCode, event);
     }
 
-    private void revertVoiceInput() {
-        InputConnection ic = getCurrentInputConnection();
-        if (ic != null) ic.commitText("", 1);
-        updateSuggestions();
-        mVoiceInputHighlighted = false;
-    }
-
-    private void commitVoiceInput() {
-        InputConnection ic = getCurrentInputConnection();
-        if (ic != null) ic.finishComposingText();
-        updateSuggestions();
-        mVoiceInputHighlighted = false;
-    }
-
-    private void reloadKeyboards() {
-        mKeyboardSwitcher.setLanguageSwitcher(mLanguageSwitcher);
-        if (mKeyboardSwitcher.getInputView() != null
-                && mKeyboardSwitcher.getKeyboardMode() != KeyboardSwitcher.MODE_NONE) {
-            mKeyboardSwitcher.setVoiceMode(mEnableVoice && mEnableVoiceButton, mVoiceOnPrimary);
-        }
-        mKeyboardSwitcher.makeKeyboards(true);
-    }
-
-    private void commitTyped(InputConnection inputConnection) {
+    public void commitTyped(InputConnection inputConnection) {
         if (mPredicting) {
             mPredicting = false;
             if (mComposing.length() > 0) {
@@ -1040,27 +952,13 @@
         }
     }
 
-    private void postUpdateShiftKeyState() {
-        mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE);
-        // TODO: Should remove this 300ms delay?
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SHIFT_STATE), 300);
-    }
-
-    public void updateShiftKeyState(EditorInfo attr) {
+    public boolean getCurrentAutoCapsState() {
         InputConnection ic = getCurrentInputConnection();
-        if (ic != null && attr != null && mKeyboardSwitcher.isAlphabetMode()) {
-            mKeyboardSwitcher.setShifted(mShiftKeyState.isMomentary() || mCapsLock
-                    || getCursorCapsMode(ic, attr) != 0);
-        }
-    }
-
-    private int getCursorCapsMode(InputConnection ic, EditorInfo attr) {
-        int caps = 0;
         EditorInfo ei = getCurrentInputEditorInfo();
-        if (mAutoCap && ei != null && ei.inputType != EditorInfo.TYPE_NULL) {
-            caps = ic.getCursorCapsMode(attr.inputType);
+        if (mAutoCap && ic != null && ei != null && ei.inputType != EditorInfo.TYPE_NULL) {
+            return ic.getCursorCapsMode(ei.inputType) != 0;
         }
-        return caps;
+        return false;
     }
 
     private void swapPunctuationAndSpace() {
@@ -1068,12 +966,13 @@
         if (ic == null) return;
         CharSequence lastTwo = ic.getTextBeforeCursor(2, 0);
         if (lastTwo != null && lastTwo.length() == 2
-                && lastTwo.charAt(0) == KEYCODE_SPACE && isSentenceSeparator(lastTwo.charAt(1))) {
+                && lastTwo.charAt(0) == Keyboard.CODE_SPACE
+                && isSentenceSeparator(lastTwo.charAt(1))) {
             ic.beginBatchEdit();
             ic.deleteSurroundingText(2, 0);
             ic.commitText(lastTwo.charAt(1) + " ", 1);
             ic.endBatchEdit();
-            updateShiftKeyState(getCurrentInputEditorInfo());
+            mKeyboardSwitcher.updateShiftState();
             mJustAddedAutoSpace = true;
         }
     }
@@ -1083,14 +982,14 @@
         if (ic == null) return;
         CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
         if (lastThree != null && lastThree.length() == 3
-                && lastThree.charAt(0) == KEYCODE_PERIOD
-                && lastThree.charAt(1) == KEYCODE_SPACE
-                && lastThree.charAt(2) == KEYCODE_PERIOD) {
+                && lastThree.charAt(0) == Keyboard.CODE_PERIOD
+                && lastThree.charAt(1) == Keyboard.CODE_SPACE
+                && lastThree.charAt(2) == Keyboard.CODE_PERIOD) {
             ic.beginBatchEdit();
             ic.deleteSurroundingText(3, 0);
             ic.commitText(" ..", 1);
             ic.endBatchEdit();
-            updateShiftKeyState(getCurrentInputEditorInfo());
+            mKeyboardSwitcher.updateShiftState();
         }
     }
 
@@ -1102,12 +1001,13 @@
         CharSequence lastThree = ic.getTextBeforeCursor(3, 0);
         if (lastThree != null && lastThree.length() == 3
                 && Character.isLetterOrDigit(lastThree.charAt(0))
-                && lastThree.charAt(1) == KEYCODE_SPACE && lastThree.charAt(2) == KEYCODE_SPACE) {
+                && lastThree.charAt(1) == Keyboard.CODE_SPACE
+                && lastThree.charAt(2) == Keyboard.CODE_SPACE) {
             ic.beginBatchEdit();
             ic.deleteSurroundingText(2, 0);
             ic.commitText(". ", 1);
             ic.endBatchEdit();
-            updateShiftKeyState(getCurrentInputEditorInfo());
+            mKeyboardSwitcher.updateShiftState();
             mJustAddedAutoSpace = true;
         }
     }
@@ -1120,8 +1020,8 @@
         // if there is one.
         CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
         if (lastOne != null && lastOne.length() == 1
-                && lastOne.charAt(0) == KEYCODE_PERIOD
-                && text.charAt(0) == KEYCODE_PERIOD) {
+                && lastOne.charAt(0) == Keyboard.CODE_PERIOD
+                && text.charAt(0) == Keyboard.CODE_PERIOD) {
             ic.deleteSurroundingText(1, 0);
         }
     }
@@ -1132,7 +1032,7 @@
 
         CharSequence lastOne = ic.getTextBeforeCursor(1, 0);
         if (lastOne != null && lastOne.length() == 1
-                && lastOne.charAt(0) == KEYCODE_SPACE) {
+                && lastOne.charAt(0) == Keyboard.CODE_SPACE) {
             ic.deleteSurroundingText(1, 0);
         }
     }
@@ -1141,7 +1041,7 @@
         mUserDictionary.addWord(word, 128);
         // Suggestion strip should be updated after the operation of adding word to the
         // user dictionary
-        postUpdateSuggestions();
+        mHandler.postUpdateSuggestions();
         return true;
     }
 
@@ -1153,14 +1053,9 @@
         }
     }
 
-    private void showInputMethodPicker() {
-        ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE))
-                .showInputMethodPicker();
-    }
-
-    private void onOptionKeyPressed() {
+    private void onSettingsKeyPressed() {
         if (!isShowingOptionDialog()) {
-            if (LatinIMEUtil.hasMultipleEnabledIMEs(this)) {
+            if (LatinIMEUtil.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
                 showOptionsMenu();
             } else {
                 launchSettings();
@@ -1168,10 +1063,10 @@
         }
     }
 
-    private void onOptionKeyLongPressed() {
+    private void onSettingsKeyLongPressed() {
         if (!isShowingOptionDialog()) {
-            if (LatinIMEUtil.hasMultipleEnabledIMEs(this)) {
-                showInputMethodPicker();
+            if (LatinIMEUtil.hasMultipleEnabledIMEsOrSubtypes(mImm)) {
+                mImm.showInputMethodPicker();
             } else {
                 launchSettings();
             }
@@ -1184,80 +1079,80 @@
 
     // Implementation of KeyboardViewListener
 
+    @Override
     public void onKey(int primaryCode, int[] keyCodes, int x, int y) {
         long when = SystemClock.uptimeMillis();
-        if (primaryCode != Keyboard.KEYCODE_DELETE ||
-                when > mLastKeyTime + QUICK_PRESS) {
+        if (primaryCode != Keyboard.CODE_DELETE || when > mLastKeyTime + QUICK_PRESS) {
             mDeleteCount = 0;
         }
         mLastKeyTime = when;
-        final boolean distinctMultiTouch = mKeyboardSwitcher.hasDistinctMultitouch();
+        KeyboardSwitcher switcher = mKeyboardSwitcher;
+        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
         switch (primaryCode) {
-            case Keyboard.KEYCODE_DELETE:
-                handleBackspace();
-                mDeleteCount++;
-                LatinImeLogger.logOnDelete();
-                break;
-            case Keyboard.KEYCODE_SHIFT:
-                // Shift key is handled in onPress() when device has distinct multi-touch panel.
-                if (!distinctMultiTouch)
-                    handleShift();
-                break;
-            case Keyboard.KEYCODE_MODE_CHANGE:
-                // Symbol key is handled in onPress() when device has distinct multi-touch panel.
-                if (!distinctMultiTouch)
-                    changeKeyboardMode();
-                break;
-            case Keyboard.KEYCODE_CANCEL:
-                if (!isShowingOptionDialog()) {
-                    handleClose();
-                }
-                break;
-            case LatinKeyboardView.KEYCODE_OPTIONS:
-                onOptionKeyPressed();
-                break;
-            case LatinKeyboardView.KEYCODE_OPTIONS_LONGPRESS:
-                onOptionKeyLongPressed();
-                break;
-            case LatinKeyboardView.KEYCODE_NEXT_LANGUAGE:
-                toggleLanguage(false, true);
-                break;
-            case LatinKeyboardView.KEYCODE_PREV_LANGUAGE:
-                toggleLanguage(false, false);
-                break;
-            case LatinKeyboardView.KEYCODE_VOICE:
-                if (VOICE_INSTALLED) {
-                    startListening(false /* was a button press, was not a swipe */);
-                }
-                break;
-            case 9 /*Tab*/:
-                sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
-                break;
-            default:
-                if (primaryCode != KEYCODE_ENTER) {
-                    mJustAddedAutoSpace = false;
-                }
-                RingCharBuffer.getInstance().push((char)primaryCode, x, y);
-                LatinImeLogger.logOnInputChar();
-                if (isWordSeparator(primaryCode)) {
-                    handleSeparator(primaryCode);
-                } else {
-                    handleCharacter(primaryCode, keyCodes);
-                }
-                // Cancel the just reverted state
-                mJustRevertedSeparator = null;
+        case Keyboard.CODE_DELETE:
+            handleBackspace();
+            mDeleteCount++;
+            LatinImeLogger.logOnDelete();
+            break;
+        case Keyboard.CODE_SHIFT:
+            // Shift key is handled in onPress() when device has distinct multi-touch panel.
+            if (!distinctMultiTouch)
+                switcher.toggleShift();
+            break;
+        case Keyboard.CODE_SWITCH_ALPHA_SYMBOL:
+            // Symbol key is handled in onPress() when device has distinct multi-touch panel.
+            if (!distinctMultiTouch)
+                switcher.changeKeyboardMode();
+            break;
+        case Keyboard.CODE_CANCEL:
+            if (!isShowingOptionDialog()) {
+                handleClose();
+            }
+            break;
+        case Keyboard.CODE_SETTINGS:
+            onSettingsKeyPressed();
+            break;
+        case Keyboard.CODE_SETTINGS_LONGPRESS:
+            onSettingsKeyLongPressed();
+            break;
+        case Keyboard.CODE_NEXT_LANGUAGE:
+            toggleLanguage(false, true);
+            break;
+        case Keyboard.CODE_PREV_LANGUAGE:
+            toggleLanguage(false, false);
+            break;
+        case Keyboard.CODE_CAPSLOCK:
+            switcher.toggleCapsLock();
+            break;
+        case Keyboard.CODE_VOICE: /* was a button press, was not a swipe */
+            mVoiceConnector.startListening(false,
+                    mKeyboardSwitcher.getInputView().getWindowToken(), mConfigurationChanging);
+            break;
+        case Keyboard.CODE_TAB:
+            handleTab();
+            break;
+        default:
+            if (primaryCode != Keyboard.CODE_ENTER) {
+                mJustAddedAutoSpace = false;
+            }
+            RingCharBuffer.getInstance().push((char)primaryCode, x, y);
+            LatinImeLogger.logOnInputChar();
+            if (isWordSeparator(primaryCode)) {
+                handleSeparator(primaryCode);
+            } else {
+                handleCharacter(primaryCode, keyCodes);
+            }
+            // Cancel the just reverted state
+            mJustReverted = false;
         }
-        if (mKeyboardSwitcher.onKey(primaryCode)) {
-            changeKeyboardMode();
-        }
+        switcher.onKey(primaryCode);
         // Reset after any single keystroke
         mEnteredText = null;
     }
 
+    @Override
     public void onText(CharSequence text) {
-        if (VOICE_INSTALLED && mVoiceInputHighlighted) {
-            commitVoiceInput();
-        }
+        mVoiceConnector.commitVoiceInput();
         InputConnection ic = getCurrentInputConnection();
         if (ic == null) return;
         abortCorrection(false);
@@ -1268,40 +1163,26 @@
         maybeRemovePreviousPeriod(text);
         ic.commitText(text, 1);
         ic.endBatchEdit();
-        updateShiftKeyState(getCurrentInputEditorInfo());
-        mJustRevertedSeparator = null;
+        mKeyboardSwitcher.updateShiftState();
+        mJustReverted = false;
         mJustAddedAutoSpace = false;
         mEnteredText = text;
     }
 
+    @Override
     public void onCancel() {
         // User released a finger outside any key
     }
 
     private void handleBackspace() {
-        if (VOICE_INSTALLED && mVoiceInputHighlighted) {
-            mVoiceInput.incrementTextModificationDeleteCount(
-                    mVoiceResults.candidates.get(0).toString().length());
-            revertVoiceInput();
-            return;
-        }
+        if (mVoiceConnector.logAndRevertVoiceInput()) return;
         boolean deleteChar = false;
         InputConnection ic = getCurrentInputConnection();
         if (ic == null) return;
 
         ic.beginBatchEdit();
 
-        if (mAfterVoiceInput) {
-            // Don't log delete if the user is pressing delete at
-            // the beginning of the text box (hence not deleting anything)
-            if (mVoiceInput.getCursorPos() > 0) {
-                // If anything was selected before the delete was pressed, increment the
-                // delete count by the length of the selection
-                int deleteLen  =  mVoiceInput.getSelectionSpan() > 0 ?
-                        mVoiceInput.getSelectionSpan() : 1;
-                mVoiceInput.incrementTextModificationDeleteCount(deleteLen);
-            }
-        }
+        mVoiceConnector.handleBackspace();
 
         if (mPredicting) {
             final int length = mComposing.length();
@@ -1312,14 +1193,14 @@
                 if (mComposing.length() == 0) {
                     mPredicting = false;
                 }
-                postUpdateSuggestions();
+                mHandler.postUpdateSuggestions();
             } else {
                 ic.deleteSurroundingText(1, 0);
             }
         } else {
             deleteChar = true;
         }
-        postUpdateShiftKeyState();
+        mHandler.postUpdateShiftKeyState();
         TextEntryState.backspace();
         if (TextEntryState.getState() == TextEntryState.State.UNDO_COMMIT) {
             revertLastWord(deleteChar);
@@ -1344,55 +1225,46 @@
                 }
             }
         }
-        mJustRevertedSeparator = null;
+        mJustReverted = false;
         ic.endBatchEdit();
     }
 
-    private void resetShift() {
-        handleShiftInternal(true);
-    }
+    private void handleTab() {
+        final int imeOptions = getCurrentInputEditorInfo().imeOptions;
+        final int navigationFlags =
+                EditorInfo.IME_FLAG_NAVIGATE_NEXT | EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS;
+        if ((imeOptions & navigationFlags) == 0) {
+            sendDownUpKeyEvents(KeyEvent.KEYCODE_TAB);
+            return;
+        }
 
-    private void handleShift() {
-        handleShiftInternal(false);
-    }
+        final InputConnection ic = getCurrentInputConnection();
+        if (ic == null)
+            return;
 
-    private void handleShiftInternal(boolean forceNormal) {
-        mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE);
-        KeyboardSwitcher switcher = mKeyboardSwitcher;
-        LatinKeyboardView inputView = switcher.getInputView();
-        if (switcher.isAlphabetMode()) {
-            if (mCapsLock || forceNormal) {
-                mCapsLock = false;
-                switcher.setShifted(false);
-            } else if (inputView != null) {
-                if (inputView.isShifted()) {
-                    mCapsLock = true;
-                    switcher.setShiftLocked(true);
-                } else {
-                    switcher.setShifted(true);
-                }
-            }
-        } else {
-            switcher.toggleShift();
+        // True if keyboard is in either chording shift or manual temporary upper case mode.
+        final boolean isManualTemporaryUpperCase = mKeyboardSwitcher.isManualTemporaryUpperCase();
+        if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0
+                && !isManualTemporaryUpperCase) {
+            ic.performEditorAction(EditorInfo.IME_ACTION_NEXT);
+        } else if ((imeOptions & EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS) != 0
+                && isManualTemporaryUpperCase) {
+            ic.performEditorAction(EditorInfo.IME_ACTION_PREVIOUS);
         }
     }
 
     private void abortCorrection(boolean force) {
         if (force || TextEntryState.isCorrecting()) {
+            TextEntryState.onAbortCorrection();
+            setCandidatesViewShown(isCandidateStripVisible());
             getCurrentInputConnection().finishComposingText();
             clearSuggestions();
         }
     }
 
     private void handleCharacter(int primaryCode, int[] keyCodes) {
-        if (VOICE_INSTALLED && mVoiceInputHighlighted) {
-            commitVoiceInput();
-        }
+        mVoiceConnector.handleCharacter();
 
-        if (mAfterVoiceInput) {
-            // Assume input length is 1. This assumption fails for smiley face insertions.
-            mVoiceInput.incrementTextModificationInsertCount(1);
-        }
         if (mLastSelectionStart == mLastSelectionEnd && TextEntryState.isCorrecting()) {
             abortCorrection(false);
         }
@@ -1405,13 +1277,14 @@
                 mWord.reset();
             }
         }
-        if (mKeyboardSwitcher.getInputView().isShifted()) {
+        KeyboardSwitcher switcher = mKeyboardSwitcher;
+        if (switcher.isShiftedOrShiftLocked()) {
             if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
                     || keyCodes[0] > Character.MAX_CODE_POINT) {
                 return;
             }
             primaryCode = keyCodes[0];
-            if (mKeyboardSwitcher.isAlphabetMode() && Character.isLowerCase(primaryCode)) {
+            if (switcher.isAlphabetMode() && Character.isLowerCase(primaryCode)) {
                 int upperCaseCode = Character.toUpperCase(primaryCode);
                 if (upperCaseCode != primaryCode) {
                     primaryCode = upperCaseCode;
@@ -1424,9 +1297,8 @@
             }
         }
         if (mPredicting) {
-            if (mKeyboardSwitcher.getInputView().isShifted()
-                    && mKeyboardSwitcher.isAlphabetMode()
-                    && mComposing.length() == 0) {
+            if (mComposing.length() == 0 && switcher.isAlphabetMode()
+                    && switcher.isShiftedOrShiftLocked()) {
                 mWord.setFirstCharCapitalized(true);
             }
             mComposing.append((char) primaryCode);
@@ -1435,33 +1307,25 @@
             if (ic != null) {
                 // If it's the first letter, make note of auto-caps state
                 if (mWord.size() == 1) {
-                    mWord.setAutoCapitalized(
-                            getCursorCapsMode(ic, getCurrentInputEditorInfo()) != 0);
+                    mWord.setAutoCapitalized(getCurrentAutoCapsState());
                 }
                 ic.setComposingText(mComposing, 1);
             }
-            postUpdateSuggestions();
+            mHandler.postUpdateSuggestions();
         } else {
             sendKeyChar((char)primaryCode);
         }
-        updateShiftKeyState(getCurrentInputEditorInfo());
+        switcher.updateShiftState();
         if (LatinIME.PERF_DEBUG) measureCps();
         TextEntryState.typedCharacter((char) primaryCode, isWordSeparator(primaryCode));
     }
 
     private void handleSeparator(int primaryCode) {
-        if (VOICE_INSTALLED && mVoiceInputHighlighted) {
-            commitVoiceInput();
-        }
-
-        if (mAfterVoiceInput){
-            // Assume input length is 1. This assumption fails for smiley face insertions.
-            mVoiceInput.incrementTextModificationInsertPunctuationCount(1);
-        }
+        mVoiceConnector.handleSeparator();
 
         // Should dismiss the "Touch again to save" message when handling separator
         if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) {
-            postUpdateSuggestions();
+            mHandler.postUpdateSuggestions();
         }
 
         boolean pickedDefault = false;
@@ -1476,21 +1340,18 @@
             // not to auto correct, but accept the typed word. For instance,
             // in Italian dov' should not be expanded to dove' because the elision
             // requires the last vowel to be removed.
-            if (mAutoCorrectOn && primaryCode != '\'' &&
-                    (mJustRevertedSeparator == null
-                            || mJustRevertedSeparator.length() == 0
-                            || mJustRevertedSeparator.charAt(0) != primaryCode)) {
+            if (mAutoCorrectOn && primaryCode != '\'' && !mJustReverted) {
                 pickedDefault = pickDefaultSuggestion();
                 // Picked the suggestion by the space key.  We consider this
                 // as "added an auto space".
-                if (primaryCode == KEYCODE_SPACE) {
+                if (primaryCode == Keyboard.CODE_SPACE) {
                     mJustAddedAutoSpace = true;
                 }
             } else {
                 commitTyped(ic);
             }
         }
-        if (mJustAddedAutoSpace && primaryCode == KEYCODE_ENTER) {
+        if (mJustAddedAutoSpace && primaryCode == Keyboard.CODE_ENTER) {
             removeTrailingSpace();
             mJustAddedAutoSpace = false;
         }
@@ -1499,21 +1360,21 @@
         // Handle the case of ". ." -> " .." with auto-space if necessary
         // before changing the TextEntryState.
         if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
-                && primaryCode == KEYCODE_PERIOD) {
+                && primaryCode == Keyboard.CODE_PERIOD) {
             reswapPeriodAndSpace();
         }
 
         TextEntryState.typedCharacter((char) primaryCode, true);
         if (TextEntryState.getState() == TextEntryState.State.PUNCTUATION_AFTER_ACCEPTED
-                && primaryCode != KEYCODE_ENTER) {
+                && primaryCode != Keyboard.CODE_ENTER) {
             swapPunctuationAndSpace();
-        } else if (isPredictionOn() && primaryCode == KEYCODE_SPACE) {
+        } else if (isPredictionOn() && primaryCode == Keyboard.CODE_SPACE) {
             doubleSpace();
         }
         if (pickedDefault) {
             TextEntryState.backToAcceptedDefault(mWord.getTypedWord());
         }
-        updateShiftKeyState(getCurrentInputEditorInfo());
+        mKeyboardSwitcher.updateShiftState();
         if (ic != null) {
             ic.endBatchEdit();
         }
@@ -1521,16 +1382,11 @@
 
     private void handleClose() {
         commitTyped(getCurrentInputConnection());
-        if (VOICE_INSTALLED & mRecognizing) {
-            mVoiceInput.cancel();
-        }
+        mVoiceConnector.handleClose();
         requestHideSelf(0);
-        if (mKeyboardSwitcher != null) {
-            LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
-            if (inputView != null) {
-                inputView.closing();
-            }
-        }
+        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
+        if (inputView != null)
+            inputView.closing();
         TextEntryState.endSession();
     }
 
@@ -1551,216 +1407,62 @@
         mWordHistory.add(entry);
     }
 
-    private void postUpdateSuggestions() {
-        mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS);
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_SUGGESTIONS), 100);
-    }
-
-    private void postUpdateOldSuggestions() {
-        mHandler.removeMessages(MSG_UPDATE_OLD_SUGGESTIONS);
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UPDATE_OLD_SUGGESTIONS), 300);
-    }
-
     private boolean isPredictionOn() {
         return mPredictionOn;
     }
 
+    private boolean isShowingPunctuationList() {
+        return mSuggestPuncList.equals(mCandidateView.getSuggestions());
+    }
+
+    private boolean isSuggestionShown() {
+        return (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_VALUE)
+                || (mSuggestionVisibility == SUGGESTION_VISIBILILTY_SHOW_ONLY_PORTRAIT_VALUE
+                        && mOrientation == Configuration.ORIENTATION_PORTRAIT);
+    }
+
     private boolean isCandidateStripVisible() {
-        return isPredictionOn() && mShowSuggestions;
+        boolean forceVisible = mCandidateView.isShowingAddToDictionaryHint()
+                || TextEntryState.isCorrecting();
+        return forceVisible || (isSuggestionShown()
+                && (isPredictionOn() || mCompletionOn || isShowingPunctuationList()));
     }
 
-    public void onCancelVoice() {
-        if (mRecognizing) {
-            switchToKeyboardView();
-        }
-    }
-
-    private void switchToKeyboardView() {
-      mHandler.post(new Runnable() {
-          public void run() {
-              mRecognizing = false;
-              if (mKeyboardSwitcher.getInputView() != null) {
-                setInputView(mKeyboardSwitcher.getInputView());
-              }
-              setCandidatesViewShown(true);
-              updateInputViewShown();
-              postUpdateSuggestions();
-          }});
-    }
-
-    private void switchToRecognitionStatusView() {
-        final boolean configChanged = mConfigurationChanging;
+    public void switchToKeyboardView() {
         mHandler.post(new Runnable() {
+            @Override
             public void run() {
-                setCandidatesViewShown(false);
-                mRecognizing = true;
-                View v = mVoiceInput.getView();
-                ViewParent p = v.getParent();
-                if (p != null && p instanceof ViewGroup) {
-                    ((ViewGroup)v.getParent()).removeView(v);
+                if (DEBUG) {
+                    Log.d(TAG, "Switch to keyboard view.");
                 }
-                setInputView(v);
+                View v = mKeyboardSwitcher.getInputView();
+                if (v != null) {
+                    // Confirms that the keyboard view doesn't have parent view.
+                    ViewParent p = v.getParent();
+                    if (p != null && p instanceof ViewGroup) {
+                        ((ViewGroup) p).removeView(v);
+                    }
+                    setInputView(v);
+                }
+                setCandidatesViewShown(isCandidateStripVisible());
                 updateInputViewShown();
-                if (configChanged) {
-                    mVoiceInput.onConfigurationChanged();
-                }
-        }});
-    }
-
-    private void startListening(boolean swipe) {
-        if (!mHasUsedVoiceInput ||
-                (!mLocaleSupportedForVoiceInput && !mHasUsedVoiceInputUnsupportedLocale)) {
-            // Calls reallyStartListening if user clicks OK, does nothing if user clicks Cancel.
-            showVoiceWarningDialog(swipe);
-        } else {
-            reallyStartListening(swipe);
-        }
-    }
-
-    private void reallyStartListening(boolean swipe) {
-        if (!mHasUsedVoiceInput) {
-            // The user has started a voice input, so remember that in the
-            // future (so we don't show the warning dialog after the first run).
-            SharedPreferences.Editor editor =
-                    PreferenceManager.getDefaultSharedPreferences(this).edit();
-            editor.putBoolean(PREF_HAS_USED_VOICE_INPUT, true);
-            SharedPreferencesCompat.apply(editor);
-            mHasUsedVoiceInput = true;
-        }
-
-        if (!mLocaleSupportedForVoiceInput && !mHasUsedVoiceInputUnsupportedLocale) {
-            // The user has started a voice input from an unsupported locale, so remember that
-            // in the future (so we don't show the warning dialog the next time they do this).
-            SharedPreferences.Editor editor =
-                    PreferenceManager.getDefaultSharedPreferences(this).edit();
-            editor.putBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, true);
-            SharedPreferencesCompat.apply(editor);
-            mHasUsedVoiceInputUnsupportedLocale = true;
-        }
-
-        // Clear N-best suggestions
-        clearSuggestions();
-
-        FieldContext context = new FieldContext(
-            getCurrentInputConnection(),
-            getCurrentInputEditorInfo(),
-            mLanguageSwitcher.getInputLanguage(),
-            mLanguageSwitcher.getEnabledLanguages());
-        mVoiceInput.startListening(context, swipe);
-        switchToRecognitionStatusView();
-    }
-
-    private void showVoiceWarningDialog(final boolean swipe) {
-        AlertDialog.Builder builder = new AlertDialog.Builder(this);
-        builder.setCancelable(true);
-        builder.setIcon(R.drawable.ic_mic_dialog);
-        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-            public void onClick(DialogInterface dialog, int whichButton) {
-                mVoiceInput.logKeyboardWarningDialogOk();
-                reallyStartListening(swipe);
+                mHandler.postUpdateSuggestions();
             }
         });
-        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-            public void onClick(DialogInterface dialog, int whichButton) {
-                mVoiceInput.logKeyboardWarningDialogCancel();
-            }
-        });
-
-        if (mLocaleSupportedForVoiceInput) {
-            String message = getString(R.string.voice_warning_may_not_understand) + "\n\n" +
-                    getString(R.string.voice_warning_how_to_turn_off);
-            builder.setMessage(message);
-        } else {
-            String message = getString(R.string.voice_warning_locale_not_supported) + "\n\n" +
-                    getString(R.string.voice_warning_may_not_understand) + "\n\n" +
-                    getString(R.string.voice_warning_how_to_turn_off);
-            builder.setMessage(message);
-        }
-
-        builder.setTitle(R.string.voice_warning_title);
-        mVoiceWarningDialog = builder.create();
-
-        Window window = mVoiceWarningDialog.getWindow();
-        WindowManager.LayoutParams lp = window.getAttributes();
-        lp.token = mKeyboardSwitcher.getInputView().getWindowToken();
-        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
-        window.setAttributes(lp);
-        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-        mVoiceInput.logKeyboardWarningDialogShown();
-        mVoiceWarningDialog.show();
     }
 
-    public void onVoiceResults(List<String> candidates,
-            Map<String, List<CharSequence>> alternatives) {
-        if (!mRecognizing) {
-            return;
-        }
-        mVoiceResults.candidates = candidates;
-        mVoiceResults.alternatives = alternatives;
-        mHandler.sendMessage(mHandler.obtainMessage(MSG_VOICE_RESULTS));
-    }
-
-    private void handleVoiceResults() {
-        mAfterVoiceInput = true;
-        mImmediatelyAfterVoiceInput = true;
-
-        InputConnection ic = getCurrentInputConnection();
-        if (!isFullscreenMode()) {
-            // Start listening for updates to the text from typing, etc.
-            if (ic != null) {
-                ExtractedTextRequest req = new ExtractedTextRequest();
-                ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
-            }
-        }
-
-        vibrate();
-        switchToKeyboardView();
-
-        final List<CharSequence> nBest = new ArrayList<CharSequence>();
-        boolean capitalizeFirstWord = preferCapitalization()
-                || (mKeyboardSwitcher.isAlphabetMode()
-                        && mKeyboardSwitcher.getInputView().isShifted());
-        for (String c : mVoiceResults.candidates) {
-            if (capitalizeFirstWord) {
-                c = Character.toUpperCase(c.charAt(0)) + c.substring(1, c.length());
-            }
-            nBest.add(c);
-        }
-
-        if (nBest.size() == 0) {
-            return;
-        }
-
-        String bestResult = nBest.get(0).toString();
-
-        mVoiceInput.logVoiceInputDelivered(bestResult.length());
-
-        mHints.registerVoiceResult(bestResult);
-
-        if (ic != null) ic.beginBatchEdit(); // To avoid extra updates on committing older text
-
-        commitTyped(ic);
-        EditingUtil.appendText(ic, bestResult);
-
-        if (ic != null) ic.endBatchEdit();
-
-        mVoiceInputHighlighted = true;
-        mWordToSuggestions.putAll(mVoiceResults.alternatives);
-    }
-
-    private void clearSuggestions() {
+    public void clearSuggestions() {
         setSuggestions(null, false, false, false);
     }
 
-    private void setSuggestions(
+    public void setSuggestions(
             List<CharSequence> suggestions,
             boolean completions,
             boolean typedWordValid,
             boolean haveMinimalSuggestion) {
 
-        if (mIsShowingHint) {
+        if (mVoiceConnector.getAndResetIsShowingHint()) {
              setCandidatesView(mCandidateViewContainer);
-             mIsShowingHint = false;
         }
 
         if (mCandidateView != null) {
@@ -1769,17 +1471,17 @@
         }
     }
 
-    private void updateSuggestions() {
-        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
-        ((LatinKeyboard) inputView.getKeyboard()).setPreferredLetters(null);
+    public void updateSuggestions() {
+        mKeyboardSwitcher.setPreferredLetters(null);
 
         // Check if we have a suggestion engine attached.
-        if ((mSuggest == null || !isPredictionOn()) && !mVoiceInputHighlighted) {
+        if ((mSuggest == null || !isPredictionOn())
+                && !mVoiceConnector.isVoiceInputHighlighted()) {
             return;
         }
 
         if (!mPredicting) {
-            setNextSuggestions();
+            setPunctuationSuggestions();
             return;
         }
         showSuggestions(mWord);
@@ -1792,8 +1494,8 @@
     }
 
     private void showCorrections(WordAlternatives alternatives) {
+        mKeyboardSwitcher.setPreferredLetters(null);
         List<CharSequence> stringList = alternatives.getAlternatives();
-        ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).setPreferredLetters(null);
         showSuggestions(stringList, alternatives.getOriginalWord(), false, false);
     }
 
@@ -1808,12 +1510,10 @@
         // Log.d("LatinIME","Suggest Total Time - " + (stopTime - startTime));
 
         int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies();
+        mKeyboardSwitcher.setPreferredLetters(nextLettersFrequencies);
 
-        ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).setPreferredLetters(
-                nextLettersFrequencies);
-
-        boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasMinimalCorrection();
-        //|| mCorrectionMode == mSuggest.CORRECTION_FULL;
+        boolean correctionAvailable = !mInputTypeNoAutoCorrect && !mJustReverted
+                && mSuggest.hasMinimalCorrection();
         CharSequence typedWord = word.getTypedWord();
         // If we're in basic correct
         boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
@@ -1842,13 +1542,13 @@
         } else {
             mBestWord = null;
         }
-        setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn);
+        setCandidatesViewShown(isCandidateStripVisible());
     }
 
     private boolean pickDefaultSuggestion() {
         // Complete any pending candidate query first
-        if (mHandler.hasMessages(MSG_UPDATE_SUGGESTIONS)) {
-            mHandler.removeMessages(MSG_UPDATE_SUGGESTIONS);
+        if (mHandler.hasPendingUpdateSuggestions()) {
+            mHandler.cancelUpdateSuggestions();
             updateSuggestions();
         }
         if (mBestWord != null && mBestWord.length() > 0) {
@@ -1864,14 +1564,8 @@
     }
 
     public void pickSuggestionManually(int index, CharSequence suggestion) {
-        if (mAfterVoiceInput && mShowingVoiceSuggestions) mVoiceInput.logNBestChoose(index);
         List<CharSequence> suggestions = mCandidateView.getSuggestions();
-
-        if (mAfterVoiceInput && !mShowingVoiceSuggestions) {
-            mVoiceInput.flushAllTextModificationCounters();
-            // send this intent AFTER logging any prior aggregated edits.
-            mVoiceInput.logTextModifiedByChooseSuggestion(suggestion.length());
-        }
+        mVoiceConnector.flushAndLogAllTextModificationCounters(index, suggestion, mWordSeparators);
 
         final boolean correcting = TextEntryState.isCorrecting();
         InputConnection ic = getCurrentInputConnection();
@@ -1888,7 +1582,7 @@
             if (mCandidateView != null) {
                 mCandidateView.clear();
             }
-            updateShiftKeyState(getCurrentInputEditorInfo());
+            mKeyboardSwitcher.updateShiftState();
             if (ic != null) {
                 ic.endBatchEdit();
             }
@@ -1903,8 +1597,8 @@
             LatinImeLogger.logOnManualSuggestion(
                     "", suggestion.toString(), index, suggestions);
             final char primaryCode = suggestion.charAt(0);
-            onKey(primaryCode, new int[]{primaryCode}, LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE,
-                    LatinKeyboardBaseView.NOT_A_TOUCH_COORDINATE);
+            onKey(primaryCode, new int[]{primaryCode}, KeyboardView.NOT_A_TOUCH_COORDINATE,
+                    KeyboardView.NOT_A_TOUCH_COORDINATE);
             if (ic != null) {
                 ic.endBatchEdit();
             }
@@ -1935,13 +1629,13 @@
             // Fool the state watcher so that a subsequent backspace will not do a revert, unless
             // we just did a correction, in which case we need to stay in
             // TextEntryState.State.PICKED_SUGGESTION state.
-            TextEntryState.typedCharacter((char) KEYCODE_SPACE, true);
-            setNextSuggestions();
+            TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true);
+            setPunctuationSuggestions();
         } else if (!showingAddToDictionaryHint) {
             // If we're not showing the "Touch again to save", then show corrections again.
             // In case the cursor position doesn't change, make sure we show the suggestions again.
             clearSuggestions();
-            postUpdateOldSuggestions();
+            mHandler.postUpdateOldSuggestions();
         }
         if (showingAddToDictionaryHint) {
             mCandidateView.showAddToDictionaryHint(suggestion);
@@ -1951,27 +1645,6 @@
         }
     }
 
-    private void rememberReplacedWord(CharSequence suggestion) {
-        if (mShowingVoiceSuggestions) {
-            // Retain the replaced word in the alternatives array.
-            EditingUtil.Range range = new EditingUtil.Range();
-            String wordToBeReplaced = EditingUtil.getWordAtCursor(getCurrentInputConnection(),
-                    mWordSeparators, range);
-            if (!mWordToSuggestions.containsKey(wordToBeReplaced)) {
-                wordToBeReplaced = wordToBeReplaced.toLowerCase();
-            }
-            if (mWordToSuggestions.containsKey(wordToBeReplaced)) {
-                List<CharSequence> suggestions = mWordToSuggestions.get(wordToBeReplaced);
-                if (suggestions.contains(suggestion)) {
-                    suggestions.remove(suggestion);
-                }
-                suggestions.add(wordToBeReplaced);
-                mWordToSuggestions.remove(wordToBeReplaced);
-                mWordToSuggestions.put(suggestion.toString(), suggestions);
-            }
-        }
-    }
-
     /**
      * Commits the chosen word to the text field and saves it for later
      * retrieval.
@@ -1981,61 +1654,23 @@
      *            word.
      */
     private void pickSuggestion(CharSequence suggestion, boolean correcting) {
-        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
-        if (mCapsLock) {
-            suggestion = suggestion.toString().toUpperCase();
-        } else if (preferCapitalization()
-                || (mKeyboardSwitcher.isAlphabetMode()
-                        && inputView.isShifted())) {
-            suggestion = suggestion.toString().toUpperCase().charAt(0)
-                    + suggestion.subSequence(1, suggestion.length()).toString();
-        }
+        KeyboardSwitcher switcher = mKeyboardSwitcher;
+        if (!switcher.isKeyboardAvailable())
+            return;
         InputConnection ic = getCurrentInputConnection();
         if (ic != null) {
-            rememberReplacedWord(suggestion);
+            mVoiceConnector.rememberReplacedWord(suggestion, mWordSeparators);
             ic.commitText(suggestion, 1);
         }
         saveWordInHistory(suggestion);
         mPredicting = false;
         mCommittedLength = suggestion.length();
-        ((LatinKeyboard) inputView.getKeyboard()).setPreferredLetters(null);
+        switcher.setPreferredLetters(null);
         // If we just corrected a word, then don't show punctuations
         if (!correcting) {
-            setNextSuggestions();
+            setPunctuationSuggestions();
         }
-        updateShiftKeyState(getCurrentInputEditorInfo());
-    }
-
-    /**
-     * Tries to apply any voice alternatives for the word if this was a spoken word and
-     * there are voice alternatives.
-     * @param touching The word that the cursor is touching, with position information
-     * @return true if an alternative was found, false otherwise.
-     */
-    private boolean applyVoiceAlternatives(EditingUtil.SelectedWord touching) {
-        // Search for result in spoken word alternatives
-        String selectedWord = touching.word.toString().trim();
-        if (!mWordToSuggestions.containsKey(selectedWord)) {
-            selectedWord = selectedWord.toLowerCase();
-        }
-        if (mWordToSuggestions.containsKey(selectedWord)) {
-            mShowingVoiceSuggestions = true;
-            List<CharSequence> suggestions = mWordToSuggestions.get(selectedWord);
-            // If the first letter of touching is capitalized, make all the suggestions
-            // start with a capital letter.
-            if (Character.isUpperCase(touching.word.charAt(0))) {
-                for (int i = 0; i < suggestions.size(); i++) {
-                    String origSugg = (String) suggestions.get(i);
-                    String capsSugg = origSugg.toUpperCase().charAt(0)
-                            + origSugg.subSequence(1, origSugg.length()).toString();
-                    suggestions.set(i, capsSugg);
-                }
-            }
-            setSuggestions(suggestions, false, true, true);
-            setCandidatesViewShown(true);
-            return true;
-        }
-        return false;
+        switcher.updateShiftState();
     }
 
     /**
@@ -2086,7 +1721,7 @@
     }
 
     private void setOldSuggestions() {
-        mShowingVoiceSuggestions = false;
+        mVoiceConnector.setShowingVoiceSuggestions(false);
         if (mCandidateView != null && mCandidateView.isShowingAddToDictionaryHint()) {
             return;
         }
@@ -2100,7 +1735,8 @@
             if (touching != null && touching.word.length() > 1) {
                 ic.beginBatchEdit();
 
-                if (!applyVoiceAlternatives(touching) && !applyTypedAlternatives(touching)) {
+                if (!mVoiceConnector.applyVoiceAlternatives(touching)
+                        && !applyTypedAlternatives(touching)) {
                     abortCorrection(true);
                 } else {
                     TextEntryState.selectedForCorrection();
@@ -2110,14 +1746,15 @@
                 ic.endBatchEdit();
             } else {
                 abortCorrection(true);
-                setNextSuggestions();  // Show the punctuation suggestions list
+                setPunctuationSuggestions();  // Show the punctuation suggestions list
             }
         } else {
             abortCorrection(true);
         }
     }
 
-    private void setNextSuggestions() {
+    private void setPunctuationSuggestions() {
+        setCandidatesViewShown(isCandidateStripVisible());
         setSuggestions(mSuggestPuncList, false, false, false);
     }
 
@@ -2188,7 +1825,7 @@
         if (!mPredicting && length > 0) {
             final InputConnection ic = getCurrentInputConnection();
             mPredicting = true;
-            mJustRevertedSeparator = ic.getTextBeforeCursor(1, 0);
+            mJustReverted = true;
             if (deleteChar) ic.deleteSurroundingText(1, 0);
             int toDelete = mCommittedLength;
             CharSequence toTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0);
@@ -2199,10 +1836,10 @@
             ic.deleteSurroundingText(toDelete, 0);
             ic.setComposingText(mComposing, 1);
             TextEntryState.backspace();
-            postUpdateSuggestions();
+            mHandler.postUpdateSuggestions();
         } else {
             sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL);
-            mJustRevertedSeparator = null;
+            mJustReverted = false;
         }
     }
 
@@ -2220,8 +1857,8 @@
     }
 
     private void sendSpace() {
-        sendKeyChar((char)KEYCODE_SPACE);
-        updateShiftKeyState(getCurrentInputEditorInfo());
+        sendKeyChar((char)Keyboard.CODE_SPACE);
+        mKeyboardSwitcher.updateShiftState();
         //onKey(KEY_SPACE[0], KEY_SPACE);
     }
 
@@ -2229,30 +1866,33 @@
         return mWord.isFirstCharCapitalized();
     }
 
-    private void toggleLanguage(boolean reset, boolean next) {
-        if (reset) {
-            mLanguageSwitcher.reset();
-        } else {
-            if (next) {
-                mLanguageSwitcher.next();
-            } else {
-                mLanguageSwitcher.prev();
-            }
-        }
-        int currentKeyboardMode = mKeyboardSwitcher.getKeyboardMode();
-        reloadKeyboards();
-        mKeyboardSwitcher.makeKeyboards(true);
-        mKeyboardSwitcher.setKeyboardMode(currentKeyboardMode, 0,
-                mEnableVoiceButton && mEnableVoice);
-        initSuggest(mLanguageSwitcher.getInputLanguage());
-        mLanguageSwitcher.persist();
-        updateShiftKeyState(getCurrentInputEditorInfo());
+    // Notify that Language has been changed and toggleLanguage will update KeyboaredID according
+    // to new Language.
+    public void onKeyboardLanguageChanged() {
+        toggleLanguage(true, true);
     }
 
+    // "reset" and "next" are used only for USE_SPACEBAR_LANGUAGE_SWITCHER.
+    private void toggleLanguage(boolean reset, boolean next) {
+        if (SubtypeSwitcher.USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            mSubtypeSwitcher.toggleLanguage(reset, next);
+        }
+        // Reload keyboard because the current language has been changed.
+        KeyboardSwitcher switcher = mKeyboardSwitcher;
+        final int mode = switcher.getKeyboardMode();
+        final EditorInfo attribute = getCurrentInputEditorInfo();
+        final int imeOptions = (attribute != null) ? attribute.imeOptions : 0;
+        switcher.loadKeyboard(mode, imeOptions, mVoiceConnector.isVoiceButtonEnabled(),
+                mVoiceConnector.isVoiceButtonOnPrimary());
+        initSuggest();
+        switcher.updateShiftState();
+    }
+
+    @Override
     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
             String key) {
+        mSubtypeSwitcher.onSharedPreferenceChanged(sharedPreferences, key);
         if (PREF_SELECTED_LANGUAGES.equals(key)) {
-            mLanguageSwitcher.loadLocales(sharedPreferences);
             mRefreshKeyboardRequired = true;
         } else if (PREF_RECORRECTION_ENABLED.equals(key)) {
             mReCorrectionEnabled = sharedPreferences.getBoolean(PREF_RECORRECTION_ENABLED,
@@ -2260,79 +1900,58 @@
         }
     }
 
+    @Override
     public void swipeRight() {
         if (LatinKeyboardView.DEBUG_AUTO_PLAY) {
-            ClipboardManager cm = ((ClipboardManager)getSystemService(CLIPBOARD_SERVICE));
-            CharSequence text = cm.getText();
+            CharSequence text = ((android.text.ClipboardManager)getSystemService(
+                    CLIPBOARD_SERVICE)).getText();
             if (!TextUtils.isEmpty(text)) {
                 mKeyboardSwitcher.getInputView().startPlaying(text.toString());
             }
         }
     }
 
+    @Override
     public void swipeLeft() {
     }
 
+    @Override
     public void swipeDown() {
         handleClose();
     }
 
+    @Override
     public void swipeUp() {
-        //launchSettings();
     }
 
+    @Override
     public void onPress(int primaryCode) {
         vibrate();
         playKeyClick(primaryCode);
-        final boolean distinctMultiTouch = mKeyboardSwitcher.hasDistinctMultitouch();
-        if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_SHIFT) {
-            mShiftKeyState.onPress();
-            handleShift();
-        } else if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
-            mSymbolKeyState.onPress();
-            changeKeyboardMode();
+        KeyboardSwitcher switcher = mKeyboardSwitcher;
+        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
+        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
+            switcher.onPressShift();
+        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
+            switcher.onPressSymbol();
         } else {
-            mShiftKeyState.onOtherKeyPressed();
-            mSymbolKeyState.onOtherKeyPressed();
+            switcher.onOtherKeyPressed();
         }
     }
 
+    @Override
     public void onRelease(int primaryCode) {
+        KeyboardSwitcher switcher = mKeyboardSwitcher;
         // Reset any drag flags in the keyboard
-        ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).keyReleased();
-        //vibrate();
-        final boolean distinctMultiTouch = mKeyboardSwitcher.hasDistinctMultitouch();
-        if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_SHIFT) {
-            if (mShiftKeyState.isMomentary())
-                resetShift();
-            mShiftKeyState.onRelease();
-        } else if (distinctMultiTouch && primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
-            if (mSymbolKeyState.isMomentary())
-                changeKeyboardMode();
-            mSymbolKeyState.onRelease();
+        switcher.keyReleased();
+        final boolean distinctMultiTouch = switcher.hasDistinctMultitouch();
+        if (distinctMultiTouch && primaryCode == Keyboard.CODE_SHIFT) {
+            switcher.onReleaseShift();
+        } else if (distinctMultiTouch && primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
+            switcher.onReleaseSymbol();
         }
     }
 
-    private FieldContext makeFieldContext() {
-        return new FieldContext(
-                getCurrentInputConnection(),
-                getCurrentInputEditorInfo(),
-                mLanguageSwitcher.getInputLanguage(),
-                mLanguageSwitcher.getEnabledLanguages());
-    }
-
-    private boolean fieldCanDoVoice(FieldContext fieldContext) {
-        return !mPasswordText
-                && mVoiceInput != null
-                && !mVoiceInput.isBlacklistedField(fieldContext);
-    }
-
-    private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo attribute) {
-        return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext)
-                && !(attribute != null
-                        && IME_OPTION_NO_MICROPHONE.equals(attribute.privateImeOptions))
-                && SpeechRecognizer.isRecognitionAvailable(this);
-    }
 
     // receive ringer mode changes to detect silent mode
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -2365,13 +1984,13 @@
             // FIXME: These should be triggered after auto-repeat logic
             int sound = AudioManager.FX_KEYPRESS_STANDARD;
             switch (primaryCode) {
-                case Keyboard.KEYCODE_DELETE:
+                case Keyboard.CODE_DELETE:
                     sound = AudioManager.FX_KEYPRESS_DELETE;
                     break;
-                case KEYCODE_ENTER:
+                case Keyboard.CODE_ENTER:
                     sound = AudioManager.FX_KEYPRESS_RETURN;
                     break;
-                case KEYCODE_SPACE:
+                case Keyboard.CODE_SPACE:
                     sound = AudioManager.FX_KEYPRESS_SPACEBAR;
                     break;
             }
@@ -2379,12 +1998,13 @@
         }
     }
 
-    private void vibrate() {
+    public void vibrate() {
         if (!mVibrateOn) {
             return;
         }
-        if (mKeyboardSwitcher.getInputView() != null) {
-            mKeyboardSwitcher.getInputView().performHapticFeedback(
+        LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
+        if (inputView != null) {
+            inputView.performHapticFeedback(
                     HapticFeedbackConstants.KEYBOARD_TAP,
                     HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
         }
@@ -2393,7 +2013,7 @@
     private void checkTutorial(String privateImeOptions) {
         if (privateImeOptions == null) return;
         if (privateImeOptions.equals("com.android.setupwizard:ShowTutorial")) {
-            if (mTutorial == null) startTutorial();
+            if (mTutorial == null) mHandler.startTutorial();
         } else if (privateImeOptions.equals("com.android.setupwizard:HideTutorial")) {
             if (mTutorial != null) {
                 if (mTutorial.close()) {
@@ -2403,24 +2023,23 @@
         }
     }
 
-    private void startTutorial() {
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_TUTORIAL), 500);
-    }
-
-    /* package */ void tutorialDone() {
+    // Tutorial.TutorialListener
+    @Override
+    public void onTutorialDone() {
+        sendDownUpKeyEvents(-1); // Inform the setupwizard that tutorial is in last bubble
         mTutorial = null;
     }
 
-    /* package */ void promoteToUserDictionary(String word, int frequency) {
+    public void promoteToUserDictionary(String word, int frequency) {
         if (mUserDictionary.isValidWord(word)) return;
         mUserDictionary.addWord(word, frequency);
     }
 
-    /* package */ WordComposer getCurrentWord() {
+    public WordComposer getCurrentWord() {
         return mWord;
     }
 
-    /* package */ boolean getPopupOn() {
+    public boolean getPopupOn() {
         return mPopupOn;
     }
 
@@ -2438,11 +2057,22 @@
         }
     }
 
-    private void updateAutoTextEnabled(Locale systemLocale) {
+    private void updateAutoTextEnabled() {
         if (mSuggest == null) return;
-        boolean different =
-                !systemLocale.getLanguage().equalsIgnoreCase(mInputLocale.substring(0, 2));
-        mSuggest.setAutoTextEnabled(!different && mQuickFixes);
+        mSuggest.setAutoTextEnabled(mQuickFixes
+                && SubtypeSwitcher.getInstance().isSystemLanguageSameAsInputLanguage());
+    }
+
+    private void updateSuggestionVisibility(SharedPreferences prefs) {
+        final String suggestionVisiblityStr = prefs.getString(
+                PREF_SHOW_SUGGESTIONS_SETTING, mResources.getString(
+                        R.string.prefs_suggestion_visibility_default_value));
+        for (int visibility : SUGGESTION_VISIBILITY_VALUE_ARRAY) {
+            if (suggestionVisiblityStr.equals(mResources.getString(visibility))) {
+                mSuggestionVisibility = visibility;
+                break;
+            }
+        }
     }
 
     protected void launchSettings() {
@@ -2453,7 +2083,7 @@
         launchSettings(LatinIMEDebugSettings.class);
     }
 
-    protected void launchSettings (Class<? extends PreferenceActivity> settingsClass) {
+    protected void launchSettings(Class<? extends PreferenceActivity> settingsClass) {
         handleClose();
         Intent intent = new Intent();
         intent.setClass(LatinIME.this, settingsClass);
@@ -2461,55 +2091,78 @@
         startActivity(intent);
     }
 
-    private void loadSettings() {
+    private void loadSettings(EditorInfo attribute) {
         // Get the settings preferences
-        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
-        mVibrateOn = sp.getBoolean(PREF_VIBRATE_ON, false);
-        mSoundOn = sp.getBoolean(PREF_SOUND_ON, false);
-        mPopupOn = sp.getBoolean(PREF_POPUP_ON,
+        final SharedPreferences prefs = mPrefs;
+        Vibrator vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
+        mVibrateOn = vibrator != null && vibrator.hasVibrator()
+                && prefs.getBoolean(LatinIMESettings.PREF_VIBRATE_ON, false);
+        mSoundOn = prefs.getBoolean(PREF_SOUND_ON, false);
+        mPopupOn = prefs.getBoolean(PREF_POPUP_ON,
                 mResources.getBoolean(R.bool.default_popup_preview));
-        mAutoCap = sp.getBoolean(PREF_AUTO_CAP, true);
-        mQuickFixes = sp.getBoolean(PREF_QUICK_FIXES, true);
-        mHasUsedVoiceInput = sp.getBoolean(PREF_HAS_USED_VOICE_INPUT, false);
-        mHasUsedVoiceInputUnsupportedLocale =
-                sp.getBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, false);
+        mAutoCap = prefs.getBoolean(PREF_AUTO_CAP, true);
+        mQuickFixes = prefs.getBoolean(PREF_QUICK_FIXES, true);
 
-        // Get the current list of supported locales and check the current locale against that
-        // list. We cache this value so as not to check it every time the user starts a voice
-        // input. Because this method is called by onStartInputView, this should mean that as
-        // long as the locale doesn't change while the user is keeping the IME open, the
-        // value should never be stale.
-        String supportedLocalesString = SettingsUtil.getSettingsString(
-                getContentResolver(),
-                SettingsUtil.LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES,
-                DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES);
-        ArrayList<String> voiceInputSupportedLocales =
-                newArrayList(supportedLocalesString.split("\\s+"));
+        mAutoCorrectEnabled = isAutoCorrectEnabled(prefs);
+        mBigramSuggestionEnabled = mAutoCorrectEnabled && isBigramSuggestionEnabled(prefs);
+        loadAndSetAutoCompletionThreshold(prefs);
 
-        mLocaleSupportedForVoiceInput = voiceInputSupportedLocales.contains(mInputLocale);
+        mVoiceConnector.loadSettings(attribute, prefs);
 
-        mShowSuggestions = sp.getBoolean(PREF_SHOW_SUGGESTIONS, true);
-
-        if (VOICE_INSTALLED) {
-            final String voiceMode = sp.getString(PREF_VOICE_MODE,
-                    getString(R.string.voice_mode_main));
-            boolean enableVoice = !voiceMode.equals(getString(R.string.voice_mode_off))
-                    && mEnableVoiceButton;
-            boolean voiceOnPrimary = voiceMode.equals(getString(R.string.voice_mode_main));
-            if (mKeyboardSwitcher != null &&
-                    (enableVoice != mEnableVoice || voiceOnPrimary != mVoiceOnPrimary)) {
-                mKeyboardSwitcher.setVoiceMode(enableVoice, voiceOnPrimary);
-            }
-            mEnableVoice = enableVoice;
-            mVoiceOnPrimary = voiceOnPrimary;
-        }
-        mAutoCorrectEnabled = sp.getBoolean(PREF_AUTO_COMPLETE,
-                mResources.getBoolean(R.bool.enable_autocorrect)) & mShowSuggestions;
-        //mBigramSuggestionEnabled = sp.getBoolean(
-        //        PREF_BIGRAM_SUGGESTIONS, true) & mShowSuggestions;
         updateCorrectionMode();
-        updateAutoTextEnabled(mResources.getConfiguration().locale);
-        mLanguageSwitcher.loadLocales(sp);
+        updateAutoTextEnabled();
+        updateSuggestionVisibility(prefs);
+        SubtypeSwitcher.getInstance().loadSettings();
+    }
+
+    /**
+     *  load Auto completion threshold from SharedPreferences,
+     *  and modify mSuggest's threshold.
+     */
+    private void loadAndSetAutoCompletionThreshold(SharedPreferences sp) {
+        // When mSuggest is not initialized, cannnot modify mSuggest's threshold.
+        if (mSuggest == null) return;
+        // When auto completion setting is turned off, the threshold is ignored.
+        if (!isAutoCorrectEnabled(sp)) return;
+
+        final String currentAutoCompletionSetting = sp.getString(PREF_AUTO_COMPLETION_THRESHOLD,
+                mResources.getString(R.string.auto_completion_threshold_mode_value_modest));
+        final String[] autoCompletionThresholdValues = mResources.getStringArray(
+                R.array.auto_complete_threshold_values);
+        // When autoCompletionThreshold is greater than 1.0,
+        // auto completion is virtually turned off.
+        double autoCompletionThreshold = Double.MAX_VALUE;
+        try {
+            final int arrayIndex = Integer.valueOf(currentAutoCompletionSetting);
+            if (arrayIndex >= 0 && arrayIndex < autoCompletionThresholdValues.length) {
+                autoCompletionThreshold = Double.parseDouble(
+                        autoCompletionThresholdValues[arrayIndex]);
+            }
+        } catch (NumberFormatException e) {
+            // Whenever the threshold settings are correct,
+            // never come here.
+            autoCompletionThreshold = Double.MAX_VALUE;
+            Log.w(TAG, "Cannot load auto completion threshold setting."
+                    + " currentAutoCompletionSetting: " + currentAutoCompletionSetting
+                    + ", autoCompletionThresholdValues: "
+                    + Arrays.toString(autoCompletionThresholdValues));
+        }
+        // TODO: This should be refactored :
+        //           setAutoCompleteThreshold should be called outside of this method.
+        mSuggest.setAutoCompleteThreshold(autoCompletionThreshold);
+    }
+
+    private boolean isAutoCorrectEnabled(SharedPreferences sp) {
+        final String currentAutoCompletionSetting = sp.getString(PREF_AUTO_COMPLETION_THRESHOLD,
+                mResources.getString(R.string.auto_completion_threshold_mode_value_modest));
+        final String autoCompletionOff = mResources.getString(
+                R.string.auto_completion_threshold_mode_value_off);
+        return !currentAutoCompletionSetting.equals(autoCompletionOff);
+    }
+
+    private boolean isBigramSuggestionEnabled(SharedPreferences sp) {
+       // TODO: Define default value instead of 'true'.
+       return sp.getBoolean(PREF_BIGRAM_SUGGESTIONS, true);
     }
 
     private void initSuggestPuncList() {
@@ -2537,6 +2190,7 @@
                 itemInputMethod, itemSettings},
                 new DialogInterface.OnClickListener() {
 
+            @Override
             public void onClick(DialogInterface di, int position) {
                 di.dismiss();
                 switch (position) {
@@ -2544,8 +2198,7 @@
                         launchSettings();
                         break;
                     case POS_METHOD:
-                        ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE))
-                            .showInputMethodPicker();
+                        mImm.showInputMethodPicker();
                         break;
                 }
             }
@@ -2561,22 +2214,6 @@
         mOptionsDialog.show();
     }
 
-    private void changeKeyboardMode() {
-        mKeyboardSwitcher.toggleSymbols();
-        if (mCapsLock && mKeyboardSwitcher.isAlphabetMode()) {
-            mKeyboardSwitcher.setShiftLocked(mCapsLock);
-        }
-
-        updateShiftKeyState(getCurrentInputEditorInfo());
-    }
-
-    public static <E> ArrayList<E> newArrayList(E... elements) {
-        int capacity = (elements.length * 110) / 100 + 5;
-        ArrayList<E> list = new ArrayList<E>(capacity);
-        Collections.addAll(list, elements);
-        return list;
-    }
-
     @Override
     protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
         super.dump(fd, fout, args);
@@ -2584,7 +2221,6 @@
         final Printer p = new PrintWriterPrinter(fout);
         p.println("LatinIME state :");
         p.println("  Keyboard mode = " + mKeyboardSwitcher.getKeyboardMode());
-        p.println("  mCapsLock=" + mCapsLock);
         p.println("  mComposing=" + mComposing.toString());
         p.println("  mPredictionOn=" + mPredictionOn);
         p.println("  mCorrectionMode=" + mCorrectionMode);
@@ -2619,4 +2255,9 @@
     public void onAutoCompletionStateChanged(boolean isAutoCompletion) {
         mKeyboardSwitcher.onAutoCompletionStateChanged(isAutoCompletion);
     }
+
+    @Override
+    public void onCurrentInputMethodSubtypeChanged(InputMethodSubtype subtype) {
+        SubtypeSwitcher.getInstance().updateSubtype(subtype);
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/LatinIMEDebugSettings.java b/java/src/com/android/inputmethod/latin/LatinIMEDebugSettings.java
index cba1a0a..68738ec 100644
--- a/java/src/com/android/inputmethod/latin/LatinIMEDebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/LatinIMEDebugSettings.java
@@ -43,6 +43,7 @@
         updateDebugMode();
     }
 
+    @Override
     public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
         if (key.equals(DEBUG_MODE_KEY)) {
             if (mDebugMode != null) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIMESettings.java b/java/src/com/android/inputmethod/latin/LatinIMESettings.java
index ffff33d..3aa89dd 100644
--- a/java/src/com/android/inputmethod/latin/LatinIMESettings.java
+++ b/java/src/com/android/inputmethod/latin/LatinIMESettings.java
@@ -16,8 +16,8 @@
 
 package com.android.inputmethod.latin;
 
-import java.util.ArrayList;
-import java.util.Locale;
+import com.android.inputmethod.voice.VoiceIMEConnector;
+import com.android.inputmethod.voice.VoiceInputLogger;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -25,16 +25,19 @@
 import android.content.DialogInterface;
 import android.content.SharedPreferences;
 import android.os.Bundle;
+import android.os.Vibrator;
 import android.preference.CheckBoxPreference;
 import android.preference.ListPreference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceGroup;
 import android.speech.SpeechRecognizer;
 import android.text.AutoText;
+import android.text.TextUtils;
+import android.text.method.LinkMovementMethod;
 import android.util.Log;
+import android.widget.TextView;
 
-import com.android.inputmethod.voice.SettingsUtil;
-import com.android.inputmethod.voice.VoiceInputLogger;
+import java.util.Locale;
 
 public class LatinIMESettings extends PreferenceActivity
         implements SharedPreferences.OnSharedPreferenceChangeListener,
@@ -43,7 +46,10 @@
     private static final String QUICK_FIXES_KEY = "quick_fixes";
     private static final String PREDICTION_SETTINGS_KEY = "prediction_settings";
     private static final String VOICE_SETTINGS_KEY = "voice_mode";
-    /* package */ static final String PREF_SETTINGS_KEY = "settings_key";
+    private static final String PREF_AUTO_COMPLETION_THRESHOLD = "auto_completion_threshold";
+    private static final String PREF_BIGRAM_SUGGESTIONS = "bigram_suggestion";
+    public static final String PREF_SETTINGS_KEY = "settings_key";
+    /* package */ static final String PREF_VIBRATE_ON = "vibrate_on";
 
     private static final String TAG = "LatinIMESettings";
 
@@ -53,13 +59,23 @@
     private CheckBoxPreference mQuickFixes;
     private ListPreference mVoicePreference;
     private ListPreference mSettingsKeyPreference;
+    private ListPreference mAutoCompletionThreshold;
+    private CheckBoxPreference mBigramSuggestion;
     private boolean mVoiceOn;
 
+    private AlertDialog mDialog;
+
     private VoiceInputLogger mLogger;
 
     private boolean mOkClicked = false;
     private String mVoiceModeOff;
 
+    private void ensureConsistencyOfAutoCompletionSettings() {
+        final String autoCompletionOff = getResources().getString(
+                R.string.auto_completion_threshold_mode_value_off);
+        final String currentSetting = mAutoCompletionThreshold.getValue();
+        mBigramSuggestion.setEnabled(!currentSetting.equals(autoCompletionOff));
+    }
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
@@ -73,6 +89,28 @@
         mVoiceModeOff = getString(R.string.voice_mode_off);
         mVoiceOn = !(prefs.getString(VOICE_SETTINGS_KEY, mVoiceModeOff).equals(mVoiceModeOff));
         mLogger = VoiceInputLogger.getLogger(this);
+
+        mAutoCompletionThreshold = (ListPreference) findPreference(PREF_AUTO_COMPLETION_THRESHOLD);
+        mBigramSuggestion = (CheckBoxPreference) findPreference(PREF_BIGRAM_SUGGESTIONS);
+        ensureConsistencyOfAutoCompletionSettings();
+
+        final boolean showSettingsKeyOption = getResources().getBoolean(
+                R.bool.config_enable_show_settings_key_option);
+        if (!showSettingsKeyOption) {
+            getPreferenceScreen().removePreference(mSettingsKeyPreference);
+        }
+
+        final boolean showVoiceKeyOption = getResources().getBoolean(
+                R.bool.config_enable_show_voice_key_option);
+        if (!showVoiceKeyOption) {
+            getPreferenceScreen().removePreference(mVoicePreference);
+        }
+
+        Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
+        if (vibrator == null || !vibrator.hasVibrator()) {
+            getPreferenceScreen().removePreference(
+                    getPreferenceScreen().findPreference(PREF_VIBRATE_ON));
+        }
     }
 
     @Override
@@ -83,7 +121,7 @@
             ((PreferenceGroup) findPreference(PREDICTION_SETTINGS_KEY))
                     .removePreference(mQuickFixes);
         }
-        if (!LatinIME.VOICE_INSTALLED
+        if (!VoiceIMEConnector.VOICE_INSTALLED
                 || !SpeechRecognizer.isRecognitionAvailable(this)) {
             getPreferenceScreen().removePreference(mVoicePreference);
         } else {
@@ -99,6 +137,7 @@
         super.onDestroy();
     }
 
+    @Override
     public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
         (new BackupManager(this)).dataChanged();
         // If turning on voice input, show dialog
@@ -108,6 +147,7 @@
                 showVoiceConfirmation();
             }
         }
+        ensureConsistencyOfAutoCompletionSettings();
         mVoiceOn = !(prefs.getString(VOICE_SETTINGS_KEY, mVoiceModeOff).equals(mVoiceModeOff));
         updateVoiceModeSummary();
         updateSettingsKeySummary();
@@ -122,6 +162,13 @@
     private void showVoiceConfirmation() {
         mOkClicked = false;
         showDialog(VOICE_INPUT_CONFIRM_DIALOG);
+        // Make URL in the dialog message clickable
+        if (mDialog != null) {
+            TextView textView = (TextView) mDialog.findViewById(android.R.id.message);
+            if (textView != null) {
+                textView.setMovementMethod(LinkMovementMethod.getInstance());
+            }
+        }
     }
 
     private void updateVoiceModeSummary() {
@@ -135,6 +182,7 @@
         switch (id) {
             case VOICE_INPUT_CONFIRM_DIALOG:
                 DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
+                    @Override
                     public void onClick(DialogInterface dialog, int whichButton) {
                         if (whichButton == DialogInterface.BUTTON_NEGATIVE) {
                             mVoicePreference.setValue(mVoiceModeOff);
@@ -154,27 +202,23 @@
                 // Get the current list of supported locales and check the current locale against
                 // that list, to decide whether to put a warning that voice input will not work in
                 // the current language as part of the pop-up confirmation dialog.
-                String supportedLocalesString = SettingsUtil.getSettingsString(
-                        getContentResolver(),
-                        SettingsUtil.LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES,
-                        LatinIME.DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES);
-                ArrayList<String> voiceInputSupportedLocales =
-                        LatinIME.newArrayList(supportedLocalesString.split("\\s+"));
-                boolean localeSupported = voiceInputSupportedLocales.contains(
+                boolean localeSupported = SubtypeSwitcher.getInstance().isVoiceSupported(
                         Locale.getDefault().toString());
 
+                final CharSequence message;
                 if (localeSupported) {
-                    String message = getString(R.string.voice_warning_may_not_understand) + "\n\n" +
-                            getString(R.string.voice_hint_dialog_message);
-                    builder.setMessage(message);
+                    message = TextUtils.concat(
+                            getText(R.string.voice_warning_may_not_understand), "\n\n",
+                                    getText(R.string.voice_hint_dialog_message));
                 } else {
-                    String message = getString(R.string.voice_warning_locale_not_supported) +
-                            "\n\n" + getString(R.string.voice_warning_may_not_understand) + "\n\n" +
-                            getString(R.string.voice_hint_dialog_message);
-                    builder.setMessage(message);
+                    message = TextUtils.concat(
+                            getText(R.string.voice_warning_locale_not_supported), "\n\n",
+                                    getText(R.string.voice_warning_may_not_understand), "\n\n",
+                                            getText(R.string.voice_hint_dialog_message));
                 }
-
+                builder.setMessage(message);
                 AlertDialog dialog = builder.create();
+                mDialog = dialog;
                 dialog.setOnDismissListener(this);
                 mLogger.settingsWarningDialogShown();
                 return dialog;
@@ -184,6 +228,7 @@
         }
     }
 
+    @Override
     public void onDismiss(DialogInterface dialog) {
         mLogger.settingsWarningDialogDismissed();
         if (!mOkClicked) {
diff --git a/java/src/com/android/inputmethod/latin/LatinIMEUtil.java b/java/src/com/android/inputmethod/latin/LatinIMEUtil.java
index 85ecaee..f508b9a 100644
--- a/java/src/com/android/inputmethod/latin/LatinIMEUtil.java
+++ b/java/src/com/android/inputmethod/latin/LatinIMEUtil.java
@@ -16,12 +16,24 @@
 
 package com.android.inputmethod.latin;
 
-import android.view.inputmethod.InputMethodManager;
-
-import android.content.Context;
+import android.inputmethodservice.InputMethodService;
 import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
 import android.text.format.DateUtils;
 import android.util.Log;
+import android.view.inputmethod.InputMethodManager;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 
 public class LatinIMEUtil {
 
@@ -76,9 +88,11 @@
         }
     }
 
-    public static boolean hasMultipleEnabledIMEs(Context context) {
-        return ((InputMethodManager) context.getSystemService(
-                Context.INPUT_METHOD_SERVICE)).getEnabledInputMethodList().size() > 1;
+    public static boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm) {
+        return imm.getEnabledInputMethodList().size() > 1
+        // imm.getEnabledInputMethodSubtypeList(null) will return the current IME's enabled input
+        // method subtype (The current IME should be LatinIME.)
+                || imm.getEnabledInputMethodSubtypeList(null).size() > 1;
     }
 
     /* package */ static class RingCharBuffer {
@@ -86,8 +100,9 @@
         private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC';
         private static final int INVALID_COORDINATE = -2;
         /* package */ static final int BUFSIZE = 20;
-        private Context mContext;
+        private InputMethodService mContext;
         private boolean mEnabled = false;
+        private boolean mUsabilityStudy = false;
         private int mEnd = 0;
         /* package */ int mLength = 0;
         private char[] mCharBuf = new char[BUFSIZE];
@@ -99,9 +114,12 @@
         public static RingCharBuffer getInstance() {
             return sRingCharBuffer;
         }
-        public static RingCharBuffer init(Context context, boolean enabled) {
+        public static RingCharBuffer init(InputMethodService context, boolean enabled,
+                boolean usabilityStudy) {
             sRingCharBuffer.mContext = context;
-            sRingCharBuffer.mEnabled = enabled;
+            sRingCharBuffer.mEnabled = enabled || usabilityStudy;
+            sRingCharBuffer.mUsabilityStudy = usabilityStudy;
+            UsabilityStudyLogUtils.getInstance().init(context);
             return sRingCharBuffer;
         }
         private int normalize(int in) {
@@ -110,6 +128,9 @@
         }
         public void push(char c, int x, int y) {
             if (!mEnabled) return;
+            if (mUsabilityStudy) {
+                UsabilityStudyLogUtils.getInstance().writeChar(c, x, y);
+            }
             mCharBuf[mEnd] = c;
             mXBuf[mEnd] = x;
             mYBuf[mEnd] = y;
@@ -153,7 +174,7 @@
             }
         }
         public String getLastString() {
-            StringBuffer sb = new StringBuffer();
+            StringBuilder sb = new StringBuilder();
             for (int i = 0; i < mLength; ++i) {
                 char c = mCharBuf[normalize(mEnd - 1 - i)];
                 if (!((LatinIME)mContext).isWordSeparator(c)) {
@@ -168,4 +189,205 @@
             mLength = 0;
         }
     }
+
+    public static int editDistance(CharSequence s, CharSequence t) {
+        if (s == null || t == null) {
+            throw new IllegalArgumentException("editDistance: Arguments should not be null.");
+        }
+        final int sl = s.length();
+        final int tl = t.length();
+        int[][] dp = new int [sl + 1][tl + 1];
+        for (int i = 0; i <= sl; i++) {
+            dp[i][0] = i;
+        }
+        for (int j = 0; j <= tl; j++) {
+            dp[0][j] = j;
+        }
+        for (int i = 0; i < sl; ++i) {
+            for (int j = 0; j < tl; ++j) {
+                if (s.charAt(i) == t.charAt(j)) {
+                    dp[i + 1][j + 1] = dp[i][j];
+                } else {
+                    dp[i + 1][j + 1] = 1 + Math.min(dp[i][j],
+                            Math.min(dp[i + 1][j], dp[i][j + 1]));
+                }
+            }
+        }
+        return dp[sl][tl];
+    }
+
+    // In dictionary.cpp, getSuggestion() method,
+    // suggestion scores are computed using the below formula.
+    // original score (called 'frequency')
+    //  := pow(mTypedLetterMultiplier (this is defined 2),
+    //         (the number of matched characters between typed word and suggested word))
+    //     * (individual word's score which defined in the unigram dictionary,
+    //         and this score is defined in range [0, 255].)
+    //     * (when before.length() == after.length(),
+    //         mFullWordMultiplier (this is defined 2))
+    // So, maximum original score is pow(2, before.length()) * 255 * 2
+    // So, we can normalize original score by dividing this value.
+    private static final int MAX_INITIAL_SCORE = 255;
+    private static final int TYPED_LETTER_MULTIPLIER = 2;
+    private static final int FULL_WORD_MULTIPLYER = 2;
+    public static double calcNormalizedScore(CharSequence before, CharSequence after, int score) {
+        final int beforeLength = before.length();
+        final int afterLength = after.length();
+        final int distance = editDistance(before, after);
+        final double maximumScore = MAX_INITIAL_SCORE
+                * Math.pow(TYPED_LETTER_MULTIPLIER, beforeLength)
+                * FULL_WORD_MULTIPLYER;
+        // add a weight based on edit distance.
+        // distance <= max(afterLength, beforeLength) == afterLength,
+        // so, 0 <= distance / afterLength <= 1
+        final double weight = 1.0 - (double) distance / afterLength;
+        return (score / maximumScore) * weight;
+    }
+
+    public static class UsabilityStudyLogUtils {
+        private static final String TAG = "UsabilityStudyLogUtils";
+        private static final String FILENAME = "log.txt";
+        private static final UsabilityStudyLogUtils sInstance =
+                new UsabilityStudyLogUtils();
+        private final Handler mLoggingHandler;
+        private File mFile;
+        private File mDirectory;
+        private InputMethodService mIms;
+        private PrintWriter mWriter;
+        private final Date mDate;
+        private final SimpleDateFormat mDateFormat;
+
+        private UsabilityStudyLogUtils() {
+            mDate = new Date();
+            mDateFormat = new SimpleDateFormat("dd MMM HH:mm:ss.SSS");
+
+            HandlerThread handlerThread = new HandlerThread("UsabilityStudyLogUtils logging task",
+                    Process.THREAD_PRIORITY_BACKGROUND);
+            handlerThread.start();
+            mLoggingHandler = new Handler(handlerThread.getLooper());
+        }
+
+        public static UsabilityStudyLogUtils getInstance() {
+            return sInstance;
+        }
+
+        public void init(InputMethodService ims) {
+            mIms = ims;
+            mDirectory = ims.getFilesDir();
+        }
+
+        private void createLogFileIfNotExist() {
+            if ((mFile == null || !mFile.exists())
+                    && (mDirectory != null && mDirectory.exists())) {
+                try {
+                    mWriter = getPrintWriter(mDirectory, FILENAME, false);
+                } catch (IOException e) {
+                    Log.e(TAG, "Can't create log file.");
+                }
+            }
+        }
+
+        public void writeBackSpace() {
+            UsabilityStudyLogUtils.getInstance().write("<backspace>\t0\t0");
+        }
+
+        public void writeChar(char c, int x, int y) {
+            String inputChar = String.valueOf(c);
+            switch (c) {
+                case '\n':
+                    inputChar = "<enter>";
+                    break;
+                case '\t':
+                    inputChar = "<tab>";
+                    break;
+                case ' ':
+                    inputChar = "<space>";
+                    break;
+            }
+            UsabilityStudyLogUtils.getInstance().write(inputChar + "\t" + x + "\t" + y);
+            LatinImeLogger.onPrintAllUsabilityStudtyLogs();
+        }
+
+        public void write(final String log) {
+            mLoggingHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    createLogFileIfNotExist();
+                    final long currentTime = System.currentTimeMillis();
+                    mDate.setTime(currentTime);
+
+                    final String printString = String.format("%s\t%d\t%s\n",
+                            mDateFormat.format(mDate), currentTime, log);
+                    if (LatinImeLogger.sDBG) {
+                        Log.d(TAG, "Write: " + log);
+                    }
+                    mWriter.print(printString);
+                }
+            });
+        }
+
+        public void printAll() {
+            mLoggingHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mWriter.flush();
+                    StringBuilder sb = new StringBuilder();
+                    BufferedReader br = getBufferedReader();
+                    String line;
+                    try {
+                        while ((line = br.readLine()) != null) {
+                            sb.append('\n');
+                            sb.append(line);
+                        }
+                    } catch (IOException e) {
+                        Log.e(TAG, "Can't read log file.");
+                    } finally {
+                        if (LatinImeLogger.sDBG) {
+                            Log.d(TAG, "output all logs\n" + sb.toString());
+                        }
+                        mIms.getCurrentInputConnection().commitText(sb.toString(), 0);
+                        try {
+                            br.close();
+                        } catch (IOException e) {
+                        }
+                    }
+                }
+            });
+        }
+
+        public void clearAll() {
+            mLoggingHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    if (mFile != null && mFile.exists()) {
+                        if (LatinImeLogger.sDBG) {
+                            Log.d(TAG, "Delete log file.");
+                        }
+                        mFile.delete();
+                        mWriter.close();
+                    }
+                }
+            });
+        }
+
+        private BufferedReader getBufferedReader() {
+            createLogFileIfNotExist();
+            try {
+                return new BufferedReader(new FileReader(mFile));
+            } catch (FileNotFoundException e) {
+                return null;
+            }
+        }
+
+        private PrintWriter getPrintWriter(
+                File dir, String filename, boolean renew) throws IOException {
+            mFile = new File(dir, filename);
+            if (mFile.exists()) {
+                if (renew) {
+                    mFile.delete();
+                }
+            }
+            return new PrintWriter(new FileOutputStream(mFile), true /* autoFlush */);
+        }
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
index a8ab9cc..de194d2 100644
--- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java
+++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
@@ -16,19 +16,23 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.latin.Dictionary.DataType;
 
 import android.content.Context;
 import android.content.SharedPreferences;
-import android.inputmethodservice.Keyboard;
+
 import java.util.List;
 
 public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChangeListener {
 
+    public static boolean sDBG = false;
+
+    @Override
     public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
     }
 
-    public static void init(Context context) {
+    public static void init(Context context, SharedPreferences prefs) {
     }
 
     public static void commit() {
@@ -68,4 +72,6 @@
     public static void onSetKeyboard(Keyboard kb) {
     }
 
+    public static void onPrintAllUsabilityStudtyLogs() {
+    }
 }
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboard.java b/java/src/com/android/inputmethod/latin/LatinKeyboard.java
deleted file mode 100644
index 45a4a95..0000000
--- a/java/src/com/android/inputmethod/latin/LatinKeyboard.java
+++ /dev/null
@@ -1,1022 +0,0 @@
-/*
- * Copyright (C) 2008 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.content.Context;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Paint;
-import android.graphics.Paint.Align;
-import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.inputmethodservice.Keyboard;
-import android.text.TextPaint;
-import android.util.Log;
-import android.view.ViewConfiguration;
-import android.view.inputmethod.EditorInfo;
-
-import java.util.List;
-import java.util.Locale;
-
-public class LatinKeyboard extends Keyboard {
-
-    private static final boolean DEBUG_PREFERRED_LETTER = false;
-    private static final String TAG = "LatinKeyboard";
-    private static final int OPACITY_FULLY_OPAQUE = 255;
-    private static final int SPACE_LED_LENGTH_PERCENT = 80;
-
-    private Drawable mShiftLockIcon;
-    private Drawable mShiftLockPreviewIcon;
-    private Drawable mOldShiftIcon;
-    private Drawable mSpaceIcon;
-    private Drawable mSpaceAutoCompletionIndicator;
-    private Drawable mSpacePreviewIcon;
-    private Drawable mMicIcon;
-    private Drawable mMicPreviewIcon;
-    private Drawable m123MicIcon;
-    private Drawable m123MicPreviewIcon;
-    private final Drawable mButtonArrowLeftIcon;
-    private final Drawable mButtonArrowRightIcon;
-    private Key mShiftKey;
-    private Key mEnterKey;
-    private Key mF1Key;
-    private final Drawable mHintIcon;
-    private Key mSpaceKey;
-    private Key m123Key;
-    private final int NUMBER_HINT_COUNT = 10;
-    private Key[] mNumberHintKeys;
-    private Drawable[] mNumberHintIcons = new Drawable[NUMBER_HINT_COUNT];
-    private int mSpaceKeyIndex = -1;
-    private int mSpaceDragStartX;
-    private int mSpaceDragLastDiff;
-    private Locale mLocale;
-    private LanguageSwitcher mLanguageSwitcher;
-    private final Resources mRes;
-    private final Context mContext;
-    private int mMode;
-    // Whether this keyboard has voice icon on it
-    private boolean mHasVoiceButton;
-    // Whether voice icon is enabled at all
-    private boolean mVoiceEnabled;
-    private final boolean mIsAlphaKeyboard;
-    private CharSequence m123Label;
-    private boolean mCurrentlyInSpace;
-    private SlidingLocaleDrawable mSlidingLocaleIcon;
-    private int[] mPrefLetterFrequencies;
-    private int mPrefLetter;
-    private int mPrefLetterX;
-    private int mPrefLetterY;
-    private int mPrefDistance;
-
-    // TODO: generalize for any keyboardId
-    private boolean mIsBlackSym;
-
-    // TODO: remove this attribute when either Keyboard.mDefaultVerticalGap or Key.parent becomes
-    // non-private.
-    private final int mVerticalGap;
-
-    private static final int SHIFT_OFF = 0;
-    private static final int SHIFT_ON = 1;
-    private static final int SHIFT_LOCKED = 2;
-    
-    private int mShiftState = SHIFT_OFF;
-
-    private static final float SPACEBAR_DRAG_THRESHOLD = 0.8f;
-    private static final float OVERLAP_PERCENTAGE_LOW_PROB = 0.70f;
-    private static final float OVERLAP_PERCENTAGE_HIGH_PROB = 0.85f;
-    // Minimum width of space key preview (proportional to keyboard width)
-    private static final float SPACEBAR_POPUP_MIN_RATIO = 0.4f;
-    // Height in space key the language name will be drawn. (proportional to space key height)
-    private static final float SPACEBAR_LANGUAGE_BASELINE = 0.6f;
-    // If the full language name needs to be smaller than this value to be drawn on space key,
-    // its short language name will be used instead.
-    private static final float MINIMUM_SCALE_OF_LANGUAGE_NAME = 0.8f;
-
-    private static int sSpacebarVerticalCorrection;
-
-    public LatinKeyboard(Context context, int xmlLayoutResId) {
-        this(context, xmlLayoutResId, 0);
-    }
-
-    public LatinKeyboard(Context context, int xmlLayoutResId, int mode) {
-        super(context, xmlLayoutResId, mode);
-        final Resources res = context.getResources();
-        mContext = context;
-        mMode = mode;
-        mRes = res;
-        mShiftLockIcon = res.getDrawable(R.drawable.sym_keyboard_shift_locked);
-        mShiftLockPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_shift_locked);
-        setDefaultBounds(mShiftLockPreviewIcon);
-        mSpaceIcon = res.getDrawable(R.drawable.sym_keyboard_space);
-        mSpaceAutoCompletionIndicator = res.getDrawable(R.drawable.sym_keyboard_space_led);
-        mSpacePreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_space);
-        mMicIcon = res.getDrawable(R.drawable.sym_keyboard_mic);
-        mMicPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_mic);
-        setDefaultBounds(mMicPreviewIcon);
-        mButtonArrowLeftIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_left);
-        mButtonArrowRightIcon = res.getDrawable(R.drawable.sym_keyboard_language_arrows_right);
-        m123MicIcon = res.getDrawable(R.drawable.sym_keyboard_123_mic);
-        m123MicPreviewIcon = res.getDrawable(R.drawable.sym_keyboard_feedback_123_mic);
-        mHintIcon = res.getDrawable(R.drawable.hint_popup);
-        setDefaultBounds(m123MicPreviewIcon);
-        sSpacebarVerticalCorrection = res.getDimensionPixelOffset(
-                R.dimen.spacebar_vertical_correction);
-        mIsAlphaKeyboard = xmlLayoutResId == R.xml.kbd_qwerty
-                || xmlLayoutResId == R.xml.kbd_qwerty_black;
-        mSpaceKeyIndex = indexOf(LatinIME.KEYCODE_SPACE);
-        initializeNumberHintResources(context);
-        // TODO remove this initialization after cleanup
-        mVerticalGap = super.getVerticalGap();
-    }
-
-    private void initializeNumberHintResources(Context context) {
-        final Resources res = context.getResources();
-        mNumberHintIcons[0] = res.getDrawable(R.drawable.keyboard_hint_0);
-        mNumberHintIcons[1] = res.getDrawable(R.drawable.keyboard_hint_1);
-        mNumberHintIcons[2] = res.getDrawable(R.drawable.keyboard_hint_2);
-        mNumberHintIcons[3] = res.getDrawable(R.drawable.keyboard_hint_3);
-        mNumberHintIcons[4] = res.getDrawable(R.drawable.keyboard_hint_4);
-        mNumberHintIcons[5] = res.getDrawable(R.drawable.keyboard_hint_5);
-        mNumberHintIcons[6] = res.getDrawable(R.drawable.keyboard_hint_6);
-        mNumberHintIcons[7] = res.getDrawable(R.drawable.keyboard_hint_7);
-        mNumberHintIcons[8] = res.getDrawable(R.drawable.keyboard_hint_8);
-        mNumberHintIcons[9] = res.getDrawable(R.drawable.keyboard_hint_9);
-    }
-
-    @Override
-    protected Key createKeyFromXml(Resources res, Row parent, int x, int y, 
-            XmlResourceParser parser) {
-        Key key = new LatinKey(res, parent, x, y, parser);
-        switch (key.codes[0]) {
-        case LatinIME.KEYCODE_ENTER:
-            mEnterKey = key;
-            break;
-        case LatinKeyboardView.KEYCODE_F1:
-            mF1Key = key;
-            break;
-        case LatinIME.KEYCODE_SPACE:
-            mSpaceKey = key;
-            break;
-        case KEYCODE_MODE_CHANGE:
-            m123Key = key;
-            m123Label = key.label;
-            break;
-        }
-
-        // For number hints on the upper-right corner of key
-        if (mNumberHintKeys == null) {
-            // NOTE: This protected method is being called from the base class constructor before
-            // mNumberHintKeys gets initialized.
-            mNumberHintKeys = new Key[NUMBER_HINT_COUNT];
-        }
-        int hintNumber = -1;
-        if (LatinKeyboardBaseView.isNumberAtLeftmostPopupChar(key)) {
-            hintNumber = key.popupCharacters.charAt(0) - '0';
-        } else if (LatinKeyboardBaseView.isNumberAtRightmostPopupChar(key)) {
-            hintNumber = key.popupCharacters.charAt(key.popupCharacters.length() - 1) - '0';
-        }
-        if (hintNumber >= 0 && hintNumber <= 9) {
-            mNumberHintKeys[hintNumber] = key;
-        }
-
-        return key;
-    }
-
-    void setImeOptions(Resources res, int mode, int options) {
-        mMode = mode;
-        // TODO should clean up this method
-        if (mEnterKey != null) {
-            // Reset some of the rarely used attributes.
-            mEnterKey.popupCharacters = null;
-            mEnterKey.popupResId = 0;
-            mEnterKey.text = null;
-            switch (options&(EditorInfo.IME_MASK_ACTION|EditorInfo.IME_FLAG_NO_ENTER_ACTION)) {
-                case EditorInfo.IME_ACTION_GO:
-                    mEnterKey.iconPreview = null;
-                    mEnterKey.icon = null;
-                    mEnterKey.label = res.getText(R.string.label_go_key);
-                    break;
-                case EditorInfo.IME_ACTION_NEXT:
-                    mEnterKey.iconPreview = null;
-                    mEnterKey.icon = null;
-                    mEnterKey.label = res.getText(R.string.label_next_key);
-                    break;
-                case EditorInfo.IME_ACTION_DONE:
-                    mEnterKey.iconPreview = null;
-                    mEnterKey.icon = null;
-                    mEnterKey.label = res.getText(R.string.label_done_key);
-                    break;
-                case EditorInfo.IME_ACTION_SEARCH:
-                    mEnterKey.iconPreview = res.getDrawable(
-                            R.drawable.sym_keyboard_feedback_search);
-                    mEnterKey.icon = res.getDrawable(mIsBlackSym ?
-                            R.drawable.sym_bkeyboard_search : R.drawable.sym_keyboard_search);
-                    mEnterKey.label = null;
-                    break;
-                case EditorInfo.IME_ACTION_SEND:
-                    mEnterKey.iconPreview = null;
-                    mEnterKey.icon = null;
-                    mEnterKey.label = res.getText(R.string.label_send_key);
-                    break;
-                default:
-                    if (mode == KeyboardSwitcher.MODE_IM) {
-                        mEnterKey.icon = mHintIcon;
-                        mEnterKey.iconPreview = null;
-                        mEnterKey.label = ":-)";
-                        mEnterKey.text = ":-) ";
-                        mEnterKey.popupResId = R.xml.popup_smileys;
-                    } else {
-                        mEnterKey.iconPreview = res.getDrawable(
-                                R.drawable.sym_keyboard_feedback_return);
-                        mEnterKey.icon = res.getDrawable(mIsBlackSym ?
-                                R.drawable.sym_bkeyboard_return : R.drawable.sym_keyboard_return);
-                        mEnterKey.label = null;
-                    }
-                    break;
-            }
-            // Set the initial size of the preview icon
-            if (mEnterKey.iconPreview != null) {
-                setDefaultBounds(mEnterKey.iconPreview);
-            }
-        }
-    }
-    
-    void enableShiftLock() {
-        int index = getShiftKeyIndex();
-        if (index >= 0) {
-            mShiftKey = getKeys().get(index);
-            if (mShiftKey instanceof LatinKey) {
-                ((LatinKey)mShiftKey).enableShiftLock();
-            }
-            mOldShiftIcon = mShiftKey.icon;
-        }
-    }
-
-    void setShiftLocked(boolean shiftLocked) {
-        if (mShiftKey != null) {
-            if (shiftLocked) {
-                mShiftKey.on = true;
-                mShiftKey.icon = mShiftLockIcon;
-                mShiftState = SHIFT_LOCKED;
-            } else {
-                mShiftKey.on = false;
-                mShiftKey.icon = mShiftLockIcon;
-                mShiftState = SHIFT_ON;
-            }
-        }
-    }
-
-    boolean isShiftLocked() {
-        return mShiftState == SHIFT_LOCKED;
-    }
-    
-    @Override
-    public boolean setShifted(boolean shiftState) {
-        boolean shiftChanged = false;
-        if (mShiftKey != null) {
-            if (shiftState == false) {
-                shiftChanged = mShiftState != SHIFT_OFF;
-                mShiftState = SHIFT_OFF;
-                mShiftKey.on = false;
-                mShiftKey.icon = mOldShiftIcon;
-            } else {
-                if (mShiftState == SHIFT_OFF) {
-                    shiftChanged = mShiftState == SHIFT_OFF;
-                    mShiftState = SHIFT_ON;
-                    mShiftKey.icon = mShiftLockIcon;
-                }
-            }
-        } else {
-            return super.setShifted(shiftState);
-        }
-        return shiftChanged;
-    }
-
-    @Override
-    public boolean isShifted() {
-        if (mShiftKey != null) {
-            return mShiftState != SHIFT_OFF;
-        } else {
-            return super.isShifted();
-        }
-    }
-
-    /* package */ boolean isAlphaKeyboard() {
-        return mIsAlphaKeyboard;
-    }
-
-    public void setColorOfSymbolIcons(boolean isAutoCompletion, boolean isBlack) {
-        mIsBlackSym = isBlack;
-        if (isBlack) {
-            mShiftLockIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_shift_locked);
-            mSpaceIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_space);
-            mMicIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_mic);
-            m123MicIcon = mRes.getDrawable(R.drawable.sym_bkeyboard_123_mic);
-        } else {
-            mShiftLockIcon = mRes.getDrawable(R.drawable.sym_keyboard_shift_locked);
-            mSpaceIcon = mRes.getDrawable(R.drawable.sym_keyboard_space);
-            mMicIcon = mRes.getDrawable(R.drawable.sym_keyboard_mic);
-            m123MicIcon = mRes.getDrawable(R.drawable.sym_keyboard_123_mic);
-        }
-        updateDynamicKeys();
-        if (mSpaceKey != null) {
-            updateSpaceBarForLocale(isAutoCompletion, isBlack);
-        }
-        updateNumberHintKeys();
-    }
-
-    private void setDefaultBounds(Drawable drawable) {
-        drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
-    }
-
-    public void setVoiceMode(boolean hasVoiceButton, boolean hasVoice) {
-        mHasVoiceButton = hasVoiceButton;
-        mVoiceEnabled = hasVoice;
-        updateDynamicKeys();
-    }
-
-    private void updateDynamicKeys() {
-        update123Key();
-        updateF1Key();
-    }
-
-    private void update123Key() {
-        // Update KEYCODE_MODE_CHANGE key only on alphabet mode, not on symbol mode.
-        if (m123Key != null && mIsAlphaKeyboard) {
-            if (mVoiceEnabled && !mHasVoiceButton) {
-                m123Key.icon = m123MicIcon;
-                m123Key.iconPreview = m123MicPreviewIcon;
-                m123Key.label = null;
-            } else {
-                m123Key.icon = null;
-                m123Key.iconPreview = null;
-                m123Key.label = m123Label;
-            }
-        }
-    }
-
-    private void updateF1Key() {
-        // Update KEYCODE_F1 key. Please note that some keyboard layouts have no F1 key.
-        if (mF1Key == null)
-            return;
-
-        if (mIsAlphaKeyboard) {
-            if (mMode == KeyboardSwitcher.MODE_URL) {
-                setNonMicF1Key(mF1Key, "/", R.xml.popup_slash);
-            } else if (mMode == KeyboardSwitcher.MODE_EMAIL) {
-                setNonMicF1Key(mF1Key, "@", R.xml.popup_at);
-            } else {
-                if (mVoiceEnabled && mHasVoiceButton) {
-                    setMicF1Key(mF1Key);
-                } else {
-                    setNonMicF1Key(mF1Key, ",", R.xml.popup_comma);
-                }
-            }
-        } else {  // Symbols keyboard
-            if (mVoiceEnabled && mHasVoiceButton) {
-                setMicF1Key(mF1Key);
-            } else {
-                setNonMicF1Key(mF1Key, ",", R.xml.popup_comma);
-            }
-        }
-    }
-
-    private void setMicF1Key(Key key) {
-        // HACK: draw mMicIcon and mHintIcon at the same time
-        final Drawable micWithSettingsHintDrawable = new BitmapDrawable(mRes,
-                drawSynthesizedSettingsHintImage(key.width, key.height, mMicIcon, mHintIcon));
-
-        key.label = null;
-        key.codes = new int[] { LatinKeyboardView.KEYCODE_VOICE };
-        key.popupResId = R.xml.popup_mic;
-        key.icon = micWithSettingsHintDrawable;
-        key.iconPreview = mMicPreviewIcon;
-    }
-
-    private void setNonMicF1Key(Key key, String label, int popupResId) {
-        key.label = label;
-        key.codes = new int[] { label.charAt(0) };
-        key.popupResId = popupResId;
-        key.icon = mHintIcon;
-        key.iconPreview = null;
-    }
-
-    public boolean isF1Key(Key key) {
-        return key == mF1Key;
-    }
-
-    public static boolean hasPuncOrSmileysPopup(Key key) {
-        return key.popupResId == R.xml.popup_punctuation || key.popupResId == R.xml.popup_smileys;
-    }
-
-    /**
-     * @return a key which should be invalidated.
-     */
-    public Key onAutoCompletionStateChanged(boolean isAutoCompletion) {
-        updateSpaceBarForLocale(isAutoCompletion, mIsBlackSym);
-        return mSpaceKey;
-    }
-
-    private void updateNumberHintKeys() {
-        for (int i = 0; i < mNumberHintKeys.length; ++i) {
-            if (mNumberHintKeys[i] != null) {
-                mNumberHintKeys[i].icon = mNumberHintIcons[i];
-            }
-        }
-    }
-
-    public boolean isLanguageSwitchEnabled() {
-        return mLocale != null;
-    }
-
-    private void updateSpaceBarForLocale(boolean isAutoCompletion, boolean isBlack) {
-        // If application locales are explicitly selected.
-        if (mLocale != null) {
-            mSpaceKey.icon = new BitmapDrawable(mRes,
-                    drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCompletion, isBlack));
-        } else {
-            // sym_keyboard_space_led can be shared with Black and White symbol themes.
-            if (isAutoCompletion) {
-                mSpaceKey.icon = new BitmapDrawable(mRes,
-                        drawSpaceBar(OPACITY_FULLY_OPAQUE, isAutoCompletion, isBlack));
-            } else {
-                mSpaceKey.icon = isBlack ? mRes.getDrawable(R.drawable.sym_bkeyboard_space)
-                        : mRes.getDrawable(R.drawable.sym_keyboard_space);
-            }
-        }
-    }
-
-    // Compute width of text with specified text size using paint.
-    private static int getTextWidth(Paint paint, String text, float textSize, Rect bounds) {
-        paint.setTextSize(textSize);
-        paint.getTextBounds(text, 0, text.length(), bounds);
-        return bounds.width();
-    }
-
-    // Overlay two images: mainIcon and hintIcon.
-    private Bitmap drawSynthesizedSettingsHintImage(
-            int width, int height, Drawable mainIcon, Drawable hintIcon) {
-        if (mainIcon == null || hintIcon == null)
-            return null;
-        Rect hintIconPadding = new Rect(0, 0, 0, 0);
-        hintIcon.getPadding(hintIconPadding);
-        final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-        final Canvas canvas = new Canvas(buffer);
-        canvas.drawColor(mRes.getColor(R.color.latinkeyboard_transparent), PorterDuff.Mode.CLEAR);
-
-        // Draw main icon at the center of the key visual
-        // Assuming the hintIcon shares the same padding with the key's background drawable
-        final int drawableX = (width + hintIconPadding.left - hintIconPadding.right
-                - mainIcon.getIntrinsicWidth()) / 2;
-        final int drawableY = (height + hintIconPadding.top - hintIconPadding.bottom
-                - mainIcon.getIntrinsicHeight()) / 2;
-        setDefaultBounds(mainIcon);
-        canvas.translate(drawableX, drawableY);
-        mainIcon.draw(canvas);
-        canvas.translate(-drawableX, -drawableY);
-
-        // Draw hint icon fully in the key
-        hintIcon.setBounds(0, 0, width, height);
-        hintIcon.draw(canvas);
-        return buffer;
-    }
-
-    // Layout local language name and left and right arrow on space bar.
-    private static String layoutSpaceBar(Paint paint, Locale locale, Drawable lArrow,
-            Drawable rArrow, int width, int height, float origTextSize,
-            boolean allowVariableTextSize) {
-        final float arrowWidth = lArrow.getIntrinsicWidth();
-        final float arrowHeight = lArrow.getIntrinsicHeight();
-        final float maxTextWidth = width - (arrowWidth + arrowWidth);
-        final Rect bounds = new Rect();
-
-        // Estimate appropriate language name text size to fit in maxTextWidth.
-        String language = LanguageSwitcher.toTitleCase(locale.getDisplayLanguage(locale));
-        int textWidth = getTextWidth(paint, language, origTextSize, bounds);
-        // Assuming text width and text size are proportional to each other.
-        float textSize = origTextSize * Math.min(maxTextWidth / textWidth, 1.0f);
-
-        final boolean useShortName;
-        if (allowVariableTextSize) {
-            textWidth = getTextWidth(paint, language, textSize, bounds);
-            // If text size goes too small or text does not fit, use short name
-            useShortName = textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME
-                    || textWidth > maxTextWidth;
-        } else {
-            useShortName = textWidth > maxTextWidth;
-            textSize = origTextSize;
-        }
-        if (useShortName) {
-            language = LanguageSwitcher.toTitleCase(locale.getLanguage());
-            textWidth = getTextWidth(paint, language, origTextSize, bounds);
-            textSize = origTextSize * Math.min(maxTextWidth / textWidth, 1.0f);
-        }
-        paint.setTextSize(textSize);
-
-        // Place left and right arrow just before and after language text.
-        final float baseline = height * SPACEBAR_LANGUAGE_BASELINE;
-        final int top = (int)(baseline - arrowHeight);
-        final float remains = (width - textWidth) / 2;
-        lArrow.setBounds((int)(remains - arrowWidth), top, (int)remains, (int)baseline);
-        rArrow.setBounds((int)(remains + textWidth), top, (int)(remains + textWidth + arrowWidth),
-                (int)baseline);
-
-        return language;
-    }
-
-    private Bitmap drawSpaceBar(int opacity, boolean isAutoCompletion, boolean isBlack) {
-        final int width = mSpaceKey.width;
-        final int height = mSpaceIcon.getIntrinsicHeight();
-        final Bitmap buffer = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-        final Canvas canvas = new Canvas(buffer);
-        canvas.drawColor(mRes.getColor(R.color.latinkeyboard_transparent), PorterDuff.Mode.CLEAR);
-
-        // If application locales are explicitly selected.
-        if (mLocale != null) {
-            final Paint paint = new Paint();
-            paint.setAlpha(opacity);
-            paint.setAntiAlias(true);
-            paint.setTextAlign(Align.CENTER);
-
-            final boolean allowVariableTextSize = true;
-            final String language = layoutSpaceBar(paint, mLanguageSwitcher.getInputLocale(),
-                    mButtonArrowLeftIcon, mButtonArrowRightIcon, width, height,
-                    getTextSizeFromTheme(android.R.style.TextAppearance_Small, 14),
-                    allowVariableTextSize);
-
-            // Draw language text with shadow
-            final int shadowColor = mRes.getColor(isBlack
-                    ? R.color.latinkeyboard_bar_language_shadow_black
-                    : R.color.latinkeyboard_bar_language_shadow_white);
-            final float baseline = height * SPACEBAR_LANGUAGE_BASELINE;
-            final float descent = paint.descent();
-            paint.setColor(shadowColor);
-            canvas.drawText(language, width / 2, baseline - descent - 1, paint);
-            paint.setColor(mRes.getColor(R.color.latinkeyboard_bar_language_text));
-            canvas.drawText(language, width / 2, baseline - descent, paint);
-
-            // Put arrows that are already layed out on either side of the text
-            if (mLanguageSwitcher.getLocaleCount() > 1) {
-                mButtonArrowLeftIcon.draw(canvas);
-                mButtonArrowRightIcon.draw(canvas);
-            }
-        }
-
-        // Draw the spacebar icon at the bottom
-        if (isAutoCompletion) {
-            final int iconWidth = width * SPACE_LED_LENGTH_PERCENT / 100;
-            final int iconHeight = mSpaceAutoCompletionIndicator.getIntrinsicHeight();
-            int x = (width - iconWidth) / 2;
-            int y = height - iconHeight;
-            mSpaceAutoCompletionIndicator.setBounds(x, y, x + iconWidth, y + iconHeight);
-            mSpaceAutoCompletionIndicator.draw(canvas);
-        } else {
-            final int iconWidth = mSpaceIcon.getIntrinsicWidth();
-            final int iconHeight = mSpaceIcon.getIntrinsicHeight();
-            int x = (width - iconWidth) / 2;
-            int y = height - iconHeight;
-            mSpaceIcon.setBounds(x, y, x + iconWidth, y + iconHeight);
-            mSpaceIcon.draw(canvas);
-        }
-        return buffer;
-    }
-
-    private void updateLocaleDrag(int diff) {
-        if (mSlidingLocaleIcon == null) {
-            final int width = Math.max(mSpaceKey.width,
-                    (int)(getMinWidth() * SPACEBAR_POPUP_MIN_RATIO));
-            final int height = mSpacePreviewIcon.getIntrinsicHeight();
-            mSlidingLocaleIcon = new SlidingLocaleDrawable(mSpacePreviewIcon, width, height);
-            mSlidingLocaleIcon.setBounds(0, 0, width, height);
-            mSpaceKey.iconPreview = mSlidingLocaleIcon;
-        }
-        mSlidingLocaleIcon.setDiff(diff);
-        if (Math.abs(diff) == Integer.MAX_VALUE) {
-            mSpaceKey.iconPreview = mSpacePreviewIcon;
-        } else {
-            mSpaceKey.iconPreview = mSlidingLocaleIcon;
-        }
-        mSpaceKey.iconPreview.invalidateSelf();
-    }
-
-    public int getLanguageChangeDirection() {
-        if (mSpaceKey == null || mLanguageSwitcher.getLocaleCount() < 2
-                || Math.abs(mSpaceDragLastDiff) < mSpaceKey.width * SPACEBAR_DRAG_THRESHOLD ) {
-            return 0; // No change
-        }
-        return mSpaceDragLastDiff > 0 ? 1 : -1;
-    }
-
-    public void setLanguageSwitcher(LanguageSwitcher switcher, boolean isAutoCompletion,
-            boolean isBlackSym) {
-        mLanguageSwitcher = switcher;
-        Locale locale = mLanguageSwitcher.getLocaleCount() > 0
-                ? mLanguageSwitcher.getInputLocale()
-                : null;
-        // If the language count is 1 and is the same as the system language, don't show it.
-        if (locale != null
-                && mLanguageSwitcher.getLocaleCount() == 1
-                && mLanguageSwitcher.getSystemLocale().getLanguage()
-                   .equalsIgnoreCase(locale.getLanguage())) {
-            locale = null;
-        }
-        mLocale = locale;
-        setColorOfSymbolIcons(isAutoCompletion, isBlackSym);
-    }
-
-    boolean isCurrentlyInSpace() {
-        return mCurrentlyInSpace;
-    }
-
-    void setPreferredLetters(int[] frequencies) {
-        mPrefLetterFrequencies = frequencies;
-        mPrefLetter = 0;
-    }
-
-    void keyReleased() {
-        mCurrentlyInSpace = false;
-        mSpaceDragLastDiff = 0;
-        mPrefLetter = 0;
-        mPrefLetterX = 0;
-        mPrefLetterY = 0;
-        mPrefDistance = Integer.MAX_VALUE;
-        if (mSpaceKey != null) {
-            updateLocaleDrag(Integer.MAX_VALUE);
-        }
-    }
-
-    /**
-     * Does the magic of locking the touch gesture into the spacebar when
-     * switching input languages.
-     */
-    boolean isInside(LatinKey key, int x, int y) {
-        final int code = key.codes[0];
-        if (code == KEYCODE_SHIFT ||
-                code == KEYCODE_DELETE) {
-            y -= key.height / 10;
-            if (code == KEYCODE_SHIFT) x += key.width / 6;
-            if (code == KEYCODE_DELETE) x -= key.width / 6;
-        } else if (code == LatinIME.KEYCODE_SPACE) {
-            y += LatinKeyboard.sSpacebarVerticalCorrection;
-            if (mLanguageSwitcher.getLocaleCount() > 1) {
-                if (mCurrentlyInSpace) {
-                    int diff = x - mSpaceDragStartX;
-                    if (Math.abs(diff - mSpaceDragLastDiff) > 0) {
-                        updateLocaleDrag(diff);
-                    }
-                    mSpaceDragLastDiff = diff;
-                    return true;
-                } else {
-                    boolean insideSpace = key.isInsideSuper(x, y);
-                    if (insideSpace) {
-                        mCurrentlyInSpace = true;
-                        mSpaceDragStartX = x;
-                        updateLocaleDrag(0);
-                    }
-                    return insideSpace;
-                }
-            }
-        } else if (mPrefLetterFrequencies != null) {
-            // New coordinate? Reset
-            if (mPrefLetterX != x || mPrefLetterY != y) {
-                mPrefLetter = 0;
-                mPrefDistance = Integer.MAX_VALUE;
-            }
-            // Handle preferred next letter
-            final int[] pref = mPrefLetterFrequencies;
-            if (mPrefLetter > 0) {
-                if (DEBUG_PREFERRED_LETTER) {
-                    if (mPrefLetter == code && !key.isInsideSuper(x, y)) {
-                        Log.d(TAG, "CORRECTED !!!!!!");
-                    }
-                }
-                return mPrefLetter == code;
-            } else {
-                final boolean inside = key.isInsideSuper(x, y);
-                int[] nearby = getNearestKeys(x, y);
-                List<Key> nearbyKeys = getKeys();
-                if (inside) {
-                    // If it's a preferred letter
-                    if (inPrefList(code, pref)) {
-                        // Check if its frequency is much lower than a nearby key
-                        mPrefLetter = code;
-                        mPrefLetterX = x;
-                        mPrefLetterY = y;
-                        for (int i = 0; i < nearby.length; i++) {
-                            Key k = nearbyKeys.get(nearby[i]);
-                            if (k != key && inPrefList(k.codes[0], pref)) {
-                                final int dist = distanceFrom(k, x, y);
-                                if (dist < (int) (k.width * OVERLAP_PERCENTAGE_LOW_PROB) &&
-                                        (pref[k.codes[0]] > pref[mPrefLetter] * 3))  {
-                                    mPrefLetter = k.codes[0];
-                                    mPrefDistance = dist;
-                                    if (DEBUG_PREFERRED_LETTER) {
-                                        Log.d(TAG, "CORRECTED ALTHOUGH PREFERRED !!!!!!");
-                                    }
-                                    break;
-                                }
-                            }
-                        }
-
-                        return mPrefLetter == code;
-                    }
-                }
-
-                // Get the surrounding keys and intersect with the preferred list
-                // For all in the intersection
-                //   if distance from touch point is within a reasonable distance
-                //       make this the pref letter
-                // If no pref letter
-                //   return inside;
-                // else return thiskey == prefletter;
-
-                for (int i = 0; i < nearby.length; i++) {
-                    Key k = nearbyKeys.get(nearby[i]);
-                    if (inPrefList(k.codes[0], pref)) {
-                        final int dist = distanceFrom(k, x, y);
-                        if (dist < (int) (k.width * OVERLAP_PERCENTAGE_HIGH_PROB)
-                                && dist < mPrefDistance)  {
-                            mPrefLetter = k.codes[0];
-                            mPrefLetterX = x;
-                            mPrefLetterY = y;
-                            mPrefDistance = dist;
-                        }
-                    }
-                }
-                // Didn't find any
-                if (mPrefLetter == 0) {
-                    return inside;
-                } else {
-                    return mPrefLetter == code;
-                }
-            }
-        }
-
-        // Lock into the spacebar
-        if (mCurrentlyInSpace) return false;
-
-        return key.isInsideSuper(x, y);
-    }
-
-    private boolean inPrefList(int code, int[] pref) {
-        if (code < pref.length && code >= 0) return pref[code] > 0;
-        return false;
-    }
-
-    private int distanceFrom(Key k, int x, int y) {
-        if (y > k.y && y < k.y + k.height) {
-            return Math.abs(k.x + k.width / 2 - x);
-        } else {
-            return Integer.MAX_VALUE;
-        }
-    }
-
-    @Override
-    public int[] getNearestKeys(int x, int y) {
-        if (mCurrentlyInSpace) {
-            return new int[] { mSpaceKeyIndex };
-        } else {
-            // Avoid dead pixels at edges of the keyboard
-            return super.getNearestKeys(Math.max(0, Math.min(x, getMinWidth() - 1)),
-                    Math.max(0, Math.min(y, getHeight() - 1)));
-        }
-    }
-
-    private int indexOf(int code) {
-        List<Key> keys = getKeys();
-        int count = keys.size();
-        for (int i = 0; i < count; i++) {
-            if (keys.get(i).codes[0] == code) return i;
-        }
-        return -1;
-    }
-
-    private int getTextSizeFromTheme(int style, int defValue) {
-        TypedArray array = mContext.getTheme().obtainStyledAttributes(
-                style, new int[] { android.R.attr.textSize });
-        int textSize = array.getDimensionPixelSize(array.getResourceId(0, 0), defValue);
-        return textSize;
-    }
-
-    // TODO LatinKey could be static class
-    class LatinKey extends Keyboard.Key {
-
-        // functional normal state (with properties)
-        private final int[] KEY_STATE_FUNCTIONAL_NORMAL = {
-                android.R.attr.state_single
-        };
-
-        // functional pressed state (with properties)
-        private final int[] KEY_STATE_FUNCTIONAL_PRESSED = {
-                android.R.attr.state_single,
-                android.R.attr.state_pressed
-        };
-
-        private boolean mShiftLockEnabled;
-
-        public LatinKey(Resources res, Keyboard.Row parent, int x, int y, 
-                XmlResourceParser parser) {
-            super(res, parent, x, y, parser);
-            if (popupCharacters != null && popupCharacters.length() == 0) {
-                // If there is a keyboard with no keys specified in popupCharacters
-                popupResId = 0;
-            }
-        }
-
-        private void enableShiftLock() {
-            mShiftLockEnabled = true;
-        }
-
-        // sticky is used for shift key.  If a key is not sticky and is modifier,
-        // the key will be treated as functional.
-        private boolean isFunctionalKey() {
-            return !sticky && modifier;
-        }
-
-        @Override
-        public void onReleased(boolean inside) {
-            if (!mShiftLockEnabled) {
-                super.onReleased(inside);
-            } else {
-                pressed = !pressed;
-            }
-        }
-
-        /**
-         * Overriding this method so that we can reduce the target area for certain keys.
-         */
-        @Override
-        public boolean isInside(int x, int y) {
-            // TODO This should be done by parent.isInside(this, x, y)
-            // if Key.parent were protected.
-            boolean result = LatinKeyboard.this.isInside(this, x, y);
-            return result;
-        }
-
-        boolean isInsideSuper(int x, int y) {
-            return super.isInside(x, y);
-        }
-
-        @Override
-        public int[] getCurrentDrawableState() {
-            if (isFunctionalKey()) {
-                if (pressed) {
-                    return KEY_STATE_FUNCTIONAL_PRESSED;
-                } else {
-                    return KEY_STATE_FUNCTIONAL_NORMAL;
-                }
-            }
-            return super.getCurrentDrawableState();
-        }
-
-        @Override
-        public int squaredDistanceFrom(int x, int y) {
-            // We should count vertical gap between rows to calculate the center of this Key.
-            final int verticalGap = LatinKeyboard.this.mVerticalGap;
-            final int xDist = this.x + width / 2 - x;
-            final int yDist = this.y + (height + verticalGap) / 2 - y;
-            return xDist * xDist + yDist * yDist;
-        }
-    }
-
-    /**
-     * Animation to be displayed on the spacebar preview popup when switching 
-     * languages by swiping the spacebar. It draws the current, previous and
-     * next languages and moves them by the delta of touch movement on the spacebar.
-     */
-    class SlidingLocaleDrawable extends Drawable {
-
-        private final int mWidth;
-        private final int mHeight;
-        private final Drawable mBackground;
-        private final TextPaint mTextPaint;
-        private final int mMiddleX;
-        private final Drawable mLeftDrawable;
-        private final Drawable mRightDrawable;
-        private final int mThreshold;
-        private int mDiff;
-        private boolean mHitThreshold;
-        private String mCurrentLanguage;
-        private String mNextLanguage;
-        private String mPrevLanguage;
-
-        public SlidingLocaleDrawable(Drawable background, int width, int height) {
-            mBackground = background;
-            setDefaultBounds(mBackground);
-            mWidth = width;
-            mHeight = height;
-            mTextPaint = new TextPaint();
-            mTextPaint.setTextSize(getTextSizeFromTheme(android.R.style.TextAppearance_Medium, 18));
-            mTextPaint.setColor(R.color.latinkeyboard_transparent);
-            mTextPaint.setTextAlign(Align.CENTER);
-            mTextPaint.setAlpha(OPACITY_FULLY_OPAQUE);
-            mTextPaint.setAntiAlias(true);
-            mMiddleX = (mWidth - mBackground.getIntrinsicWidth()) / 2;
-            mLeftDrawable =
-                    mRes.getDrawable(R.drawable.sym_keyboard_feedback_language_arrows_left);
-            mRightDrawable =
-                    mRes.getDrawable(R.drawable.sym_keyboard_feedback_language_arrows_right);
-            mThreshold = ViewConfiguration.get(mContext).getScaledTouchSlop();
-        }
-
-        private void setDiff(int diff) {
-            if (diff == Integer.MAX_VALUE) {
-                mHitThreshold = false;
-                mCurrentLanguage = null;
-                return;
-            }
-            mDiff = diff;
-            if (mDiff > mWidth) mDiff = mWidth;
-            if (mDiff < -mWidth) mDiff = -mWidth;
-            if (Math.abs(mDiff) > mThreshold) mHitThreshold = true;
-            invalidateSelf();
-        }
-
-        private String getLanguageName(Locale locale) {
-            return LanguageSwitcher.toTitleCase(locale.getDisplayLanguage(locale));
-        }
-
-        @Override
-        public void draw(Canvas canvas) {
-            canvas.save();
-            if (mHitThreshold) {
-                Paint paint = mTextPaint;
-                final int width = mWidth;
-                final int height = mHeight;
-                final int diff = mDiff;
-                final Drawable lArrow = mLeftDrawable;
-                final Drawable rArrow = mRightDrawable;
-                canvas.clipRect(0, 0, width, height);
-                if (mCurrentLanguage == null) {
-                    final LanguageSwitcher languageSwitcher = mLanguageSwitcher;
-                    mCurrentLanguage = getLanguageName(languageSwitcher.getInputLocale());
-                    mNextLanguage = getLanguageName(languageSwitcher.getNextInputLocale());
-                    mPrevLanguage = getLanguageName(languageSwitcher.getPrevInputLocale());
-                }
-                // Draw language text with shadow
-                final float baseline = mHeight * SPACEBAR_LANGUAGE_BASELINE - paint.descent();
-                paint.setColor(mRes.getColor(R.color.latinkeyboard_feedback_language_text));
-                canvas.drawText(mCurrentLanguage, width / 2 + diff, baseline, paint);
-                canvas.drawText(mNextLanguage, diff - width / 2, baseline, paint);
-                canvas.drawText(mPrevLanguage, diff + width + width / 2, baseline, paint);
-
-                setDefaultBounds(lArrow);
-                rArrow.setBounds(width - rArrow.getIntrinsicWidth(), 0, width,
-                        rArrow.getIntrinsicHeight());
-                lArrow.draw(canvas);
-                rArrow.draw(canvas);
-            }
-            if (mBackground != null) {
-                canvas.translate(mMiddleX, 0);
-                mBackground.draw(canvas);
-            }
-            canvas.restore();
-        }
-
-        @Override
-        public int getOpacity() {
-            return PixelFormat.TRANSLUCENT;
-        }
-
-        @Override
-        public void setAlpha(int alpha) {
-            // Ignore
-        }
-
-        @Override
-        public void setColorFilter(ColorFilter cf) {
-            // Ignore
-        }
-
-        @Override
-        public int getIntrinsicWidth() {
-            return mWidth;
-        }
-
-        @Override
-        public int getIntrinsicHeight() {
-            return mHeight;
-        }
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/ModifierKeyState.java b/java/src/com/android/inputmethod/latin/ModifierKeyState.java
deleted file mode 100644
index 097e87a..0000000
--- a/java/src/com/android/inputmethod/latin/ModifierKeyState.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc.
- *
- * 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;
-
-class ModifierKeyState {
-    private static final int RELEASING = 0;
-    private static final int PRESSING = 1;
-    private static final int MOMENTARY = 2;
-
-    private int mState = RELEASING;
-
-    public void onPress() {
-        mState = PRESSING;
-    }
-
-    public void onRelease() {
-        mState = RELEASING;
-    }
-
-    public void onOtherKeyPressed() {
-        if (mState == PRESSING)
-            mState = MOMENTARY;
-    }
-
-    public boolean isMomentary() {
-        return mState == MOMENTARY;
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java b/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java
deleted file mode 100644
index 325ce67..0000000
--- a/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc.
- *
- * 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.inputmethodservice.Keyboard.Key;
-
-import java.util.Arrays;
-
-class ProximityKeyDetector extends KeyDetector {
-    private static final int MAX_NEARBY_KEYS = 12;
-
-    // working area
-    private int[] mDistances = new int[MAX_NEARBY_KEYS];
-
-    @Override
-    protected int getMaxNearbyKeys() {
-        return MAX_NEARBY_KEYS;
-    }
-
-    @Override
-    public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) {
-        final Key[] keys = getKeys();
-        final int touchX = getTouchX(x);
-        final int touchY = getTouchY(y);
-        int primaryIndex = LatinKeyboardBaseView.NOT_A_KEY;
-        int closestKey = LatinKeyboardBaseView.NOT_A_KEY;
-        int closestKeyDist = mProximityThresholdSquare + 1;
-        int[] distances = mDistances;
-        Arrays.fill(distances, Integer.MAX_VALUE);
-        int [] nearestKeyIndices = mKeyboard.getNearestKeys(touchX, touchY);
-        final int keyCount = nearestKeyIndices.length;
-        for (int i = 0; i < keyCount; i++) {
-            final Key key = keys[nearestKeyIndices[i]];
-            int dist = 0;
-            boolean isInside = key.isInside(touchX, touchY);
-            if (isInside) {
-                primaryIndex = nearestKeyIndices[i];
-            }
-
-            if (((mProximityCorrectOn
-                    && (dist = key.squaredDistanceFrom(touchX, touchY)) < mProximityThresholdSquare)
-                    || isInside)
-                    && key.codes[0] > 32) {
-                // Find insertion point
-                final int nCodes = key.codes.length;
-                if (dist < closestKeyDist) {
-                    closestKeyDist = dist;
-                    closestKey = nearestKeyIndices[i];
-                }
-
-                if (allKeys == null) continue;
-
-                for (int j = 0; j < distances.length; j++) {
-                    if (distances[j] > dist) {
-                        // Make space for nCodes codes
-                        System.arraycopy(distances, j, distances, j + nCodes,
-                                distances.length - j - nCodes);
-                        System.arraycopy(allKeys, j, allKeys, j + nCodes,
-                                allKeys.length - j - nCodes);
-                        System.arraycopy(key.codes, 0, allKeys, j, nCodes);
-                        Arrays.fill(distances, j, j + nCodes, dist);
-                        break;
-                    }
-                }
-            }
-        }
-        if (primaryIndex == LatinKeyboardBaseView.NOT_A_KEY) {
-            primaryIndex = closestKey;
-        }
-        return primaryIndex;
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
new file mode 100644
index 0000000..3ee4eb8
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -0,0 +1,478 @@
+/*
+ * 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.
+ */
+
+package com.android.inputmethod.latin;
+
+import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.voice.SettingsUtil;
+import com.android.inputmethod.voice.VoiceIMEConnector;
+import com.android.inputmethod.voice.VoiceInput;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Locale;
+
+public class SubtypeSwitcher {
+    // This flag indicates if we support language switching by swipe on space bar.
+    // We may or may not draw the current language on space bar regardless of this flag.
+    public static final boolean USE_SPACEBAR_LANGUAGE_SWITCHER = false;
+    private static final boolean DBG = false;
+    private static final String TAG = "SubtypeSwitcher";
+
+    private static final char LOCALE_SEPARATER = '_';
+    private static final String KEYBOARD_MODE = "keyboard";
+    private static final String VOICE_MODE = "voice";
+    private final TextUtils.SimpleStringSplitter mLocaleSplitter =
+            new TextUtils.SimpleStringSplitter(LOCALE_SEPARATER);
+
+    private static final SubtypeSwitcher sInstance = new SubtypeSwitcher();
+    private /* final */ LatinIME mService;
+    private /* final */ SharedPreferences mPrefs;
+    private /* final */ InputMethodManager mImm;
+    private /* final */ Resources mResources;
+    private final ArrayList<InputMethodSubtype> mEnabledKeyboardSubtypesOfCurrentInputMethod =
+            new ArrayList<InputMethodSubtype>();
+    private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>();
+
+    /*-----------------------------------------------------------*/
+    // Variants which should be changed only by reload functions.
+    private Locale mSystemLocale;
+    private Locale mInputLocale;
+    private String mInputLocaleStr;
+    private String mMode;
+    private List<InputMethodSubtype> mAllEnabledSubtypesOfCurrentInputMethod;
+    private VoiceInput mVoiceInput;
+    private boolean mNeedsToDisplayLanguage;
+    private boolean mIsSystemLanguageSameAsInputLanguage;
+    /*-----------------------------------------------------------*/
+
+    public static SubtypeSwitcher getInstance() {
+        return sInstance;
+    }
+
+    public static void init(LatinIME service, SharedPreferences prefs) {
+        sInstance.mPrefs = prefs;
+        sInstance.resetParams(service);
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            sInstance.initLanguageSwitcher(service);
+        }
+
+        sInstance.updateAllParameters();
+    }
+
+    private SubtypeSwitcher() {
+    }
+
+    private void resetParams(LatinIME service) {
+        mService = service;
+        mResources = service.getResources();
+        mImm = (InputMethodManager) service.getSystemService(Context.INPUT_METHOD_SERVICE);
+        mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
+        mEnabledLanguagesOfCurrentInputMethod.clear();
+        mSystemLocale = null;
+        mInputLocale = null;
+        mInputLocaleStr = null;
+        mMode = null;
+        mAllEnabledSubtypesOfCurrentInputMethod = null;
+        // TODO: Voice input should be created here
+        mVoiceInput = null;
+    }
+
+    // Update all parameters stored in SubtypeSwitcher.
+    // Only configuration changed event is allowed to call this because this is heavy.
+    private void updateAllParameters() {
+        mSystemLocale = mResources.getConfiguration().locale;
+        updateSubtype(mImm.getCurrentInputMethodSubtype());
+        updateParametersOnStartInputView();
+    }
+
+    // Update parameters which are changed outside LatinIME. This parameters affect UI so they
+    // should be updated every time onStartInputview.
+    public void updateParametersOnStartInputView() {
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            updateForSpaceBarLanguageSwitch();
+        } else {
+            updateEnabledSubtypes();
+        }
+    }
+
+    // Reload enabledSubtypes from the framework.
+    private void updateEnabledSubtypes() {
+        boolean foundCurrentSubtypeBecameDisabled = true;
+        mAllEnabledSubtypesOfCurrentInputMethod = mImm.getEnabledInputMethodSubtypeList(null);
+        mEnabledLanguagesOfCurrentInputMethod.clear();
+        mEnabledKeyboardSubtypesOfCurrentInputMethod.clear();
+        for (InputMethodSubtype ims: mAllEnabledSubtypesOfCurrentInputMethod) {
+            final String locale = ims.getLocale();
+            final String mode = ims.getMode();
+            mLocaleSplitter.setString(locale);
+            if (mLocaleSplitter.hasNext()) {
+                mEnabledLanguagesOfCurrentInputMethod.add(mLocaleSplitter.next());
+            }
+            if (locale.equals(mInputLocaleStr) && mode.equals(mMode)) {
+                foundCurrentSubtypeBecameDisabled = false;
+            }
+            if (KEYBOARD_MODE.equals(ims.getMode())) {
+                mEnabledKeyboardSubtypesOfCurrentInputMethod.add(ims);
+            }
+        }
+        mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1
+                && mIsSystemLanguageSameAsInputLanguage);
+        if (foundCurrentSubtypeBecameDisabled) {
+            if (DBG) {
+                Log.w(TAG, "Last subtype was disabled. Update to the current one.");
+            }
+            updateSubtype(mImm.getCurrentInputMethodSubtype());
+        }
+    }
+
+    // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function.
+    public void updateSubtype(InputMethodSubtype newSubtype) {
+        final String newLocale;
+        final String newMode;
+        if (newSubtype == null) {
+            // Normally, newSubtype shouldn't be null. But just in case newSubtype was null,
+            // fallback to the default locale and mode.
+            Log.w(TAG, "Couldn't get the current subtype.");
+            newLocale = "en_US";
+            newMode =KEYBOARD_MODE;
+        } else {
+            newLocale = newSubtype.getLocale();
+            newMode = newSubtype.getMode();
+        }
+        if (DBG) {
+            Log.w(TAG, "Update subtype to:" + newLocale + "," + newMode
+                    + ", from: " + mInputLocaleStr + ", " + mMode);
+        }
+        boolean languageChanged = false;
+        if (!newLocale.equals(mInputLocaleStr)) {
+            if (mInputLocaleStr != null) {
+                languageChanged = true;
+            }
+            updateInputLocale(newLocale);
+        }
+        boolean modeChanged = false;
+        String oldMode = mMode;
+        if (!newMode.equals(mMode)) {
+            if (mMode != null) {
+                modeChanged = true;
+            }
+            mMode = newMode;
+        }
+        if (isKeyboardMode()) {
+            if (modeChanged) {
+                if (VOICE_MODE.equals(oldMode) && mVoiceInput != null) {
+                    mVoiceInput.cancel();
+                }
+            }
+            if (languageChanged) {
+                mService.onKeyboardLanguageChanged();
+            }
+        } else if (isVoiceMode()) {
+            // If needsToShowWarningDialog is true, voice input need to show warning before
+            // show recognition view.
+            if (languageChanged || modeChanged
+                    || VoiceIMEConnector.getInstance().needsToShowWarningDialog()) {
+                if (mVoiceInput != null) {
+                    // TODO: Call proper function to trigger VoiceIME
+                    mService.onKey(Keyboard.CODE_VOICE, null, 0, 0);
+                }
+            }
+        } else {
+            Log.w(TAG, "Unknown subtype mode: " + mMode);
+        }
+    }
+
+    // Update the current input locale from Locale string.
+    private void updateInputLocale(String inputLocaleStr) {
+        // example: inputLocaleStr = "en_US" "en" ""
+        // "en_US" --> language: en  & country: US
+        // "en" --> language: en
+        // "" --> the system locale
+        mLocaleSplitter.setString(inputLocaleStr);
+        if (mLocaleSplitter.hasNext()) {
+            String language = mLocaleSplitter.next();
+            if (mLocaleSplitter.hasNext()) {
+                mInputLocale = new Locale(language, mLocaleSplitter.next());
+            } else {
+                mInputLocale = new Locale(language);
+            }
+            mInputLocaleStr = inputLocaleStr;
+        } else {
+            mInputLocale = mSystemLocale;
+            String country = mSystemLocale.getCountry();
+            mInputLocaleStr = mSystemLocale.getLanguage()
+                    + (TextUtils.isEmpty(country) ? "" : "_" + mSystemLocale.getLanguage());
+        }
+        mIsSystemLanguageSameAsInputLanguage = getSystemLocale().getLanguage().equalsIgnoreCase(
+                getInputLocale().getLanguage());
+        mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1
+                && mIsSystemLanguageSameAsInputLanguage);
+    }
+
+    //////////////////////////////////
+    // Language Switching functions //
+    //////////////////////////////////
+
+    public int getEnabledKeyboardLocaleCount() {
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            return mLanguageSwitcher.getLocaleCount();
+        } else {
+            return mEnabledKeyboardSubtypesOfCurrentInputMethod.size();
+        }
+    }
+
+    public boolean needsToDisplayLanguage() {
+        return mNeedsToDisplayLanguage;
+    }
+
+    public Locale getInputLocale() {
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            return mLanguageSwitcher.getInputLocale();
+        } else {
+            return mInputLocale;
+        }
+    }
+
+    public String getInputLocaleStr() {
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            String inputLanguage = null;
+            inputLanguage = mLanguageSwitcher.getInputLanguage();
+            // Should return system locale if there is no Language available.
+            if (inputLanguage == null) {
+                inputLanguage = getSystemLocale().getLanguage();
+            }
+            return inputLanguage;
+        } else {
+            return mInputLocaleStr;
+        }
+    }
+
+    public String[] getEnabledLanguages() {
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            return mLanguageSwitcher.getEnabledLanguages();
+        } else {
+            return mEnabledLanguagesOfCurrentInputMethod.toArray(
+                    new String[mEnabledLanguagesOfCurrentInputMethod.size()]);
+        }
+    }
+
+    public Locale getSystemLocale() {
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            return mLanguageSwitcher.getSystemLocale();
+        } else {
+            return mSystemLocale;
+        }
+    }
+
+    public boolean isSystemLanguageSameAsInputLanguage() {
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            return getSystemLocale().getLanguage().equalsIgnoreCase(
+                    getInputLocaleStr().substring(0, 2));
+        } else {
+            return mIsSystemLanguageSameAsInputLanguage;
+        }
+    }
+
+    public void onConfigurationChanged(Configuration conf) {
+        final Locale systemLocale = conf.locale;
+        // If system configuration was changed, update all parameters.
+        if (!TextUtils.equals(systemLocale.toString(), mSystemLocale.toString())) {
+            if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+                // If the system locale changes and is different from the saved
+                // locale (mSystemLocale), then reload the input locale list from the
+                // latin ime settings (shared prefs) and reset the input locale
+                // to the first one.
+                mLanguageSwitcher.loadLocales(mPrefs);
+                mLanguageSwitcher.setSystemLocale(systemLocale);
+            } else {
+                updateAllParameters();
+            }
+        }
+    }
+
+    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            if (LatinIME.PREF_SELECTED_LANGUAGES.equals(key)) {
+                mLanguageSwitcher.loadLocales(sharedPreferences);
+            }
+        }
+    }
+
+    /**
+     * Change system locale for this application
+     * @param newLocale
+     * @return oldLocale
+     */
+    public Locale changeSystemLocale(Locale newLocale) {
+        Configuration conf = mResources.getConfiguration();
+        Locale oldLocale = conf.locale;
+        conf.locale = newLocale;
+        mResources.updateConfiguration(conf, mResources.getDisplayMetrics());
+        return oldLocale;
+    }
+
+    public boolean isKeyboardMode() {
+        return KEYBOARD_MODE.equals(mMode);
+    }
+
+
+    ///////////////////////////
+    // Voice Input functions //
+    ///////////////////////////
+
+    public boolean setVoiceInput(VoiceInput vi) {
+        if (mVoiceInput == null && vi != null) {
+            mVoiceInput = vi;
+            if (isVoiceMode()) {
+                if (DBG) {
+                    Log.d(TAG, "Set and call voice input.");
+                }
+                mService.onKey(Keyboard.CODE_VOICE, null, 0, 0);
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean isVoiceMode() {
+        return VOICE_MODE.equals(mMode);
+    }
+
+    //////////////////////////////////////
+    // SpaceBar Language Switch support //
+    //////////////////////////////////////
+
+    private LanguageSwitcher mLanguageSwitcher;
+
+    public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) {
+        if (returnsNameInThisLocale) {
+            return toTitleCase(locale.getDisplayName(locale));
+        } else {
+            return toTitleCase(locale.getDisplayName());
+        }
+    }
+
+    public static String getDisplayLanguage(Locale locale) {
+        return toTitleCase(locale.getDisplayLanguage(locale));
+    }
+
+    public static String getShortDisplayLanguage(Locale locale) {
+        return toTitleCase(locale.getLanguage());
+    }
+
+    private static String toTitleCase(String s) {
+        if (s.length() == 0) {
+            return s;
+        }
+        return Character.toUpperCase(s.charAt(0)) + s.substring(1);
+    }
+
+    private void updateForSpaceBarLanguageSwitch() {
+        // We need to update mNeedsToDisplayLanguage in onStartInputView because
+        // getEnabledKeyboardLocaleCount could have been changed.
+        mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1
+                && getSystemLocale().getLanguage().equalsIgnoreCase(
+                        getInputLocale().getLanguage()));
+    }
+
+    public String getInputLanguageName() {
+        return getDisplayLanguage(getInputLocale());
+    }
+
+    public String getNextInputLanguageName() {
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            return getDisplayLanguage(mLanguageSwitcher.getNextInputLocale());
+        } else {
+            return "";
+        }
+    }
+
+    public String getPreviousInputLanguageName() {
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            return getDisplayLanguage(mLanguageSwitcher.getPrevInputLocale());
+        } else {
+            return "";
+        }
+    }
+
+    // A list of locales which are supported by default for voice input, unless we get a
+    // different list from Gservices.
+    private static final String DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES =
+            "en " +
+            "en_US " +
+            "en_GB " +
+            "en_AU " +
+            "en_CA " +
+            "en_IE " +
+            "en_IN " +
+            "en_NZ " +
+            "en_SG " +
+            "en_ZA ";
+
+    public boolean isVoiceSupported(String locale) {
+        // Get the current list of supported locales and check the current locale against that
+        // list. We cache this value so as not to check it every time the user starts a voice
+        // input. Because this method is called by onStartInputView, this should mean that as
+        // long as the locale doesn't change while the user is keeping the IME open, the
+        // value should never be stale.
+        String supportedLocalesString = SettingsUtil.getSettingsString(
+                mService.getContentResolver(),
+                SettingsUtil.LATIN_IME_VOICE_INPUT_SUPPORTED_LOCALES,
+                DEFAULT_VOICE_INPUT_SUPPORTED_LOCALES);
+        List<String> voiceInputSupportedLocales = Arrays.asList(
+                supportedLocalesString.split("\\s+"));
+        return voiceInputSupportedLocales.contains(locale);
+    }
+
+    public void loadSettings() {
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            mLanguageSwitcher.loadLocales(mPrefs);
+        }
+    }
+
+    public void toggleLanguage(boolean reset, boolean next) {
+        if (USE_SPACEBAR_LANGUAGE_SWITCHER) {
+            if (reset) {
+                mLanguageSwitcher.reset();
+            } else {
+                if (next) {
+                    mLanguageSwitcher.next();
+                } else {
+                    mLanguageSwitcher.prev();
+                }
+            }
+            mLanguageSwitcher.persist(mPrefs);
+        }
+    }
+
+    private void initLanguageSwitcher(LatinIME service) {
+        final Configuration conf = service.getResources().getConfiguration();
+        mLanguageSwitcher = new LanguageSwitcher(service);
+        mLanguageSwitcher.loadLocales(mPrefs);
+        mLanguageSwitcher.setSystemLocale(conf.locale);
+    }
+}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
old mode 100755
new mode 100644
index 3b89894..4c9b750
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -16,17 +16,17 @@
 
 package com.android.inputmethod.latin;
 
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
 import android.content.Context;
 import android.text.AutoText;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 /**
  * This class loads a dictionary and provides a list of suggestions for a given sequence of 
  * characters. This includes corrections and completions.
@@ -81,6 +81,7 @@
 
     private boolean mAutoTextEnabled;
 
+    private double mAutoCompleteThreshold;
     private int[] mPriorities = new int[mPrefMaxSuggestions];
     private int[] mBigramPriorities = new int[PREF_MAX_BIGRAMS];
 
@@ -163,6 +164,10 @@
         mUserBigramDictionary = userBigramDictionary;
     }
 
+    public void setAutoCompleteThreshold(double threshold) {
+        mAutoCompleteThreshold = threshold;
+    }
+
     /**
      * Number of suggestions to generate from the input key sequence. This has
      * to be a number between 1 and 100 (inclusive).
@@ -301,8 +306,14 @@
             }
             mMainDict.getWords(wordComposer, this, mNextLettersFrequencies);
             if ((mCorrectionMode == CORRECTION_FULL || mCorrectionMode == CORRECTION_FULL_BIGRAM)
-                    && mSuggestions.size() > 0) {
-                mHaveCorrection = true;
+                    && mSuggestions.size() > 0 && mPriorities.length > 0) {
+                // TODO: when the normalized score of the first suggestion is nearly equals to
+                //       the normalized score of the second suggestion, behave less aggressive.
+                final double normalizedScore = LatinIMEUtil.calcNormalizedScore(
+                        mOriginalWord, mSuggestions.get(0), mPriorities[0]);
+                if (normalizedScore >= mAutoCompleteThreshold) {
+                    mHaveCorrection = true;
+                }
             }
         }
         if (mOriginalWord != null) {
@@ -326,8 +337,25 @@
                 String suggestedWord = mSuggestions.get(i).toString().toLowerCase();
                 CharSequence autoText =
                         AutoText.get(suggestedWord, 0, suggestedWord.length(), view);
-                // Is there an AutoText correction?
+                // Is there an AutoText (also known as Quick Fixes) correction?
                 boolean canAdd = autoText != null;
+                // Capitalize as needed
+                final int autoTextLength = autoText != null ? autoText.length() : 0;
+                if (autoTextLength > 0 && (mIsAllUpperCase || mIsFirstCharCapitalized)) {
+                    int poolSize = mStringPool.size();
+                    StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(
+                            poolSize - 1) : new StringBuilder(getApproxMaxWordLength());
+                    sb.setLength(0);
+                    if (mIsAllUpperCase) {
+                        sb.append(autoText.toString().toUpperCase());
+                    } else if (mIsFirstCharCapitalized) {
+                        sb.append(Character.toUpperCase(autoText.charAt(0)));
+                        if (autoTextLength > 1) {
+                            sb.append(autoText.subSequence(1, autoTextLength));
+                        }
+                    }
+                    autoText = sb.toString();
+                }
                 // Is that correction already the current prediction (or original word)?
                 canAdd &= !TextUtils.equals(autoText, mSuggestions.get(i));
                 // Is that correction already the next predicted word?
@@ -395,6 +423,7 @@
         return false;
     }
 
+    @Override
     public boolean addWord(final char[] word, final int offset, final int length, int freq,
             final int dicTypeId, final Dictionary.DataType dataType) {
         Dictionary.DataType dataTypeForLog = dataType;
@@ -450,8 +479,7 @@
             return true;
         }
 
-        System.arraycopy(priorities, pos, priorities, pos + 1,
-                prefMaxSuggestions - pos - 1);
+        System.arraycopy(priorities, pos, priorities, pos + 1, prefMaxSuggestions - pos - 1);
         priorities[pos] = freq;
         int poolSize = mStringPool.size();
         StringBuilder sb = poolSize > 0 ? (StringBuilder) mStringPool.remove(poolSize - 1) 
diff --git a/java/src/com/android/inputmethod/latin/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java
index 9011191..34babdc 100644
--- a/java/src/com/android/inputmethod/latin/TextEntryState.java
+++ b/java/src/com/android/inputmethod/latin/TextEntryState.java
@@ -16,8 +16,9 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.keyboard.Key;
+
 import android.content.Context;
-import android.inputmethodservice.Keyboard.Key;
 import android.text.format.DateFormat;
 import android.util.Log;
 
@@ -61,7 +62,7 @@
         SPACE_AFTER_PICKED,
         UNDO_COMMIT,
         CORRECTING,
-        PICKED_CORRECTION;
+        PICKED_CORRECTION,
     }
 
     private static State sState = State.UNKNOWN;
@@ -96,7 +97,7 @@
         }
         try {
             sKeyLocationFile.close();
-            // Write to log file            
+            // Write to log file
             // Write timestamp, settings,
             String out = DateFormat.format("MM:dd hh:mm:ss", Calendar.getInstance().getTime())
                     .toString()
@@ -168,6 +169,13 @@
         displayState();
     }
 
+    public static void onAbortCorrection() {
+        if (isCorrecting()) {
+            sState = State.START;
+        }
+        displayState();
+    }
+
     public static void typedCharacter(char c, boolean isSeparator) {
         boolean isSpace = c == ' ';
         switch (sState) {
@@ -253,13 +261,13 @@
     }
 
     public static void keyPressedAt(Key key, int x, int y) {
-        if (LOGGING && sKeyLocationFile != null && key.codes[0] >= 32) {
-            String out = 
-                    "KEY: " + (char) key.codes[0] 
-                    + " X: " + x 
+        if (LOGGING && sKeyLocationFile != null && key.mCodes[0] >= 32) {
+            String out =
+                    "KEY: " + (char) key.mCodes[0]
+                    + " X: " + x
                     + " Y: " + y
-                    + " MX: " + (key.x + key.width / 2)
-                    + " MY: " + (key.y + key.height / 2) 
+                    + " MX: " + (key.mX + key.mWidth / 2)
+                    + " MY: " + (key.mY + key.mHeight / 2)
                     + "\n";
             try {
                 sKeyLocationFile.write(out.getBytes());
diff --git a/java/src/com/android/inputmethod/latin/Tutorial.java b/java/src/com/android/inputmethod/latin/Tutorial.java
index d3eaf30..20767de 100644
--- a/java/src/com/android/inputmethod/latin/Tutorial.java
+++ b/java/src/com/android/inputmethod/latin/Tutorial.java
@@ -16,6 +16,9 @@
 
 package com.android.inputmethod.latin;
 
+import com.android.inputmethod.keyboard.KeyboardSwitcher;
+import com.android.inputmethod.keyboard.LatinKeyboardView;
+
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
@@ -32,20 +35,24 @@
 import android.widget.TextView;
 
 import java.util.ArrayList;
-import java.util.List;
 
 public class Tutorial implements OnTouchListener {
-    
-    private List<Bubble> mBubbles = new ArrayList<Bubble>();
-    private View mInputView;
-    private LatinIME mIme;
-    private int[] mLocation = new int[2];
-    
+
+    public interface TutorialListener {
+        public void onTutorialDone();
+    }
+
+    private final ArrayList<Bubble> mBubbles = new ArrayList<Bubble>();
+    private final KeyboardSwitcher mKeyboardSwitcher;
+    private final View mInputView;
+    private final TutorialListener mListener;
+    private final int[] mLocation = new int[2];
+
     private static final int MSG_SHOW_BUBBLE = 0;
-    
+
     private int mBubbleIndex;
-    
-    Handler mHandler = new Handler() {
+
+    private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -57,20 +64,18 @@
         }
     };
 
-    class Bubble {
-        Drawable bubbleBackground;
-        int x;
-        int y;
-        int width;
-        int gravity;
-        CharSequence text;
-        boolean dismissOnTouch;
-        boolean dismissOnClose;
-        PopupWindow window;
-        TextView textView;
-        View inputView;
-        
-        Bubble(Context context, View inputView,
+    private class Bubble {
+        private final Drawable bubbleBackground;
+        private final int x;
+        private final int y;
+        private final int width;
+        private final int gravity;
+        private final CharSequence text;
+        private final PopupWindow window;
+        private final TextView textView;
+        private final View inputView;
+
+        private Bubble(Context context, View inputView,
                 int backgroundResource, int bx, int by, int textResource1, int textResource2) {
             bubbleBackground = context.getResources().getDrawable(backgroundResource);
             x = bx;
@@ -81,8 +86,6 @@
                 .append(context.getResources().getText(textResource1))
                 .append("\n") 
                 .append(context.getResources().getText(textResource2));
-            this.dismissOnTouch = true;
-            this.dismissOnClose = false;
             this.inputView = inputView;
             window = new PopupWindow(context);
             window.setBackgroundDrawable(null);
@@ -124,7 +127,7 @@
             return l.getHeight();
         }
 
-        void show(int offx, int offy) {
+        private void show(int offx, int offy) {
             int textHeight = chooseSize(window, inputView, text, textView);
             offy -= textView.getPaddingTop() + textHeight;
             if (inputView.getVisibility() == View.VISIBLE 
@@ -133,6 +136,7 @@
                     if ((gravity & Gravity.BOTTOM) == Gravity.BOTTOM) offy -= window.getHeight();
                     if ((gravity & Gravity.RIGHT) == Gravity.RIGHT) offx -= window.getWidth();
                     textView.setOnTouchListener(new View.OnTouchListener() {
+                        @Override
                         public boolean onTouch(View view, MotionEvent me) {
                             Tutorial.this.next();
                             return true;
@@ -144,63 +148,66 @@
                 }
             }
         }
-        
-        void hide() {
+
+        private void hide() {
             if (window.isShowing()) {
                 textView.setOnTouchListener(null);
                 window.dismiss();
             }
         }
-        
-        boolean isShowing() {
+
+        private boolean isShowing() {
             return window.isShowing();
         }
     }
-    
-    public Tutorial(LatinIME ime, LatinKeyboardView inputView) {
+
+    public Tutorial(TutorialListener listener, KeyboardSwitcher keyboardSwitcher) {
+        mListener = listener;
+        mKeyboardSwitcher = keyboardSwitcher;
+        LatinKeyboardView inputView = keyboardSwitcher.getInputView();
+        mInputView = inputView;
         Context context = inputView.getContext();
-        mIme = ime;
         int inputWidth = inputView.getWidth();
         final int x = inputWidth / 20; // Half of 1/10th
+        ArrayList<Bubble> bubbles = mBubbles;
         Bubble bWelcome = new Bubble(context, inputView, 
                 R.drawable.dialog_bubble_step02, x, 0, 
                 R.string.tip_to_open_keyboard, R.string.touch_to_continue);
-        mBubbles.add(bWelcome);
+        bubbles.add(bWelcome);
         Bubble bAccents = new Bubble(context, inputView, 
                 R.drawable.dialog_bubble_step02, x, 0, 
                 R.string.tip_to_view_accents, R.string.touch_to_continue);
-        mBubbles.add(bAccents);
+        bubbles.add(bAccents);
         Bubble b123 = new Bubble(context, inputView, 
                 R.drawable.dialog_bubble_step07, x, 0, 
                 R.string.tip_to_open_symbols, R.string.touch_to_continue);
-        mBubbles.add(b123);
+        bubbles.add(b123);
         Bubble bABC = new Bubble(context, inputView, 
                 R.drawable.dialog_bubble_step07, x, 0, 
                 R.string.tip_to_close_symbols, R.string.touch_to_continue);
-        mBubbles.add(bABC);
+        bubbles.add(bABC);
         Bubble bSettings = new Bubble(context, inputView, 
                 R.drawable.dialog_bubble_step07, x, 0, 
                 R.string.tip_to_launch_settings, R.string.touch_to_continue);
-        mBubbles.add(bSettings);
+        bubbles.add(bSettings);
         Bubble bDone = new Bubble(context, inputView, 
                 R.drawable.dialog_bubble_step02, x, 0, 
                 R.string.tip_to_start_typing, R.string.touch_to_finish);
-        mBubbles.add(bDone);
-        mInputView = inputView;
+        bubbles.add(bDone);
     }
-    
-    void start() {
+
+    public void start() {
         mInputView.getLocationInWindow(mLocation);
         mBubbleIndex = -1;
         mInputView.setOnTouchListener(this);
         next();
     }
 
-    boolean next() {
+    private void next() {
         if (mBubbleIndex >= 0) {
             // If the bubble is not yet showing, don't move to the next.
             if (!mBubbles.get(mBubbleIndex).isShowing()) {
-                return true;
+                return;
             }
             // Hide all previous bubbles as well, as they may have had a delayed show
             for (int i = 0; i <= mBubbleIndex; i++) {
@@ -210,31 +217,31 @@
         mBubbleIndex++;
         if (mBubbleIndex >= mBubbles.size()) {
             mInputView.setOnTouchListener(null);
-            mIme.sendDownUpKeyEvents(-1); // Inform the setupwizard that tutorial is in last bubble
-            mIme.tutorialDone();
-            return false;
+            mListener.onTutorialDone();
+            return;
         }
         if (mBubbleIndex == 3 || mBubbleIndex == 4) {
-            mIme.mKeyboardSwitcher.toggleSymbols();
+            mKeyboardSwitcher.changeKeyboardMode();
         }
         mHandler.sendMessageDelayed(
                 mHandler.obtainMessage(MSG_SHOW_BUBBLE, mBubbles.get(mBubbleIndex)), 500);
-        return true;
+        return;
     }
-    
-    void hide() {
-        for (int i = 0; i < mBubbles.size(); i++) {
-            mBubbles.get(i).hide();
+
+    private void hide() {
+        for (Bubble bubble : mBubbles) {
+            bubble.hide();
         }
         mInputView.setOnTouchListener(null);
     }
 
-    boolean close() {
+    public boolean close() {
         mHandler.removeMessages(MSG_SHOW_BUBBLE);
         hide();
         return true;
     }
 
+    @Override
     public boolean onTouch(View v, MotionEvent event) {
         if (event.getAction() == MotionEvent.ACTION_DOWN) {
             next();
diff --git a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java
index 67d9c0b..6d2f6b6 100644
--- a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java
@@ -16,10 +16,6 @@
 
 package com.android.inputmethod.latin;
 
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
@@ -30,6 +26,10 @@
 import android.provider.BaseColumns;
 import android.util.Log;
 
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+
 /**
  * Stores all the pairs user types in databases. Prune the database if the size
  * gets too big. Unlike AutoDictionary, it even stores the pairs that are already
diff --git a/java/src/com/android/inputmethod/latin/UserDictionary.java b/java/src/com/android/inputmethod/latin/UserDictionary.java
index 49b95e9..a522303 100644
--- a/java/src/com/android/inputmethod/latin/UserDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserDictionary.java
@@ -97,6 +97,7 @@
 
         final ContentResolver contentResolver = getContext().getContentResolver();
         new Thread("addWord") {
+            @Override
             public void run() {
                 contentResolver.insert(Words.CONTENT_URI, values);
             }
diff --git a/java/src/com/android/inputmethod/voice/FieldContext.java b/java/src/com/android/inputmethod/voice/FieldContext.java
index 5fbacfb..dfdfbaa 100644
--- a/java/src/com/android/inputmethod/voice/FieldContext.java
+++ b/java/src/com/android/inputmethod/voice/FieldContext.java
@@ -73,6 +73,7 @@
         bundle.putInt(IME_OPTIONS, info.imeOptions);
     }
 
+    @SuppressWarnings("static-access")
     private static void addInputConnectionToBundle(
         InputConnection conn, Bundle bundle) {
         if (conn == null) {
@@ -96,6 +97,7 @@
         return mFieldInfo;
     }
 
+    @Override
     public String toString() {
         return mFieldInfo.toString();
     }
diff --git a/java/src/com/android/inputmethod/latin/Hints.java b/java/src/com/android/inputmethod/voice/Hints.java
similarity index 84%
rename from java/src/com/android/inputmethod/latin/Hints.java
rename to java/src/com/android/inputmethod/voice/Hints.java
index c467365..d11d3b0 100644
--- a/java/src/com/android/inputmethod/latin/Hints.java
+++ b/java/src/com/android/inputmethod/voice/Hints.java
@@ -14,14 +14,14 @@
  * the License.
  */
 
-package com.android.inputmethod.latin;
+package com.android.inputmethod.voice;
 
-import com.android.inputmethod.voice.SettingsUtil;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SharedPreferencesCompat;
 
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.SharedPreferences;
-import android.preference.PreferenceManager;
 import android.view.inputmethod.InputConnection;
 
 import java.util.Calendar;
@@ -47,8 +47,9 @@
     private static final int DEFAULT_SWIPE_HINT_MAX_DAYS_TO_SHOW = 7;
     private static final int DEFAULT_PUNCTUATION_HINT_MAX_DISPLAYS = 7;
 
-    private Context mContext;
-    private Display mDisplay;
+    private final Context mContext;
+    private final SharedPreferences mPrefs;
+    private final Display mDisplay;
     private boolean mVoiceResultContainedPunctuation;
     private int mSwipeHintMaxDaysToShow;
     private int mPunctuationHintMaxDisplays;
@@ -62,8 +63,9 @@
         SPEAKABLE_PUNCTUATION.put("?", "question mark");
     }
 
-    public Hints(Context context, Display display) {
+    public Hints(Context context, SharedPreferences prefs, Display display) {
         mContext = context;
+        mPrefs = prefs;
         mDisplay = display;
 
         ContentResolver cr = mContext.getContentResolver();
@@ -103,8 +105,7 @@
 
     public void registerVoiceResult(String text) {
         // Update the current time as the last time voice input was used.
-        SharedPreferences.Editor editor =
-                PreferenceManager.getDefaultSharedPreferences(mContext).edit();
+        SharedPreferences.Editor editor = mPrefs.edit();
         editor.putLong(PREF_VOICE_INPUT_LAST_TIME_USED, System.currentTimeMillis());
         SharedPreferencesCompat.apply(editor);
 
@@ -118,14 +119,14 @@
     }
 
     private boolean shouldShowSwipeHint() {
-        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+        final SharedPreferences prefs = mPrefs;
 
-        int numUniqueDaysShown = sp.getInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, 0);
+        int numUniqueDaysShown = prefs.getInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, 0);
 
         // If we've already shown the hint for enough days, we'll return false.
         if (numUniqueDaysShown < mSwipeHintMaxDaysToShow) {
 
-            long lastTimeVoiceWasUsed = sp.getLong(PREF_VOICE_INPUT_LAST_TIME_USED, 0);
+            long lastTimeVoiceWasUsed = prefs.getLong(PREF_VOICE_INPUT_LAST_TIME_USED, 0);
 
             // If the user has used voice today, we'll return false. (We don't show the hint on
             // any day that the user has already used voice.)
@@ -156,16 +157,16 @@
     }
 
     private void showHint(int hintViewResource) {
-        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
+        final SharedPreferences prefs = mPrefs;
 
-        int numUniqueDaysShown = sp.getInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, 0);
-        long lastTimeHintWasShown = sp.getLong(PREF_VOICE_HINT_LAST_TIME_SHOWN, 0);
+        int numUniqueDaysShown = prefs.getInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, 0);
+        long lastTimeHintWasShown = prefs.getLong(PREF_VOICE_HINT_LAST_TIME_SHOWN, 0);
 
         // If this is the first time the hint is being shown today, increase the saved values
         // to represent that. We don't need to increase the last time the hint was shown unless
         // it is a different day from the current value.
         if (!isFromToday(lastTimeHintWasShown)) {
-            SharedPreferences.Editor editor = sp.edit();
+            SharedPreferences.Editor editor = prefs.edit();
             editor.putInt(PREF_VOICE_HINT_NUM_UNIQUE_DAYS_SHOWN, numUniqueDaysShown + 1);
             editor.putLong(PREF_VOICE_HINT_LAST_TIME_SHOWN, System.currentTimeMillis());
             SharedPreferencesCompat.apply(editor);
@@ -177,9 +178,9 @@
     }
 
     private int getAndIncrementPref(String pref) {
-        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
-        int value = sp.getInt(pref, 0);
-        SharedPreferences.Editor editor = sp.edit();
+        final SharedPreferences prefs = mPrefs;
+        int value = prefs.getInt(pref, 0);
+        SharedPreferences.Editor editor = prefs.edit();
         editor.putInt(pref, value + 1);
         SharedPreferencesCompat.apply(editor);
         return value;
diff --git a/java/src/com/android/inputmethod/voice/RecognitionView.java b/java/src/com/android/inputmethod/voice/RecognitionView.java
index 7cec0b0..12d0de8 100644
--- a/java/src/com/android/inputmethod/voice/RecognitionView.java
+++ b/java/src/com/android/inputmethod/voice/RecognitionView.java
@@ -16,12 +16,7 @@
 
 package com.android.inputmethod.voice;
 
-import java.io.ByteArrayOutputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.ShortBuffer;
-import java.util.ArrayList;
-import java.util.List;
+import com.android.inputmethod.latin.R;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -43,7 +38,12 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import com.android.inputmethod.latin.R;
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.ShortBuffer;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * The user interface for the "Speak now" and "working" states.
@@ -51,6 +51,7 @@
  * plays beeps, shows errors, etc.
  */
 public class RecognitionView {
+    @SuppressWarnings("unused")
     private static final String TAG = "RecognitionView";
 
     private Handler mUiHandler;  // Reference to UI thread
@@ -78,6 +79,7 @@
 
     /** Updates the microphone icon to show user their volume.*/
     private Runnable mUpdateVolumeRunnable = new Runnable() {
+        @Override
         public void run() {
             if (mState != State.LISTENING) {
                 return;
@@ -141,6 +143,7 @@
 
     public void restoreState() {
         mUiHandler.post(new Runnable() {
+            @Override
             public void run() {
                 // Restart the spinner
                 if (mState == State.WORKING) {
@@ -153,6 +156,7 @@
 
     public void showInitializing() {
         mUiHandler.post(new Runnable() {
+            @Override
             public void run() {
                 prepareDialog(false, mContext.getText(R.string.voice_initializing), mInitializing,
                         mContext.getText(R.string.cancel)); 
@@ -162,6 +166,7 @@
 
     public void showListening() {
         mUiHandler.post(new Runnable() {
+            @Override
             public void run() {
                 mState = State.LISTENING;
                 prepareDialog(false, mContext.getText(R.string.voice_listening), mSpeakNow.get(0),
@@ -177,6 +182,7 @@
 
     public void showError(final String message) {
         mUiHandler.post(new Runnable() {
+            @Override
             public void run() {
                 mState = State.READY;
                 prepareDialog(false, message, mError, mContext.getText(R.string.ok));
@@ -190,6 +196,7 @@
         final int speechEndPosition) {
 
         mUiHandler.post(new Runnable() {
+            @Override
             public void run() {
                 mState = State.WORKING;
                 prepareDialog(true, mContext.getText(R.string.voice_working), null, mContext
@@ -309,6 +316,7 @@
 
     public void finish() {
         mUiHandler.post(new Runnable() {
+            @Override
             public void run() {
                 mState = State.READY;
                 exitWorking();
diff --git a/java/src/com/android/inputmethod/voice/SettingsUtil.java b/java/src/com/android/inputmethod/voice/SettingsUtil.java
index abf5204..4d746e1 100644
--- a/java/src/com/android/inputmethod/voice/SettingsUtil.java
+++ b/java/src/com/android/inputmethod/voice/SettingsUtil.java
@@ -17,10 +17,7 @@
 package com.android.inputmethod.voice;
 
 import android.content.ContentResolver;
-import android.database.Cursor;
-import android.net.Uri;
 import android.provider.Settings;
-import android.util.Log;
 
 /**
  * Utility for retrieving settings from Settings.Secure.
diff --git a/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
new file mode 100644
index 0000000..7ad6c35
--- /dev/null
+++ b/java/src/com/android/inputmethod/voice/VoiceIMEConnector.java
@@ -0,0 +1,688 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.voice;
+
+import com.android.inputmethod.keyboard.KeyboardSwitcher;
+import com.android.inputmethod.latin.EditingUtil;
+import com.android.inputmethod.latin.LatinIME;
+import com.android.inputmethod.latin.LatinIME.UIHandler;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.SharedPreferencesCompat;
+import com.android.inputmethod.latin.SubtypeSwitcher;
+
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.IBinder;
+import android.preference.PreferenceManager;
+import android.provider.Browser;
+import android.speech.SpeechRecognizer;
+import android.text.Layout;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.TextUtils;
+import android.text.method.LinkMovementMethod;
+import android.text.style.ClickableSpan;
+import android.text.style.URLSpan;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class VoiceIMEConnector implements VoiceInput.UiListener {
+    private static final VoiceIMEConnector sInstance = new VoiceIMEConnector();
+
+    public static final boolean VOICE_INSTALLED = true;
+    private static final boolean ENABLE_VOICE_BUTTON = true;
+    private static final String PREF_VOICE_MODE = "voice_mode";
+    // Whether or not the user has used voice input before (and thus, whether to show the
+    // first-run warning dialog or not).
+    private static final String PREF_HAS_USED_VOICE_INPUT = "has_used_voice_input";
+    // Whether or not the user has used voice input from an unsupported locale UI before.
+    // For example, the user has a Chinese UI but activates voice input.
+    private static final String PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE =
+            "has_used_voice_input_unsupported_locale";
+    // The private IME option used to indicate that no microphone should be shown for a
+    // given text field. For instance this is specified by the search dialog when the
+    // dialog is already showing a voice search button.
+    private static final String IME_OPTION_NO_MICROPHONE = "nm";
+
+    private boolean mAfterVoiceInput;
+    private boolean mHasUsedVoiceInput;
+    private boolean mHasUsedVoiceInputUnsupportedLocale;
+    private boolean mImmediatelyAfterVoiceInput;
+    private boolean mIsShowingHint;
+    private boolean mLocaleSupportedForVoiceInput;
+    private boolean mPasswordText;
+    private boolean mRecognizing;
+    private boolean mShowingVoiceSuggestions;
+    private boolean mVoiceButtonEnabled;
+    private boolean mVoiceButtonOnPrimary;
+    private boolean mVoiceInputHighlighted;
+
+    private InputMethodManager mImm;
+    private LatinIME mContext;
+    private AlertDialog mVoiceWarningDialog;
+    private VoiceInput mVoiceInput;
+    private final VoiceResults mVoiceResults = new VoiceResults();
+    private Hints mHints;
+    private UIHandler mHandler;
+    private SubtypeSwitcher mSubtypeSwitcher;
+    // For each word, a list of potential replacements, usually from voice.
+    private final Map<String, List<CharSequence>> mWordToSuggestions =
+            new HashMap<String, List<CharSequence>>();
+
+    public static VoiceIMEConnector init(LatinIME context, SharedPreferences prefs, UIHandler h) {
+        sInstance.initInternal(context, prefs, h);
+        return sInstance;
+    }
+
+    public static VoiceIMEConnector getInstance() {
+        return sInstance;
+    }
+
+    private void initInternal(LatinIME context, SharedPreferences prefs, UIHandler h) {
+        mContext = context;
+        mHandler = h;
+        mImm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
+        if (VOICE_INSTALLED) {
+            mVoiceInput = new VoiceInput(context, this);
+            mHints = new Hints(context, prefs, new Hints.Display() {
+                @Override
+                public void showHint(int viewResource) {
+                    LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+                            Context.LAYOUT_INFLATER_SERVICE);
+                    View view = inflater.inflate(viewResource, null);
+                    mContext.setCandidatesView(view);
+                    mContext.setCandidatesViewShown(true);
+                    mIsShowingHint = true;
+                }
+              });
+        }
+    }
+
+    private VoiceIMEConnector() {
+    }
+
+    public void resetVoiceStates(boolean isPasswordText) {
+        mAfterVoiceInput = false;
+        mImmediatelyAfterVoiceInput = false;
+        mShowingVoiceSuggestions = false;
+        mVoiceInputHighlighted = false;
+        mPasswordText = isPasswordText;
+    }
+
+    public void flushVoiceInputLogs(boolean configurationChanged) {
+        if (VOICE_INSTALLED && !configurationChanged) {
+            if (mAfterVoiceInput) {
+                mVoiceInput.flushAllTextModificationCounters();
+                mVoiceInput.logInputEnded();
+            }
+            mVoiceInput.flushLogs();
+            mVoiceInput.cancel();
+        }
+    }
+
+    public void flushAndLogAllTextModificationCounters(int index, CharSequence suggestion,
+            String wordSeparators) {
+        if (mAfterVoiceInput && mShowingVoiceSuggestions) {
+            mVoiceInput.flushAllTextModificationCounters();
+            // send this intent AFTER logging any prior aggregated edits.
+            mVoiceInput.logTextModifiedByChooseSuggestion(suggestion.toString(), index,
+                    wordSeparators, mContext.getCurrentInputConnection());
+        }
+    }
+
+    private void showVoiceWarningDialog(final boolean swipe, IBinder token,
+            final boolean configurationChanging) {
+        if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
+            return;
+        }
+        AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
+        builder.setCancelable(true);
+        builder.setIcon(R.drawable.ic_mic_dialog);
+        builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int whichButton) {
+                mVoiceInput.logKeyboardWarningDialogOk();
+                reallyStartListening(swipe, configurationChanging);
+            }
+        });
+        builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int whichButton) {
+                mVoiceInput.logKeyboardWarningDialogCancel();
+                switchToLastInputMethod();
+            }
+        });
+        // When the dialog is dismissed by user's cancellation, switch back to the last input method
+        builder.setOnCancelListener(new DialogInterface.OnCancelListener() {
+            @Override
+            public void onCancel(DialogInterface arg0) {
+                mVoiceInput.logKeyboardWarningDialogCancel();
+                switchToLastInputMethod();
+            }
+        });
+
+        final CharSequence message;
+        if (mLocaleSupportedForVoiceInput) {
+            message = TextUtils.concat(
+                    mContext.getText(R.string.voice_warning_may_not_understand), "\n\n",
+                            mContext.getText(R.string.voice_warning_how_to_turn_off));
+        } else {
+            message = TextUtils.concat(
+                    mContext.getText(R.string.voice_warning_locale_not_supported), "\n\n",
+                            mContext.getText(R.string.voice_warning_may_not_understand), "\n\n",
+                                    mContext.getText(R.string.voice_warning_how_to_turn_off));
+        }
+        builder.setMessage(message);
+
+        builder.setTitle(R.string.voice_warning_title);
+        mVoiceWarningDialog = builder.create();
+        Window window = mVoiceWarningDialog.getWindow();
+        WindowManager.LayoutParams lp = window.getAttributes();
+        lp.token = token;
+        lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
+        window.setAttributes(lp);
+        window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+        mVoiceInput.logKeyboardWarningDialogShown();
+        mVoiceWarningDialog.show();
+        // Make URL in the dialog message clickable
+        TextView textView = (TextView) mVoiceWarningDialog.findViewById(android.R.id.message);
+        if (textView != null) {
+            final CustomLinkMovementMethod method = CustomLinkMovementMethod.getInstance();
+            method.setVoiceWarningDialog(mVoiceWarningDialog);
+            textView.setMovementMethod(method);
+        }
+    }
+
+    private static class CustomLinkMovementMethod extends LinkMovementMethod {
+        private static CustomLinkMovementMethod sInstance = new CustomLinkMovementMethod();
+        private AlertDialog mAlertDialog;
+
+        public void setVoiceWarningDialog(AlertDialog alertDialog) {
+            mAlertDialog = alertDialog;
+        }
+
+        public static CustomLinkMovementMethod getInstance() {
+            return sInstance;
+        }
+
+        // Almost the same as LinkMovementMethod.onTouchEvent(), but overrides it for
+        // FLAG_ACTIVITY_NEW_TASK and mAlertDialog.cancel().
+        @Override
+        public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
+            int action = event.getAction();
+
+            if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
+                int x = (int) event.getX();
+                int y = (int) event.getY();
+
+                x -= widget.getTotalPaddingLeft();
+                y -= widget.getTotalPaddingTop();
+
+                x += widget.getScrollX();
+                y += widget.getScrollY();
+
+                Layout layout = widget.getLayout();
+                int line = layout.getLineForVertical(y);
+                int off = layout.getOffsetForHorizontal(line, x);
+
+                ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class);
+
+                if (link.length != 0) {
+                    if (action == MotionEvent.ACTION_UP) {
+                        if (link[0] instanceof URLSpan) {
+                            URLSpan urlSpan = (URLSpan) link[0];
+                            Uri uri = Uri.parse(urlSpan.getURL());
+                            Context context = widget.getContext();
+                            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                            intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
+                            if (mAlertDialog != null) {
+                                // Go back to the previous IME for now.
+                                // TODO: If we can find a way to bring the new activity to front
+                                // while keeping the warning dialog, we don't need to cancel here.
+                                mAlertDialog.cancel();
+                            }
+                            context.startActivity(intent);
+                        } else {
+                            link[0].onClick(widget);
+                        }
+                    } else if (action == MotionEvent.ACTION_DOWN) {
+                        Selection.setSelection(buffer, buffer.getSpanStart(link[0]),
+                                buffer.getSpanEnd(link[0]));
+                    }
+                    return true;
+                } else {
+                    Selection.removeSelection(buffer);
+                }
+            }
+            return super.onTouchEvent(widget, buffer, event);
+        }
+    }
+
+    public void showPunctuationHintIfNecessary() {
+        InputConnection ic = mContext.getCurrentInputConnection();
+        if (!mImmediatelyAfterVoiceInput && mAfterVoiceInput && ic != null) {
+            if (mHints.showPunctuationHintIfNecessary(ic)) {
+                mVoiceInput.logPunctuationHintDisplayed();
+            }
+        }
+        mImmediatelyAfterVoiceInput = false;
+    }
+
+    public void hideVoiceWindow(boolean configurationChanging) {
+        if (!configurationChanging) {
+            if (mAfterVoiceInput)
+                mVoiceInput.logInputEnded();
+            if (mVoiceWarningDialog != null && mVoiceWarningDialog.isShowing()) {
+                mVoiceInput.logKeyboardWarningDialogDismissed();
+                mVoiceWarningDialog.dismiss();
+                mVoiceWarningDialog = null;
+            }
+            if (VOICE_INSTALLED & mRecognizing) {
+                mVoiceInput.cancel();
+            }
+        }
+        mWordToSuggestions.clear();
+    }
+
+    public void setCursorAndSelection(int newSelEnd, int newSelStart) {
+        if (mAfterVoiceInput) {
+            mVoiceInput.setCursorPos(newSelEnd);
+            mVoiceInput.setSelectionSpan(newSelEnd - newSelStart);
+        }
+    }
+
+    public void setVoiceInputHighlighted(boolean b) {
+        mVoiceInputHighlighted = b;
+    }
+
+    public void setShowingVoiceSuggestions(boolean b) {
+        mShowingVoiceSuggestions = b;
+    }
+
+    public boolean isVoiceButtonEnabled() {
+        return mVoiceButtonEnabled;
+    }
+
+    public boolean isVoiceButtonOnPrimary() {
+        return mVoiceButtonOnPrimary;
+    }
+
+    public boolean isVoiceInputHighlighted() {
+        return mVoiceInputHighlighted;
+    }
+
+    public boolean isRecognizing() {
+        return mRecognizing;
+    }
+
+    public boolean needsToShowWarningDialog() {
+        return !mHasUsedVoiceInput
+                || (!mLocaleSupportedForVoiceInput && !mHasUsedVoiceInputUnsupportedLocale);
+    }
+
+    public boolean getAndResetIsShowingHint() {
+        boolean ret = mIsShowingHint;
+        mIsShowingHint = false;
+        return ret;
+    }
+
+    private void revertVoiceInput() {
+        InputConnection ic = mContext.getCurrentInputConnection();
+        if (ic != null) ic.commitText("", 1);
+        mContext.updateSuggestions();
+        mVoiceInputHighlighted = false;
+    }
+
+    public void commitVoiceInput() {
+        if (VOICE_INSTALLED && mVoiceInputHighlighted) {
+            InputConnection ic = mContext.getCurrentInputConnection();
+            if (ic != null) ic.finishComposingText();
+            mContext.updateSuggestions();
+            mVoiceInputHighlighted = false;
+        }
+    }
+
+    public boolean logAndRevertVoiceInput() {
+        if (VOICE_INSTALLED && mVoiceInputHighlighted) {
+            mVoiceInput.incrementTextModificationDeleteCount(
+                    mVoiceResults.candidates.get(0).toString().length());
+            revertVoiceInput();
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public void rememberReplacedWord(CharSequence suggestion,String wordSeparators) {
+        if (mShowingVoiceSuggestions) {
+            // Retain the replaced word in the alternatives array.
+            EditingUtil.Range range = new EditingUtil.Range();
+            String wordToBeReplaced = EditingUtil.getWordAtCursor(
+                    mContext.getCurrentInputConnection(), wordSeparators, range);
+            if (!mWordToSuggestions.containsKey(wordToBeReplaced)) {
+                wordToBeReplaced = wordToBeReplaced.toLowerCase();
+            }
+            if (mWordToSuggestions.containsKey(wordToBeReplaced)) {
+                List<CharSequence> suggestions = mWordToSuggestions.get(wordToBeReplaced);
+                if (suggestions.contains(suggestion)) {
+                    suggestions.remove(suggestion);
+                }
+                suggestions.add(wordToBeReplaced);
+                mWordToSuggestions.remove(wordToBeReplaced);
+                mWordToSuggestions.put(suggestion.toString(), suggestions);
+            }
+        }
+    }
+
+    /**
+     * Tries to apply any voice alternatives for the word if this was a spoken word and
+     * there are voice alternatives.
+     * @param touching The word that the cursor is touching, with position information
+     * @return true if an alternative was found, false otherwise.
+     */
+    public boolean applyVoiceAlternatives(EditingUtil.SelectedWord touching) {
+        // Search for result in spoken word alternatives
+        String selectedWord = touching.word.toString().trim();
+        if (!mWordToSuggestions.containsKey(selectedWord)) {
+            selectedWord = selectedWord.toLowerCase();
+        }
+        if (mWordToSuggestions.containsKey(selectedWord)) {
+            mShowingVoiceSuggestions = true;
+            List<CharSequence> suggestions = mWordToSuggestions.get(selectedWord);
+            // If the first letter of touching is capitalized, make all the suggestions
+            // start with a capital letter.
+            if (Character.isUpperCase(touching.word.charAt(0))) {
+                for (int i = 0; i < suggestions.size(); i++) {
+                    String origSugg = (String) suggestions.get(i);
+                    String capsSugg = origSugg.toUpperCase().charAt(0)
+                            + origSugg.subSequence(1, origSugg.length()).toString();
+                    suggestions.set(i, capsSugg);
+                }
+            }
+            mContext.setSuggestions(suggestions, false, true, true);
+            mContext.setCandidatesViewShown(true);
+            return true;
+        }
+        return false;
+    }
+
+    public void handleBackspace() {
+        if (mAfterVoiceInput) {
+            // Don't log delete if the user is pressing delete at
+            // the beginning of the text box (hence not deleting anything)
+            if (mVoiceInput.getCursorPos() > 0) {
+                // If anything was selected before the delete was pressed, increment the
+                // delete count by the length of the selection
+                int deleteLen  =  mVoiceInput.getSelectionSpan() > 0 ?
+                        mVoiceInput.getSelectionSpan() : 1;
+                mVoiceInput.incrementTextModificationDeleteCount(deleteLen);
+            }
+        }
+    }
+
+    public void handleCharacter() {
+        commitVoiceInput();
+        if (mAfterVoiceInput) {
+            // Assume input length is 1. This assumption fails for smiley face insertions.
+            mVoiceInput.incrementTextModificationInsertCount(1);
+        }
+    }
+
+    public void handleSeparator() {
+        commitVoiceInput();
+        if (mAfterVoiceInput){
+            // Assume input length is 1. This assumption fails for smiley face insertions.
+            mVoiceInput.incrementTextModificationInsertPunctuationCount(1);
+        }
+    }
+
+    public void handleClose() {
+        if (VOICE_INSTALLED & mRecognizing) {
+            mVoiceInput.cancel();
+        }
+    }
+
+
+    public void handleVoiceResults(KeyboardSwitcher switcher, boolean capitalizeFirstWord) {
+        mAfterVoiceInput = true;
+        mImmediatelyAfterVoiceInput = true;
+
+        InputConnection ic = mContext.getCurrentInputConnection();
+        if (!mContext.isFullscreenMode()) {
+            // Start listening for updates to the text from typing, etc.
+            if (ic != null) {
+                ExtractedTextRequest req = new ExtractedTextRequest();
+                ic.getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR);
+            }
+        }
+        mContext.vibrate();
+
+        final List<CharSequence> nBest = new ArrayList<CharSequence>();
+        for (String c : mVoiceResults.candidates) {
+            if (capitalizeFirstWord) {
+                c = Character.toUpperCase(c.charAt(0)) + c.substring(1, c.length());
+            }
+            nBest.add(c);
+        }
+        if (nBest.size() == 0) {
+            return;
+        }
+        String bestResult = nBest.get(0).toString();
+        mVoiceInput.logVoiceInputDelivered(bestResult.length());
+        mHints.registerVoiceResult(bestResult);
+
+        if (ic != null) ic.beginBatchEdit(); // To avoid extra updates on committing older text
+        mContext.commitTyped(ic);
+        EditingUtil.appendText(ic, bestResult);
+        if (ic != null) ic.endBatchEdit();
+
+        mVoiceInputHighlighted = true;
+        mWordToSuggestions.putAll(mVoiceResults.alternatives);
+        onCancelVoice();
+    }
+
+    public void switchToRecognitionStatusView(final boolean configurationChanging) {
+        final boolean configChanged = configurationChanging;
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mContext.setCandidatesViewShown(false);
+                mRecognizing = true;
+                View v = mVoiceInput.getView();
+                ViewParent p = v.getParent();
+                if (p != null && p instanceof ViewGroup) {
+                    ((ViewGroup)p).removeView(v);
+                }
+                mContext.setInputView(v);
+                mContext.updateInputViewShown();
+                if (configChanged) {
+                    mVoiceInput.onConfigurationChanged();
+                }
+        }});
+    }
+
+    private void switchToLastInputMethod() {
+        IBinder token = mContext.getWindow().getWindow().getAttributes().token;
+        mImm.switchToLastInputMethod(token);
+    }
+
+    private void reallyStartListening(boolean swipe, final boolean configurationChanging) {
+        if (!VOICE_INSTALLED) {
+            return;
+        }
+        if (!mHasUsedVoiceInput) {
+            // The user has started a voice input, so remember that in the
+            // future (so we don't show the warning dialog after the first run).
+            SharedPreferences.Editor editor =
+                    PreferenceManager.getDefaultSharedPreferences(mContext).edit();
+            editor.putBoolean(PREF_HAS_USED_VOICE_INPUT, true);
+            SharedPreferencesCompat.apply(editor);
+            mHasUsedVoiceInput = true;
+        }
+
+        if (!mLocaleSupportedForVoiceInput && !mHasUsedVoiceInputUnsupportedLocale) {
+            // The user has started a voice input from an unsupported locale, so remember that
+            // in the future (so we don't show the warning dialog the next time they do this).
+            SharedPreferences.Editor editor =
+                    PreferenceManager.getDefaultSharedPreferences(mContext).edit();
+            editor.putBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, true);
+            SharedPreferencesCompat.apply(editor);
+            mHasUsedVoiceInputUnsupportedLocale = true;
+        }
+
+        // Clear N-best suggestions
+        mContext.clearSuggestions();
+
+        FieldContext context = makeFieldContext();
+        mVoiceInput.startListening(context, swipe);
+        switchToRecognitionStatusView(configurationChanging);
+    }
+
+    public void startListening(final boolean swipe, IBinder token,
+            final boolean configurationChanging) {
+        // TODO: remove swipe which is no longer used.
+        if (VOICE_INSTALLED) {
+            if (needsToShowWarningDialog()) {
+                // Calls reallyStartListening if user clicks OK, does nothing if user clicks Cancel.
+                showVoiceWarningDialog(swipe, token, configurationChanging);
+            } else {
+                reallyStartListening(swipe, configurationChanging);
+            }
+        }
+    }
+
+
+    private boolean fieldCanDoVoice(FieldContext fieldContext) {
+        return !mPasswordText
+                && mVoiceInput != null
+                && !mVoiceInput.isBlacklistedField(fieldContext);
+    }
+
+    private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo attribute) {
+        return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext)
+                && !(attribute != null
+                        && IME_OPTION_NO_MICROPHONE.equals(attribute.privateImeOptions))
+                && SpeechRecognizer.isRecognitionAvailable(mContext);
+    }
+
+    public void loadSettings(EditorInfo attribute, SharedPreferences sp) {
+        mHasUsedVoiceInput = sp.getBoolean(PREF_HAS_USED_VOICE_INPUT, false);
+        mHasUsedVoiceInputUnsupportedLocale =
+                sp.getBoolean(PREF_HAS_USED_VOICE_INPUT_UNSUPPORTED_LOCALE, false);
+
+        mLocaleSupportedForVoiceInput = SubtypeSwitcher.getInstance().isVoiceSupported(
+                SubtypeSwitcher.getInstance().getInputLocaleStr());
+
+        if (VOICE_INSTALLED) {
+            final String voiceMode = sp.getString(PREF_VOICE_MODE,
+                    mContext.getString(R.string.voice_mode_main));
+            mVoiceButtonEnabled = !voiceMode.equals(mContext.getString(R.string.voice_mode_off))
+                    && shouldShowVoiceButton(makeFieldContext(), attribute);
+            mVoiceButtonOnPrimary = voiceMode.equals(mContext.getString(R.string.voice_mode_main));
+        }
+    }
+
+    public void destroy() {
+        if (VOICE_INSTALLED && mVoiceInput != null) {
+            mVoiceInput.destroy();
+        }
+    }
+
+    public void onStartInputView(IBinder token) {
+        // If IME is in voice mode, but still needs to show the voice warning dialog,
+        // keep showing the warning.
+        if (mSubtypeSwitcher.isVoiceMode() && needsToShowWarningDialog() && token != null) {
+            showVoiceWarningDialog(false, token, false);
+        }
+    }
+
+    public void onAttachedToWindow() {
+        // After onAttachedToWindow, we can show the voice warning dialog. See startListening()
+        // above.
+        mSubtypeSwitcher.setVoiceInput(mVoiceInput);
+    }
+
+    public void onConfigurationChanged(boolean configurationChanging) {
+        if (mRecognizing) {
+            switchToRecognitionStatusView(configurationChanging);
+        }
+    }
+
+    @Override
+    public void onCancelVoice() {
+        if (mRecognizing) {
+            if (mSubtypeSwitcher.isVoiceMode()) {
+                // If voice mode is being canceled within LatinIME (i.e. time-out or user
+                // cancellation etc.), onCancelVoice() will be called first. LatinIME thinks it's
+                // still in voice mode. LatinIME needs to call switchToLastInputMethod().
+                // Note that onCancelVoice() will be called again from SubtypeSwitcher.
+                switchToLastInputMethod();
+            } else if (mSubtypeSwitcher.isKeyboardMode()) {
+                // If voice mode is being canceled out of LatinIME (i.e. by user's IME switching or
+                // as a result of switchToLastInputMethod() etc.),
+                // onCurrentInputMethodSubtypeChanged() will be called first. LatinIME will know
+                // that it's in keyboard mode and SubtypeSwitcher will call onCancelVoice().
+                mRecognizing = false;
+                mContext.switchToKeyboardView();
+            }
+        }
+    }
+
+    @Override
+    public void onVoiceResults(List<String> candidates,
+            Map<String, List<CharSequence>> alternatives) {
+        if (!mRecognizing) {
+            return;
+        }
+        mVoiceResults.candidates = candidates;
+        mVoiceResults.alternatives = alternatives;
+        mHandler.updateVoiceResults();
+    }
+
+    public FieldContext makeFieldContext() {
+        SubtypeSwitcher switcher = SubtypeSwitcher.getInstance();
+        return new FieldContext(mContext.getCurrentInputConnection(),
+                mContext.getCurrentInputEditorInfo(), switcher.getInputLocaleStr(),
+                switcher.getEnabledLanguages());
+    }
+
+    private class VoiceResults {
+        List<String> candidates;
+        Map<String, List<CharSequence>> alternatives;
+    }
+}
diff --git a/java/src/com/android/inputmethod/voice/VoiceInput.java b/java/src/com/android/inputmethod/voice/VoiceInput.java
index f24c180..d51d869 100644
--- a/java/src/com/android/inputmethod/voice/VoiceInput.java
+++ b/java/src/com/android/inputmethod/voice/VoiceInput.java
@@ -16,6 +16,7 @@
 
 package com.android.inputmethod.voice;
 
+import com.android.inputmethod.latin.EditingUtil;
 import com.android.inputmethod.latin.R;
 
 import android.content.ContentResolver;
@@ -27,11 +28,12 @@
 import android.os.Message;
 import android.os.Parcelable;
 import android.speech.RecognitionListener;
-import android.speech.SpeechRecognizer;
 import android.speech.RecognizerIntent;
+import android.speech.SpeechRecognizer;
 import android.util.Log;
 import android.view.View;
 import android.view.View.OnClickListener;
+import android.view.inputmethod.InputConnection;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -84,6 +86,7 @@
     private static final String ALTERNATES_BUNDLE = "alternates_bundle";
 
     //  This is copied from the VoiceSearch app.
+    @SuppressWarnings("unused")
     private static final class AlternatesBundleKeys {
         public static final String ALTERNATES = "alternates";
         public static final String CONFIDENCE = "confidence";
@@ -403,6 +406,7 @@
     /**
      * Handle the cancel button.
      */
+    @Override
     public void onClick(View view) {
         switch(view.getId()) {
             case R.id.button:
@@ -423,8 +427,14 @@
         mLogger.textModifiedByTypingDeletion(length);
     }
 
-    public void logTextModifiedByChooseSuggestion(int length) {
-        mLogger.textModifiedByChooseSuggestion(length);
+    public void logTextModifiedByChooseSuggestion(String suggestion, int index,
+                                                  String wordSeparators, InputConnection ic) {
+        EditingUtil.Range range = new EditingUtil.Range();
+        String wordToBeReplaced = EditingUtil.getWordAtCursor(ic, wordSeparators, range);
+        // If we enable phrase-based alternatives, only send up the first word
+        // in suggestion and wordToBeReplaced.
+        mLogger.textModifiedByChooseSuggestion(suggestion.length(), wordToBeReplaced.length(),
+                                               index, wordToBeReplaced, suggestion);
     }
 
     public void logKeyboardWarningDialogShown() {
@@ -455,10 +465,6 @@
         mLogger.voiceInputDelivered(length);
     }
 
-    public void logNBestChoose(int index) {
-        mLogger.nBestChoose(index);
-    }
-
     public void logInputEnded() {
         mLogger.inputEnded();
     }
@@ -552,36 +558,43 @@
         int mSpeechStart;
         private boolean mEndpointed = false;
 
+        @Override
         public void onReadyForSpeech(Bundle noiseParams) {
             mRecognitionView.showListening();
         }
 
+        @Override
         public void onBeginningOfSpeech() {
             mEndpointed = false;
             mSpeechStart = mWaveBuffer.size();
         }
 
+        @Override
         public void onRmsChanged(float rmsdB) {
             mRecognitionView.updateVoiceMeter(rmsdB);
         }
 
+        @Override
         public void onBufferReceived(byte[] buf) {
             try {
                 mWaveBuffer.write(buf);
             } catch (IOException e) {}
         }
 
+        @Override
         public void onEndOfSpeech() {
             mEndpointed = true;
             mState = WORKING;
             mRecognitionView.showWorking(mWaveBuffer, mSpeechStart, mWaveBuffer.size());
         }
 
+        @Override
         public void onError(int errorType) {
             mState = ERROR;
             VoiceInput.this.onError(errorType, mEndpointed);
         }
 
+        @Override
         public void onResults(Bundle resultsBundle) {
             List<String> results = resultsBundle
                     .getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
@@ -634,10 +647,12 @@
             mRecognitionView.finish();
         }
 
+        @Override
         public void onPartialResults(final Bundle partialResults) {
             // currently - do nothing
         }
 
+        @Override
         public void onEvent(int eventType, Bundle params) {
             // do nothing - reserved for events that might be added in the future
         }
diff --git a/java/src/com/android/inputmethod/voice/VoiceInputLogger.java b/java/src/com/android/inputmethod/voice/VoiceInputLogger.java
index 188d137..3e65434 100644
--- a/java/src/com/android/inputmethod/voice/VoiceInputLogger.java
+++ b/java/src/com/android/inputmethod/voice/VoiceInputLogger.java
@@ -31,6 +31,7 @@
  * on on the VoiceSearch side.
  */
 public class VoiceInputLogger {
+    @SuppressWarnings("unused")
     private static final String TAG = VoiceInputLogger.class.getSimpleName();
 
     private static VoiceInputLogger sVoiceInputLogger;
@@ -205,22 +206,22 @@
         mContext.sendBroadcast(i);
     }
 
-    public void textModifiedByChooseSuggestion(int length) {
+
+    public void textModifiedByChooseSuggestion(int suggestionLength, int replacedPhraseLength,
+                                               int index, String before, String after) {
         setHasLoggingInfo(true);
         Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.TEXT_MODIFIED);
-        i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, length);
+        i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_LENGTH, suggestionLength);
+        i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_REPLACED_LENGTH, replacedPhraseLength);
         i.putExtra(LoggingEvents.VoiceIme.EXTRA_TEXT_MODIFIED_TYPE,
                 LoggingEvents.VoiceIme.TEXT_MODIFIED_TYPE_CHOOSE_SUGGESTION);
+
+        i.putExtra(LoggingEvents.VoiceIme.EXTRA_N_BEST_CHOOSE_INDEX, index);
+        i.putExtra(LoggingEvents.VoiceIme.EXTRA_BEFORE_N_BEST_CHOOSE, before);
+        i.putExtra(LoggingEvents.VoiceIme.EXTRA_AFTER_N_BEST_CHOOSE, after);
         mContext.sendBroadcast(i);
     }
 
-    public void nBestChoose(int index) {
-        setHasLoggingInfo(true);
-        Intent i = newLoggingBroadcast(LoggingEvents.VoiceIme.N_BEST_CHOOSE);
-        i.putExtra(LoggingEvents.VoiceIme.EXTRA_N_BEST_CHOOSE_INDEX, index);
-        mContext.sendBroadcast(i);
-    }
-    
     public void inputEnded() {
         setHasLoggingInfo(true);
         mContext.sendBroadcast(newLoggingBroadcast(LoggingEvents.VoiceIme.INPUT_ENDED));
diff --git a/java/src/com/android/inputmethod/voice/Whitelist.java b/java/src/com/android/inputmethod/voice/Whitelist.java
index 167b688..f4c24de 100644
--- a/java/src/com/android/inputmethod/voice/Whitelist.java
+++ b/java/src/com/android/inputmethod/voice/Whitelist.java
@@ -17,6 +17,7 @@
 package com.android.inputmethod.voice;
 
 import android.os.Bundle;
+
 import java.util.ArrayList;
 import java.util.List;
 
diff --git a/native/Android.mk b/native/Android.mk
index b294469..bbbff1e 100644
--- a/native/Android.mk
+++ b/native/Android.mk
@@ -4,15 +4,28 @@
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/src
 
 LOCAL_SRC_FILES := \
-	jni/com_android_inputmethod_latin_BinaryDictionary.cpp \
-	src/dictionary.cpp \
-	src/char_utils.cpp
+    jni/com_android_inputmethod_latin_BinaryDictionary.cpp \
+    src/bigram_dictionary.cpp \
+    src/char_utils.cpp \
+    src/dictionary.cpp \
+    src/unigram_dictionary.cpp
 
-LOCAL_NDK_VERSION := 4
+#FLAG_DBG := true
+
+ifneq ($(FLAG_DBG), true)
+    LOCAL_NDK_VERSION := 4
+endif
+
 LOCAL_SDK_VERSION := 8
 
 LOCAL_MODULE := libjni_latinime
 
 LOCAL_MODULE_TAGS := user
 
+ifeq ($(FLAG_DBG), true)
+    $(warning "Making debug build.")
+    LOCAL_CFLAGS += -DFLAG_DBG
+    LOCAL_SHARED_LIBRARIES := libcutils libutils
+endif
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index bf7ec0d..9948448 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -15,13 +15,11 @@
 ** limitations under the License.
 */
 
-#include <stdio.h>
-#include <assert.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <jni.h>
 #include "dictionary.h"
+#include "jni.h"
+
+#include <assert.h>
+#include <stdio.h>
 
 // ----------------------------------------------------------------------------
 
@@ -30,8 +28,7 @@
 //
 // helper function to throw an exception
 //
-static void throwException(JNIEnv *env, const char* ex, const char* fmt, int data)
-{
+static void throwException(JNIEnv *env, const char* ex, const char* fmt, int data) {
     if (jclass cls = env->FindClass(ex)) {
         char msg[1000];
         sprintf(msg, fmt, data);
@@ -40,24 +37,22 @@
     }
 }
 
-static jint latinime_BinaryDictionary_open
-        (JNIEnv *env, jobject object, jobject dictDirectBuffer,
-         jint typedLetterMultiplier, jint fullWordMultiplier)
-{
+static jint latinime_BinaryDictionary_open(JNIEnv *env, jobject object, jobject dictDirectBuffer,
+        jint typedLetterMultiplier, jint fullWordMultiplier, jint maxWordLength, jint maxWords,
+        jint maxAlternatives) {
     void *dict = env->GetDirectBufferAddress(dictDirectBuffer);
     if (dict == NULL) {
         fprintf(stderr, "DICT: Dictionary buffer is null\n");
         return 0;
     }
-    Dictionary *dictionary = new Dictionary(dict, typedLetterMultiplier, fullWordMultiplier);
+    Dictionary *dictionary = new Dictionary(dict, typedLetterMultiplier, fullWordMultiplier,
+            maxWordLength, maxWords, maxAlternatives);
     return (jint) dictionary;
 }
 
-static int latinime_BinaryDictionary_getSuggestions(
-        JNIEnv *env, jobject object, jint dict, jintArray inputArray, jint arraySize,
-        jcharArray outputArray, jintArray frequencyArray, jint maxWordLength, jint maxWords,
-        jint maxAlternatives, jint skipPos, jintArray nextLettersArray, jint nextLettersSize)
-{
+static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jint dict,
+        jintArray inputArray, jint arraySize, jcharArray outputArray, jintArray frequencyArray,
+        jintArray nextLettersArray, jint nextLettersSize) {
     Dictionary *dictionary = (Dictionary*) dict;
     if (dictionary == NULL) return 0;
 
@@ -68,8 +63,7 @@
             : NULL;
 
     int count = dictionary->getSuggestions(inputCodes, arraySize, (unsigned short*) outputChars,
-            frequencies, maxWordLength, maxWords, maxAlternatives, skipPos, nextLetters,
-            nextLettersSize);
+            frequencies, nextLetters, nextLettersSize);
 
     env->ReleaseIntArrayElements(frequencyArray, frequencies, 0);
     env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT);
@@ -81,11 +75,10 @@
     return count;
 }
 
-static int latinime_BinaryDictionary_getBigrams
-        (JNIEnv *env, jobject object, jint dict, jcharArray prevWordArray, jint prevWordLength,
-         jintArray inputArray, jint inputArraySize, jcharArray outputArray,
-         jintArray frequencyArray, jint maxWordLength, jint maxBigrams, jint maxAlternatives)
-{
+static int latinime_BinaryDictionary_getBigrams(JNIEnv *env, jobject object, jint dict,
+        jcharArray prevWordArray, jint prevWordLength, jintArray inputArray, jint inputArraySize,
+        jcharArray outputArray, jintArray frequencyArray, jint maxWordLength, jint maxBigrams,
+        jint maxAlternatives) {
     Dictionary *dictionary = (Dictionary*) dict;
     if (dictionary == NULL) return 0;
 
@@ -107,9 +100,8 @@
 }
 
 
-static jboolean latinime_BinaryDictionary_isValidWord
-        (JNIEnv *env, jobject object, jint dict, jcharArray wordArray, jint wordLength)
-{
+static jboolean latinime_BinaryDictionary_isValidWord(JNIEnv *env, jobject object, jint dict,
+        jcharArray wordArray, jint wordLength) {
     Dictionary *dictionary = (Dictionary*) dict;
     if (dictionary == NULL) return (jboolean) false;
 
@@ -120,33 +112,27 @@
     return result;
 }
 
-static void latinime_BinaryDictionary_close
-        (JNIEnv *env, jobject object, jint dict)
-{
-    Dictionary *dictionary = (Dictionary*) dict;
+static void latinime_BinaryDictionary_close(JNIEnv *env, jobject object, jint dict) {
     delete (Dictionary*) dict;
 }
 
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
-    {"openNative",           "(Ljava/nio/ByteBuffer;II)I",
-                                          (void*)latinime_BinaryDictionary_open},
-    {"closeNative",          "(I)V",            (void*)latinime_BinaryDictionary_close},
-    {"getSuggestionsNative", "(I[II[C[IIIII[II)I",  (void*)latinime_BinaryDictionary_getSuggestions},
-    {"isValidWordNative",    "(I[CI)Z",         (void*)latinime_BinaryDictionary_isValidWord},
-    {"getBigramsNative",    "(I[CI[II[C[IIII)I",         (void*)latinime_BinaryDictionary_getBigrams}
+    {"openNative", "(Ljava/nio/ByteBuffer;IIIII)I", (void*)latinime_BinaryDictionary_open},
+    {"closeNative", "(I)V", (void*)latinime_BinaryDictionary_close},
+    {"getSuggestionsNative", "(I[II[C[I[II)I", (void*)latinime_BinaryDictionary_getSuggestions},
+    {"isValidWordNative", "(I[CI)Z", (void*)latinime_BinaryDictionary_isValidWord},
+    {"getBigramsNative", "(I[CI[II[C[IIII)I", (void*)latinime_BinaryDictionary_getBigrams}
 };
 
-static int registerNativeMethods(JNIEnv* env, const char* className,
-    JNINativeMethod* gMethods, int numMethods)
-{
+static int registerNativeMethods(JNIEnv* env, const char* className, JNINativeMethod* gMethods,
+        int numMethods) {
     jclass clazz;
 
     clazz = env->FindClass(className);
     if (clazz == NULL) {
-        fprintf(stderr,
-            "Native registration unable to find class '%s'\n", className);
+        fprintf(stderr, "Native registration unable to find class '%s'\n", className);
         return JNI_FALSE;
     }
     if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
@@ -157,18 +143,16 @@
     return JNI_TRUE;
 }
 
-static int registerNatives(JNIEnv *env)
-{
+static int registerNatives(JNIEnv *env) {
     const char* const kClassPathName = "com/android/inputmethod/latin/BinaryDictionary";
-    return registerNativeMethods(env,
-            kClassPathName, gMethods, sizeof(gMethods) / sizeof(gMethods[0]));
+    return registerNativeMethods(env, kClassPathName, gMethods,
+            sizeof(gMethods) / sizeof(gMethods[0]));
 }
 
 /*
  * Returns the JNI version on success, -1 on failure.
  */
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
-{
+jint JNI_OnLoad(JavaVM* vm, void* reserved) {
     JNIEnv* env = NULL;
     jint result = -1;
 
diff --git a/native/src/bigram_dictionary.cpp b/native/src/bigram_dictionary.cpp
new file mode 100644
index 0000000..095b805
--- /dev/null
+++ b/native/src/bigram_dictionary.cpp
@@ -0,0 +1,254 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include <string.h>
+
+#define LOG_TAG "LatinIME: bigram_dictionary.cpp"
+
+#include "bigram_dictionary.h"
+#include "dictionary.h"
+
+namespace latinime {
+
+BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength,
+        int maxAlternatives, const bool isLatestDictVersion, const bool hasBigram,
+        Dictionary *parentDictionary)
+    : DICT(dict), MAX_WORD_LENGTH(maxWordLength),
+    MAX_ALTERNATIVES(maxAlternatives), IS_LATEST_DICT_VERSION(isLatestDictVersion),
+    HAS_BIGRAM(hasBigram), mParentDictionary(parentDictionary) {
+    LOGI("BigramDictionary - constructor");
+    LOGI("Has Bigram : %d \n", hasBigram);
+}
+
+BigramDictionary::~BigramDictionary() {
+}
+
+bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequency) {
+    word[length] = 0;
+    if (DEBUG_DICT) {
+        char s[length + 1];
+        for (int i = 0; i <= length; i++) s[i] = word[i];
+        LOGI("Bigram: Found word = %s, freq = %d : \n", s, frequency);
+    }
+
+    // Find the right insertion point
+    int insertAt = 0;
+    while (insertAt < mMaxBigrams) {
+        if (frequency > mBigramFreq[insertAt] || (mBigramFreq[insertAt] == frequency
+                && length < Dictionary::wideStrLen(mBigramChars + insertAt * MAX_WORD_LENGTH))) {
+            break;
+        }
+        insertAt++;
+    }
+    LOGI("Bigram: InsertAt -> %d maxBigrams: %d\n", insertAt, mMaxBigrams);
+    if (insertAt < mMaxBigrams) {
+        memmove((char*) mBigramFreq + (insertAt + 1) * sizeof(mBigramFreq[0]),
+               (char*) mBigramFreq + insertAt * sizeof(mBigramFreq[0]),
+               (mMaxBigrams - insertAt - 1) * sizeof(mBigramFreq[0]));
+        mBigramFreq[insertAt] = frequency;
+        memmove((char*) mBigramChars + (insertAt + 1) * MAX_WORD_LENGTH * sizeof(short),
+               (char*) mBigramChars + (insertAt    ) * MAX_WORD_LENGTH * sizeof(short),
+               (mMaxBigrams - insertAt - 1) * sizeof(short) * MAX_WORD_LENGTH);
+        unsigned short *dest = mBigramChars + (insertAt    ) * MAX_WORD_LENGTH;
+        while (length--) {
+            *dest++ = *word++;
+        }
+        *dest = 0; // NULL terminate
+        if (DEBUG_DICT) LOGI("Bigram: Added word at %d\n", insertAt);
+        return true;
+    }
+    return false;
+}
+
+int BigramDictionary::getBigramAddress(int *pos, bool advance) {
+    int address = 0;
+
+    address += (DICT[*pos] & 0x3F) << 16;
+    address += (DICT[*pos + 1] & 0xFF) << 8;
+    address += (DICT[*pos + 2] & 0xFF);
+
+    if (advance) {
+        *pos += 3;
+    }
+
+    return address;
+}
+
+int BigramDictionary::getBigramFreq(int *pos) {
+    int freq = DICT[(*pos)++] & FLAG_BIGRAM_FREQ;
+
+    return freq;
+}
+
+
+int BigramDictionary::getBigrams(unsigned short *prevWord, int prevWordLength, int *codes,
+        int codesSize, unsigned short *bigramChars, int *bigramFreq, int maxWordLength,
+        int maxBigrams, int maxAlternatives) {
+    mBigramFreq = bigramFreq;
+    mBigramChars = bigramChars;
+    mInputCodes = codes;
+    mInputLength = codesSize;
+    mMaxBigrams = maxBigrams;
+
+    if (HAS_BIGRAM && IS_LATEST_DICT_VERSION) {
+        int pos = mParentDictionary->isValidWordRec(
+                DICTIONARY_HEADER_SIZE, prevWord, 0, prevWordLength);
+        LOGI("Pos -> %d\n", pos);
+        if (pos < 0) {
+            return 0;
+        }
+
+        int bigramCount = 0;
+        int bigramExist = (DICT[pos] & FLAG_BIGRAM_READ);
+        if (bigramExist > 0) {
+            int nextBigramExist = 1;
+            while (nextBigramExist > 0 && bigramCount < maxBigrams) {
+                int bigramAddress = getBigramAddress(&pos, true);
+                int frequency = (FLAG_BIGRAM_FREQ & DICT[pos]);
+                // search for all bigrams and store them
+                searchForTerminalNode(bigramAddress, frequency);
+                nextBigramExist = (DICT[pos++] & FLAG_BIGRAM_CONTINUED);
+                bigramCount++;
+            }
+        }
+
+        return bigramCount;
+    }
+    return 0;
+}
+
+void BigramDictionary::searchForTerminalNode(int addressLookingFor, int frequency) {
+    // track word with such address and store it in an array
+    unsigned short word[MAX_WORD_LENGTH];
+
+    int pos;
+    int followDownBranchAddress = DICTIONARY_HEADER_SIZE;
+    bool found = false;
+    char followingChar = ' ';
+    int depth = -1;
+
+    while(!found) {
+        bool followDownAddressSearchStop = false;
+        bool firstAddress = true;
+        bool haveToSearchAll = true;
+
+        if (depth >= 0) {
+            word[depth] = (unsigned short) followingChar;
+        }
+        pos = followDownBranchAddress; // pos start at count
+        int count = DICT[pos] & 0xFF;
+        LOGI("count - %d\n",count);
+        pos++;
+        for (int i = 0; i < count; i++) {
+            // pos at data
+            pos++;
+            // pos now at flag
+            if (!getFirstBitOfByte(&pos)) { // non-terminal
+                if (!followDownAddressSearchStop) {
+                    int addr = getBigramAddress(&pos, false);
+                    if (addr > addressLookingFor) {
+                        followDownAddressSearchStop = true;
+                        if (firstAddress) {
+                            firstAddress = false;
+                            haveToSearchAll = true;
+                        } else if (!haveToSearchAll) {
+                            break;
+                        }
+                    } else {
+                        followDownBranchAddress = addr;
+                        followingChar = (char)(0xFF & DICT[pos-1]);
+                        if (firstAddress) {
+                            firstAddress = false;
+                            haveToSearchAll = false;
+                        }
+                    }
+                }
+                pos += 3;
+            } else if (getFirstBitOfByte(&pos)) { // terminal
+                if (addressLookingFor == (pos-1)) { // found !!
+                    depth++;
+                    word[depth] = (0xFF & DICT[pos-1]);
+                    found = true;
+                    break;
+                }
+                if (getSecondBitOfByte(&pos)) { // address + freq (4 byte)
+                    if (!followDownAddressSearchStop) {
+                        int addr = getBigramAddress(&pos, false);
+                        if (addr > addressLookingFor) {
+                            followDownAddressSearchStop = true;
+                            if (firstAddress) {
+                                firstAddress = false;
+                                haveToSearchAll = true;
+                            } else if (!haveToSearchAll) {
+                                break;
+                            }
+                        } else {
+                            followDownBranchAddress = addr;
+                            followingChar = (char)(0xFF & DICT[pos-1]);
+                            if (firstAddress) {
+                                firstAddress = false;
+                                haveToSearchAll = true;
+                            }
+                        }
+                    }
+                    pos += 4;
+                } else { // freq only (2 byte)
+                    pos += 2;
+                }
+
+                // skipping bigram
+                int bigramExist = (DICT[pos] & FLAG_BIGRAM_READ);
+                if (bigramExist > 0) {
+                    int nextBigramExist = 1;
+                    while (nextBigramExist > 0) {
+                        pos += 3;
+                        nextBigramExist = (DICT[pos++] & FLAG_BIGRAM_CONTINUED);
+                    }
+                } else {
+                    pos++;
+                }
+            }
+        }
+        depth++;
+        if (followDownBranchAddress == 0) {
+            LOGI("ERROR!!! Cannot find bigram!!");
+            break;
+        }
+    }
+    if (checkFirstCharacter(word)) {
+        addWordBigram(word, depth, frequency);
+    }
+}
+
+bool BigramDictionary::checkFirstCharacter(unsigned short *word) {
+    // Checks whether this word starts with same character or neighboring characters of
+    // what user typed.
+
+    int *inputCodes = mInputCodes;
+    int maxAlt = MAX_ALTERNATIVES;
+    while (maxAlt > 0) {
+        if ((unsigned int) *inputCodes == (unsigned int) *word) {
+            return true;
+        }
+        inputCodes++;
+        maxAlt--;
+    }
+    return false;
+}
+
+// TODO: Move functions related to bigram to here
+} // namespace latinime
diff --git a/native/src/bigram_dictionary.h b/native/src/bigram_dictionary.h
new file mode 100644
index 0000000..d658b93
--- /dev/null
+++ b/native/src/bigram_dictionary.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#ifndef LATINIME_BIGRAM_DICTIONARY_H
+#define LATINIME_BIGRAM_DICTIONARY_H
+
+namespace latinime {
+
+class Dictionary;
+class BigramDictionary {
+public:
+    BigramDictionary(const unsigned char *dict, int maxWordLength, int maxAlternatives,
+            const bool isLatestDictVersion, const bool hasBigram, Dictionary *parentDictionary);
+    int getBigrams(unsigned short *word, int length, int *codes, int codesSize,
+            unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams,
+            int maxAlternatives);
+    ~BigramDictionary();
+private:
+    bool addWordBigram(unsigned short *word, int length, int frequency);
+    int getBigramAddress(int *pos, bool advance);
+    int getBigramFreq(int *pos);
+    void searchForTerminalNode(int addressLookingFor, int frequency);
+    bool getFirstBitOfByte(int *pos) { return (DICT[*pos] & 0x80) > 0; }
+    bool getSecondBitOfByte(int *pos) { return (DICT[*pos] & 0x40) > 0; }
+    bool checkFirstCharacter(unsigned short *word);
+
+    const unsigned char *DICT;
+    const int MAX_WORD_LENGTH;
+    const int MAX_ALTERNATIVES;
+    const bool IS_LATEST_DICT_VERSION;
+    const bool HAS_BIGRAM;
+
+    Dictionary *mParentDictionary;
+    int *mBigramFreq;
+    int mMaxBigrams;
+    unsigned short *mBigramChars;
+    int *mInputCodes;
+    int mInputLength;
+};
+// ----------------------------------------------------------------------------
+}; // namespace latinime
+#endif // LATINIME_BIGRAM_DICTIONARY_H
diff --git a/native/src/defines.h b/native/src/defines.h
new file mode 100644
index 0000000..953905f
--- /dev/null
+++ b/native/src/defines.h
@@ -0,0 +1,57 @@
+/*
+**
+** Copyright 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.
+*/
+
+#ifndef LATINIME_DEFINES_H
+#define LATINIME_DEFINES_H
+
+#ifdef FLAG_DBG
+#include <cutils/log.h>
+#ifndef LOG_TAG
+#define LOG_TAG "LatinIME: "
+#endif
+#define DEBUG_DICT 1
+#else // FLAG_DBG
+#define LOGI
+#define DEBUG_DICT 0
+#endif // FLAG_DBG
+
+// 22-bit address = ~4MB dictionary size limit, which on average would be about 200k-300k words
+#define ADDRESS_MASK 0x3FFFFF
+
+// The bit that decides if an address follows in the next 22 bits
+#define FLAG_ADDRESS_MASK 0x40
+// The bit that decides if this is a terminal node for a word. The node could still have children,
+// if the word has other endings.
+#define FLAG_TERMINAL_MASK 0x80
+
+#define FLAG_BIGRAM_READ 0x80
+#define FLAG_BIGRAM_CHILDEXIST 0x40
+#define FLAG_BIGRAM_CONTINUED 0x80
+#define FLAG_BIGRAM_FREQ 0x7F
+
+#define DICTIONARY_VERSION_MIN 200
+#define DICTIONARY_HEADER_SIZE 2
+#define NOT_VALID_WORD -99
+
+#define SUGGEST_MISSING_CHARACTERS true
+#define SUGGEST_MISSING_CHARACTERS_THRESHOLD 5
+
+#define MAX_WORD_LENGTH_INTERNAL 64
+
+#define MAX_DEPTH_MULTIPLIER 3
+
+#endif // LATINIME_DEFINES_H
diff --git a/native/src/dictionary.cpp b/native/src/dictionary.cpp
index 1a39f585b4..6936dc9 100644
--- a/native/src/dictionary.cpp
+++ b/native/src/dictionary.cpp
@@ -16,559 +16,59 @@
 */
 
 #include <stdio.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <string.h>
-//#define LOG_TAG "dictionary.cpp"
-//#include <cutils/log.h>
-#define LOGI
+
+#define LOG_TAG "LatinIME: dictionary.cpp"
 
 #include "dictionary.h"
-#include "basechars.h"
-#include "char_utils.h"
-
-#define DEBUG_DICT 0
-#define DICTIONARY_VERSION_MIN 200
-#define DICTIONARY_HEADER_SIZE 2
-#define NOT_VALID_WORD -99
 
 namespace latinime {
 
-Dictionary::Dictionary(void *dict, int typedLetterMultiplier, int fullWordMultiplier)
+Dictionary::Dictionary(void *dict, int typedLetterMultiplier, int fullWordMultiplier,
+        int maxWordLength, int maxWords, int maxAlternatives)
+    : DICT((unsigned char*) dict),
+    // Checks whether it has the latest dictionary or the old dictionary
+    IS_LATEST_DICT_VERSION((((unsigned char*) dict)[0] & 0xFF) >= DICTIONARY_VERSION_MIN)
 {
-    mDict = (unsigned char*) dict;
-    mTypedLetterMultiplier = typedLetterMultiplier;
-    mFullWordMultiplier = fullWordMultiplier;
-    getVersionNumber();
+    if (MAX_WORD_LENGTH_INTERNAL < maxWordLength) {
+        LOGI("Max word length (%d) is greater than %d", maxWordLength, MAX_WORD_LENGTH_INTERNAL);
+    }
+    LOGI("IN NATIVE SUGGEST Version: %d \n", (DICT[0] & 0xFF));
+    mUnigramDictionary = new UnigramDictionary(DICT, typedLetterMultiplier, fullWordMultiplier,
+            maxWordLength, maxWords, maxAlternatives, IS_LATEST_DICT_VERSION);
+    mBigramDictionary = new BigramDictionary(DICT, maxWordLength, maxAlternatives,
+            IS_LATEST_DICT_VERSION, hasBigram(), this);
 }
 
 Dictionary::~Dictionary()
 {
+    delete mUnigramDictionary;
+    delete mBigramDictionary;
 }
 
-int Dictionary::getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies,
-        int maxWordLength, int maxWords, int maxAlternatives, int skipPos,
-        int *nextLetters, int nextLettersSize)
+bool Dictionary::hasBigram() {
+    return ((DICT[1] & 0xFF) == 1);
+}
+
+// TODO: use uint16_t instead of unsigned short
+bool Dictionary::isValidWord(unsigned short *word, int length)
 {
-    int suggWords;
-    mFrequencies = frequencies;
-    mOutputChars = outWords;
-    mInputCodes = codes;
-    mInputLength = codesSize;
-    mMaxAlternatives = maxAlternatives;
-    mMaxWordLength = maxWordLength;
-    mMaxWords = maxWords;
-    mSkipPos = skipPos;
-    mMaxEditDistance = mInputLength < 5 ? 2 : mInputLength / 2;
-    mNextLettersFrequencies = nextLetters;
-    mNextLettersSize = nextLettersSize;
-
-    if (checkIfDictVersionIsLatest()) {
-        getWordsRec(DICTIONARY_HEADER_SIZE, 0, mInputLength * 3, false, 1, 0, 0);
-    } else {
-        getWordsRec(0, 0, mInputLength * 3, false, 1, 0, 0);
-    }
-
-    // Get the word count
-    suggWords = 0;
-    while (suggWords < mMaxWords && mFrequencies[suggWords] > 0) suggWords++;
-    if (DEBUG_DICT) LOGI("Returning %d words", suggWords);
-
-    if (DEBUG_DICT) {
-        LOGI("Next letters: ");
-        for (int k = 0; k < nextLettersSize; k++) {
-            if (mNextLettersFrequencies[k] > 0) {
-                LOGI("%c = %d,", k, mNextLettersFrequencies[k]);
-            }
-        }
-        LOGI("\n");
-    }
-    return suggWords;
-}
-
-void
-Dictionary::registerNextLetter(unsigned short c)
-{
-    if (c < mNextLettersSize) {
-        mNextLettersFrequencies[c]++;
-    }
-}
-
-void
-Dictionary::getVersionNumber()
-{
-    mVersion = (mDict[0] & 0xFF);
-    mBigram = (mDict[1] & 0xFF);
-    LOGI("IN NATIVE SUGGEST Version: %d Bigram : %d \n", mVersion, mBigram);
-}
-
-// Checks whether it has the latest dictionary or the old dictionary
-bool
-Dictionary::checkIfDictVersionIsLatest()
-{
-    return (mVersion >= DICTIONARY_VERSION_MIN) && (mBigram == 1 || mBigram == 0);
-}
-
-unsigned short
-Dictionary::getChar(int *pos)
-{
-    unsigned short ch = (unsigned short) (mDict[(*pos)++] & 0xFF);
-    // If the code is 255, then actual 16 bit code follows (in big endian)
-    if (ch == 0xFF) {
-        ch = ((mDict[*pos] & 0xFF) << 8) | (mDict[*pos + 1] & 0xFF);
-        (*pos) += 2;
-    }
-    return ch;
-}
-
-int
-Dictionary::getAddress(int *pos)
-{
-    int address = 0;
-    if ((mDict[*pos] & FLAG_ADDRESS_MASK) == 0) {
-        *pos += 1;
-    } else {
-        address += (mDict[*pos] & (ADDRESS_MASK >> 16)) << 16;
-        address += (mDict[*pos + 1] & 0xFF) << 8;
-        address += (mDict[*pos + 2] & 0xFF);
-        *pos += 3;
-    }
-    return address;
-}
-
-int
-Dictionary::getFreq(int *pos)
-{
-    int freq = mDict[(*pos)++] & 0xFF;
-
-    if (checkIfDictVersionIsLatest()) {
-        // skipping bigram
-        int bigramExist = (mDict[*pos] & FLAG_BIGRAM_READ);
-        if (bigramExist > 0) {
-            int nextBigramExist = 1;
-            while (nextBigramExist > 0) {
-                (*pos) += 3;
-                nextBigramExist = (mDict[(*pos)++] & FLAG_BIGRAM_CONTINUED);
-            }
-        } else {
-            (*pos)++;
-        }
-    }
-
-    return freq;
-}
-
-int
-Dictionary::wideStrLen(unsigned short *str)
-{
-    if (!str) return 0;
-    unsigned short *end = str;
-    while (*end)
-        end++;
-    return end - str;
-}
-
-bool
-Dictionary::addWord(unsigned short *word, int length, int frequency)
-{
-    word[length] = 0;
-    if (DEBUG_DICT) {
-        char s[length + 1];
-        for (int i = 0; i <= length; i++) s[i] = word[i];
-        LOGI("Found word = %s, freq = %d : \n", s, frequency);
-    }
-
-    // Find the right insertion point
-    int insertAt = 0;
-    while (insertAt < mMaxWords) {
-        if (frequency > mFrequencies[insertAt]
-                 || (mFrequencies[insertAt] == frequency
-                     && length < wideStrLen(mOutputChars + insertAt * mMaxWordLength))) {
-            break;
-        }
-        insertAt++;
-    }
-    if (insertAt < mMaxWords) {
-        memmove((char*) mFrequencies + (insertAt + 1) * sizeof(mFrequencies[0]),
-               (char*) mFrequencies + insertAt * sizeof(mFrequencies[0]),
-               (mMaxWords - insertAt - 1) * sizeof(mFrequencies[0]));
-        mFrequencies[insertAt] = frequency;
-        memmove((char*) mOutputChars + (insertAt + 1) * mMaxWordLength * sizeof(short),
-               (char*) mOutputChars + (insertAt    ) * mMaxWordLength * sizeof(short),
-               (mMaxWords - insertAt - 1) * sizeof(short) * mMaxWordLength);
-        unsigned short *dest = mOutputChars + (insertAt    ) * mMaxWordLength;
-        while (length--) {
-            *dest++ = *word++;
-        }
-        *dest = 0; // NULL terminate
-        if (DEBUG_DICT) LOGI("Added word at %d\n", insertAt);
-        return true;
-    }
-    return false;
-}
-
-bool
-Dictionary::addWordBigram(unsigned short *word, int length, int frequency)
-{
-    word[length] = 0;
-    if (DEBUG_DICT) {
-        char s[length + 1];
-        for (int i = 0; i <= length; i++) s[i] = word[i];
-        LOGI("Bigram: Found word = %s, freq = %d : \n", s, frequency);
-    }
-
-    // Find the right insertion point
-    int insertAt = 0;
-    while (insertAt < mMaxBigrams) {
-        if (frequency > mBigramFreq[insertAt]
-                 || (mBigramFreq[insertAt] == frequency
-                     && length < wideStrLen(mBigramChars + insertAt * mMaxWordLength))) {
-            break;
-        }
-        insertAt++;
-    }
-    LOGI("Bigram: InsertAt -> %d maxBigrams: %d\n", insertAt, mMaxBigrams);
-    if (insertAt < mMaxBigrams) {
-        memmove((char*) mBigramFreq + (insertAt + 1) * sizeof(mBigramFreq[0]),
-               (char*) mBigramFreq + insertAt * sizeof(mBigramFreq[0]),
-               (mMaxBigrams - insertAt - 1) * sizeof(mBigramFreq[0]));
-        mBigramFreq[insertAt] = frequency;
-        memmove((char*) mBigramChars + (insertAt + 1) * mMaxWordLength * sizeof(short),
-               (char*) mBigramChars + (insertAt    ) * mMaxWordLength * sizeof(short),
-               (mMaxBigrams - insertAt - 1) * sizeof(short) * mMaxWordLength);
-        unsigned short *dest = mBigramChars + (insertAt    ) * mMaxWordLength;
-        while (length--) {
-            *dest++ = *word++;
-        }
-        *dest = 0; // NULL terminate
-        if (DEBUG_DICT) LOGI("Bigram: Added word at %d\n", insertAt);
-        return true;
-    }
-    return false;
-}
-
-unsigned short
-Dictionary::toLowerCase(unsigned short c) {
-    if (c < sizeof(BASE_CHARS) / sizeof(BASE_CHARS[0])) {
-        c = BASE_CHARS[c];
-    }
-    if (c >='A' && c <= 'Z') {
-        c |= 32;
-    } else if (c > 127) {
-        c = latin_tolower(c);
-    }
-    return c;
-}
-
-bool
-Dictionary::sameAsTyped(unsigned short *word, int length)
-{
-    if (length != mInputLength) {
-        return false;
-    }
-    int *inputCodes = mInputCodes;
-    while (length--) {
-        if ((unsigned int) *inputCodes != (unsigned int) *word) {
-            return false;
-        }
-        inputCodes += mMaxAlternatives;
-        word++;
-    }
-    return true;
-}
-
-static char QUOTE = '\'';
-
-void
-Dictionary::getWordsRec(int pos, int depth, int maxDepth, bool completion, int snr, int inputIndex,
-                        int diffs)
-{
-    // Optimization: Prune out words that are too long compared to how much was typed.
-    if (depth > maxDepth) {
-        return;
-    }
-    if (diffs > mMaxEditDistance) {
-        return;
-    }
-    int count = getCount(&pos);
-    int *currentChars = NULL;
-    if (mInputLength <= inputIndex) {
-        completion = true;
-    } else {
-        currentChars = mInputCodes + (inputIndex * mMaxAlternatives);
-    }
-
-    for (int i = 0; i < count; i++) {
-        // -- at char
-        unsigned short c = getChar(&pos);
-        // -- at flag/add
-        unsigned short lowerC = toLowerCase(c);
-        bool terminal = getTerminal(&pos);
-        int childrenAddress = getAddress(&pos);
-        // -- after address or flag
-        int freq = 1;
-        if (terminal) freq = getFreq(&pos);
-        // -- after add or freq
-
-        // If we are only doing completions, no need to look at the typed characters.
-        if (completion) {
-            mWord[depth] = c;
-            if (terminal) {
-                addWord(mWord, depth + 1, freq * snr);
-                if (depth >= mInputLength && mSkipPos < 0) {
-                    registerNextLetter(mWord[mInputLength]);
-                }
-            }
-            if (childrenAddress != 0) {
-                getWordsRec(childrenAddress, depth + 1, maxDepth,
-                            completion, snr, inputIndex, diffs);
-            }
-        } else if ((c == QUOTE && currentChars[0] != QUOTE) || mSkipPos == depth) {
-            // Skip the ' or other letter and continue deeper
-            mWord[depth] = c;
-            if (childrenAddress != 0) {
-                getWordsRec(childrenAddress, depth + 1, maxDepth, false, snr, inputIndex, diffs);
-            }
-        } else {
-            int j = 0;
-            while (currentChars[j] > 0) {
-                if (currentChars[j] == lowerC || currentChars[j] == c) {
-                    int addedWeight = j == 0 ? mTypedLetterMultiplier : 1;
-                    mWord[depth] = c;
-                    if (mInputLength == inputIndex + 1) {
-                        if (terminal) {
-                            if (//INCLUDE_TYPED_WORD_IF_VALID ||
-                                !sameAsTyped(mWord, depth + 1)) {
-                                int finalFreq = freq * snr * addedWeight;
-                                if (mSkipPos < 0) finalFreq *= mFullWordMultiplier;
-                                addWord(mWord, depth + 1, finalFreq);
-                            }
-                        }
-                        if (childrenAddress != 0) {
-                            getWordsRec(childrenAddress, depth + 1,
-                                    maxDepth, true, snr * addedWeight, inputIndex + 1,
-                                    diffs + (j > 0));
-                        }
-                    } else if (childrenAddress != 0) {
-                        getWordsRec(childrenAddress, depth + 1, maxDepth,
-                                false, snr * addedWeight, inputIndex + 1, diffs + (j > 0));
-                    }
-                }
-                j++;
-                if (mSkipPos >= 0) break;
-            }
-        }
-    }
-}
-
-int
-Dictionary::getBigramAddress(int *pos, bool advance)
-{
-    int address = 0;
-
-    address += (mDict[*pos] & 0x3F) << 16;
-    address += (mDict[*pos + 1] & 0xFF) << 8;
-    address += (mDict[*pos + 2] & 0xFF);
-
-    if (advance) {
-        *pos += 3;
-    }
-
-    return address;
-}
-
-int
-Dictionary::getBigramFreq(int *pos)
-{
-    int freq = mDict[(*pos)++] & FLAG_BIGRAM_FREQ;
-
-    return freq;
-}
-
-
-int
-Dictionary::getBigrams(unsigned short *prevWord, int prevWordLength, int *codes, int codesSize,
-        unsigned short *bigramChars, int *bigramFreq, int maxWordLength, int maxBigrams,
-        int maxAlternatives)
-{
-    mBigramFreq = bigramFreq;
-    mBigramChars = bigramChars;
-    mInputCodes = codes;
-    mInputLength = codesSize;
-    mMaxWordLength = maxWordLength;
-    mMaxBigrams = maxBigrams;
-    mMaxAlternatives = maxAlternatives;
-
-    if (mBigram == 1 && checkIfDictVersionIsLatest()) {
-        int pos = isValidWordRec(DICTIONARY_HEADER_SIZE, prevWord, 0, prevWordLength);
-        LOGI("Pos -> %d\n", pos);
-        if (pos < 0) {
-            return 0;
-        }
-
-        int bigramCount = 0;
-        int bigramExist = (mDict[pos] & FLAG_BIGRAM_READ);
-        if (bigramExist > 0) {
-            int nextBigramExist = 1;
-            while (nextBigramExist > 0 && bigramCount < maxBigrams) {
-                int bigramAddress = getBigramAddress(&pos, true);
-                int frequency = (FLAG_BIGRAM_FREQ & mDict[pos]);
-                // search for all bigrams and store them
-                searchForTerminalNode(bigramAddress, frequency);
-                nextBigramExist = (mDict[pos++] & FLAG_BIGRAM_CONTINUED);
-                bigramCount++;
-            }
-        }
-
-        return bigramCount;
-    }
-    return 0;
-}
-
-void
-Dictionary::searchForTerminalNode(int addressLookingFor, int frequency)
-{
-    // track word with such address and store it in an array
-    unsigned short word[mMaxWordLength];
-
-    int pos;
-    int followDownBranchAddress = DICTIONARY_HEADER_SIZE;
-    bool found = false;
-    char followingChar = ' ';
-    int depth = -1;
-
-    while(!found) {
-        bool followDownAddressSearchStop = false;
-        bool firstAddress = true;
-        bool haveToSearchAll = true;
-
-        if (depth >= 0) {
-            word[depth] = (unsigned short) followingChar;
-        }
-        pos = followDownBranchAddress; // pos start at count
-        int count = mDict[pos] & 0xFF;
-        LOGI("count - %d\n",count);
-        pos++;
-        for (int i = 0; i < count; i++) {
-            // pos at data
-            pos++;
-            // pos now at flag
-            if (!getFirstBitOfByte(&pos)) { // non-terminal
-                if (!followDownAddressSearchStop) {
-                    int addr = getBigramAddress(&pos, false);
-                    if (addr > addressLookingFor) {
-                        followDownAddressSearchStop = true;
-                        if (firstAddress) {
-                            firstAddress = false;
-                            haveToSearchAll = true;
-                        } else if (!haveToSearchAll) {
-                            break;
-                        }
-                    } else {
-                        followDownBranchAddress = addr;
-                        followingChar = (char)(0xFF & mDict[pos-1]);
-                        if (firstAddress) {
-                            firstAddress = false;
-                            haveToSearchAll = false;
-                        }
-                    }
-                }
-                pos += 3;
-            } else if (getFirstBitOfByte(&pos)) { // terminal
-                if (addressLookingFor == (pos-1)) { // found !!
-                    depth++;
-                    word[depth] = (0xFF & mDict[pos-1]);
-                    found = true;
-                    break;
-                }
-                if (getSecondBitOfByte(&pos)) { // address + freq (4 byte)
-                    if (!followDownAddressSearchStop) {
-                        int addr = getBigramAddress(&pos, false);
-                        if (addr > addressLookingFor) {
-                            followDownAddressSearchStop = true;
-                            if (firstAddress) {
-                                firstAddress = false;
-                                haveToSearchAll = true;
-                            } else if (!haveToSearchAll) {
-                                break;
-                            }
-                        } else {
-                            followDownBranchAddress = addr;
-                            followingChar = (char)(0xFF & mDict[pos-1]);
-                            if (firstAddress) {
-                                firstAddress = false;
-                                haveToSearchAll = true;
-                            }
-                        }
-                    }
-                    pos += 4;
-                } else { // freq only (2 byte)
-                    pos += 2;
-                }
-
-                // skipping bigram
-                int bigramExist = (mDict[pos] & FLAG_BIGRAM_READ);
-                if (bigramExist > 0) {
-                    int nextBigramExist = 1;
-                    while (nextBigramExist > 0) {
-                        pos += 3;
-                        nextBigramExist = (mDict[pos++] & FLAG_BIGRAM_CONTINUED);
-                    }
-                } else {
-                    pos++;
-                }
-            }
-        }
-        depth++;
-        if (followDownBranchAddress == 0) {
-            LOGI("ERROR!!! Cannot find bigram!!");
-            break;
-        }
-    }
-    if (checkFirstCharacter(word)) {
-        addWordBigram(word, depth, frequency);
-    }
-}
-
-bool
-Dictionary::checkFirstCharacter(unsigned short *word)
-{
-    // Checks whether this word starts with same character or neighboring characters of
-    // what user typed.
-
-    int *inputCodes = mInputCodes;
-    int maxAlt = mMaxAlternatives;
-    while (maxAlt > 0) {
-        if ((unsigned int) *inputCodes == (unsigned int) *word) {
-            return true;
-        }
-        inputCodes++;
-        maxAlt--;
-    }
-    return false;
-}
-
-bool
-Dictionary::isValidWord(unsigned short *word, int length)
-{
-    if (checkIfDictVersionIsLatest()) {
+    if (IS_LATEST_DICT_VERSION) {
         return (isValidWordRec(DICTIONARY_HEADER_SIZE, word, 0, length) != NOT_VALID_WORD);
     } else {
         return (isValidWordRec(0, word, 0, length) != NOT_VALID_WORD);
     }
 }
 
-int
-Dictionary::isValidWordRec(int pos, unsigned short *word, int offset, int length) {
+int Dictionary::isValidWordRec(int pos, unsigned short *word, int offset, int length) {
     // returns address of bigram data of that word
     // return -99 if not found
 
-    int count = getCount(&pos);
+    int count = Dictionary::getCount(DICT, &pos);
     unsigned short currentChar = (unsigned short) word[offset];
     for (int j = 0; j < count; j++) {
-        unsigned short c = getChar(&pos);
-        int terminal = getTerminal(&pos);
-        int childPos = getAddress(&pos);
+        unsigned short c = Dictionary::getChar(DICT, &pos);
+        int terminal = Dictionary::getTerminal(DICT, &pos);
+        int childPos = Dictionary::getAddress(DICT, &pos);
         if (c == currentChar) {
             if (offset == length - 1) {
                 if (terminal) {
@@ -584,13 +84,11 @@
             }
         }
         if (terminal) {
-            getFreq(&pos);
+            Dictionary::getFreq(DICT, IS_LATEST_DICT_VERSION, &pos);
         }
         // There could be two instances of each alphabet - upper and lower case. So continue
         // looking ...
     }
     return NOT_VALID_WORD;
 }
-
-
 } // namespace latinime
diff --git a/native/src/dictionary.h b/native/src/dictionary.h
index d13496e..da87624 100644
--- a/native/src/dictionary.h
+++ b/native/src/dictionary.h
@@ -17,90 +17,134 @@
 #ifndef LATINIME_DICTIONARY_H
 #define LATINIME_DICTIONARY_H
 
+#include "bigram_dictionary.h"
+#include "defines.h"
+#include "unigram_dictionary.h"
+
 namespace latinime {
 
-// 22-bit address = ~4MB dictionary size limit, which on average would be about 200k-300k words
-#define ADDRESS_MASK 0x3FFFFF
-
-// The bit that decides if an address follows in the next 22 bits
-#define FLAG_ADDRESS_MASK 0x40
-// The bit that decides if this is a terminal node for a word. The node could still have children,
-// if the word has other endings.
-#define FLAG_TERMINAL_MASK 0x80
-
-#define FLAG_BIGRAM_READ 0x80
-#define FLAG_BIGRAM_CHILDEXIST 0x40
-#define FLAG_BIGRAM_CONTINUED 0x80
-#define FLAG_BIGRAM_FREQ 0x7F
-
 class Dictionary {
 public:
-    Dictionary(void *dict, int typedLetterMultipler, int fullWordMultiplier);
+    Dictionary(void *dict, int typedLetterMultipler, int fullWordMultiplier, int maxWordLength,
+            int maxWords, int maxAlternatives);
     int getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies,
-            int maxWordLength, int maxWords, int maxAlternatives, int skipPos,
-            int *nextLetters, int nextLettersSize);
+            int *nextLetters, int nextLettersSize) {
+        return mUnigramDictionary->getSuggestions(codes, codesSize, outWords, frequencies,
+                nextLetters, nextLettersSize);
+    }
+
+    // TODO: Call mBigramDictionary instead of mUnigramDictionary
     int getBigrams(unsigned short *word, int length, int *codes, int codesSize,
             unsigned short *outWords, int *frequencies, int maxWordLength, int maxBigrams,
-            int maxAlternatives);
+            int maxAlternatives) {
+        return mBigramDictionary->getBigrams(word, length, codes, codesSize, outWords, frequencies,
+                maxWordLength, maxBigrams, maxAlternatives);
+    }
     bool isValidWord(unsigned short *word, int length);
+    int isValidWordRec(int pos, unsigned short *word, int offset, int length);
     void setAsset(void *asset) { mAsset = asset; }
     void *getAsset() { return mAsset; }
     ~Dictionary();
 
+    // public static utility methods
+    // static inline methods should be defined in the header file
+    static unsigned short getChar(const unsigned char *dict, int *pos);
+    static int getCount(const unsigned char *dict, int *pos);
+    static bool getTerminal(const unsigned char *dict, int *pos);
+    static int getAddress(const unsigned char *dict, int *pos);
+    static int getFreq(const unsigned char *dict, const bool isLatestDictVersion, int *pos);
+    static int wideStrLen(unsigned short *str);
+    // returns next sibling's position
+    static int setDictionaryValues(const unsigned char *dict, const bool isLatestDictVersion,
+            const int pos, unsigned short *c, int *childrenPosition,
+            bool *terminal, int *freq);
+
 private:
+    bool hasBigram();
 
-    void getVersionNumber();
-    bool checkIfDictVersionIsLatest();
-    int getAddress(int *pos);
-    int getBigramAddress(int *pos, bool advance);
-    int getFreq(int *pos);
-    int getBigramFreq(int *pos);
-    void searchForTerminalNode(int address, int frequency);
-
-    bool getFirstBitOfByte(int *pos) { return (mDict[*pos] & 0x80) > 0; }
-    bool getSecondBitOfByte(int *pos) { return (mDict[*pos] & 0x40) > 0; }
-    bool getTerminal(int *pos) { return (mDict[*pos] & FLAG_TERMINAL_MASK) > 0; }
-    int getCount(int *pos) { return mDict[(*pos)++] & 0xFF; }
-    unsigned short getChar(int *pos);
-    int wideStrLen(unsigned short *str);
-
-    bool sameAsTyped(unsigned short *word, int length);
-    bool checkFirstCharacter(unsigned short *word);
-    bool addWord(unsigned short *word, int length, int frequency);
-    bool addWordBigram(unsigned short *word, int length, int frequency);
-    unsigned short toLowerCase(unsigned short c);
-    void getWordsRec(int pos, int depth, int maxDepth, bool completion, int frequency,
-            int inputIndex, int diffs);
-    int isValidWordRec(int pos, unsigned short *word, int offset, int length);
-    void registerNextLetter(unsigned short c);
-
-    unsigned char *mDict;
+    const unsigned char *DICT;
+    const bool IS_LATEST_DICT_VERSION;
     void *mAsset;
-
-    int *mFrequencies;
-    int *mBigramFreq;
-    int mMaxWords;
-    int mMaxBigrams;
-    int mMaxWordLength;
-    unsigned short *mOutputChars;
-    unsigned short *mBigramChars;
-    int *mInputCodes;
-    int mInputLength;
-    int mMaxAlternatives;
-    unsigned short mWord[128];
-    int mSkipPos;
-    int mMaxEditDistance;
-
-    int mFullWordMultiplier;
-    int mTypedLetterMultiplier;
-    int *mNextLettersFrequencies;
-    int mNextLettersSize;
-    int mVersion;
-    int mBigram;
+    BigramDictionary *mBigramDictionary;
+    UnigramDictionary *mUnigramDictionary;
 };
 
 // ----------------------------------------------------------------------------
+// public static utility methods
+// static inline methods should be defined in the header file
+inline unsigned short Dictionary::getChar(const unsigned char *dict, int *pos) {
+    unsigned short ch = (unsigned short) (dict[(*pos)++] & 0xFF);
+    // If the code is 255, then actual 16 bit code follows (in big endian)
+    if (ch == 0xFF) {
+        ch = ((dict[*pos] & 0xFF) << 8) | (dict[*pos + 1] & 0xFF);
+        (*pos) += 2;
+    }
+    return ch;
+}
+
+inline int Dictionary::getCount(const unsigned char *dict, int *pos) {
+    return dict[(*pos)++] & 0xFF;
+}
+
+inline bool Dictionary::getTerminal(const unsigned char *dict, int *pos) {
+    return (dict[*pos] & FLAG_TERMINAL_MASK) > 0;
+}
+
+inline int Dictionary::getAddress(const unsigned char *dict, int *pos) {
+    int address = 0;
+    if ((dict[*pos] & FLAG_ADDRESS_MASK) == 0) {
+        *pos += 1;
+    } else {
+        address += (dict[*pos] & (ADDRESS_MASK >> 16)) << 16;
+        address += (dict[*pos + 1] & 0xFF) << 8;
+        address += (dict[*pos + 2] & 0xFF);
+        *pos += 3;
+    }
+    return address;
+}
+
+inline int Dictionary::getFreq(const unsigned char *dict,
+        const bool isLatestDictVersion, int *pos) {
+    int freq = dict[(*pos)++] & 0xFF;
+    if (isLatestDictVersion) {
+        // skipping bigram
+        int bigramExist = (dict[*pos] & FLAG_BIGRAM_READ);
+        if (bigramExist > 0) {
+            int nextBigramExist = 1;
+            while (nextBigramExist > 0) {
+                (*pos) += 3;
+                nextBigramExist = (dict[(*pos)++] & FLAG_BIGRAM_CONTINUED);
+            }
+        } else {
+            (*pos)++;
+        }
+    }
+    return freq;
+}
+
+
+inline int Dictionary::wideStrLen(unsigned short *str) {
+    if (!str) return 0;
+    unsigned short *end = str;
+    while (*end)
+        end++;
+    return end - str;
+}
+
+inline int Dictionary::setDictionaryValues(const unsigned char *dict,
+        const bool isLatestDictVersion, const int pos, unsigned short *c,int *childrenPosition,
+        bool *terminal, int *freq) {
+    int position = pos;
+    // -- at char
+    *c = Dictionary::getChar(dict, &position);
+    // -- at flag/add
+    *terminal = Dictionary::getTerminal(dict, &position);
+    *childrenPosition = Dictionary::getAddress(dict, &position);
+    // -- after address or flag
+    *freq = (*terminal) ? Dictionary::getFreq(dict, isLatestDictVersion, &position) : 1;
+    // returns next sibling's position
+    return position;
+}
 
 }; // namespace latinime
-
 #endif // LATINIME_DICTIONARY_H
diff --git a/native/src/unigram_dictionary.cpp b/native/src/unigram_dictionary.cpp
new file mode 100644
index 0000000..fa4e296
--- /dev/null
+++ b/native/src/unigram_dictionary.cpp
@@ -0,0 +1,321 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+
+#define LOG_TAG "LatinIME: unigram_dictionary.cpp"
+
+#include "basechars.h"
+#include "char_utils.h"
+#include "dictionary.h"
+#include "unigram_dictionary.h"
+
+namespace latinime {
+
+UnigramDictionary::UnigramDictionary(const unsigned char *dict, int typedLetterMultiplier,
+        int fullWordMultiplier, int maxWordLength, int maxWords, int maxAlternatives,
+        const bool isLatestDictVersion)
+    : DICT(dict), MAX_WORD_LENGTH(maxWordLength),MAX_WORDS(maxWords),
+    MAX_ALTERNATIVES(maxAlternatives), IS_LATEST_DICT_VERSION(isLatestDictVersion),
+    TYPED_LETTER_MULTIPLIER(typedLetterMultiplier), FULL_WORD_MULTIPLIER(fullWordMultiplier) {
+    LOGI("UnigramDictionary - constructor");
+}
+
+UnigramDictionary::~UnigramDictionary() {}
+
+int UnigramDictionary::getSuggestions(int *codes, int codesSize, unsigned short *outWords,
+        int *frequencies, int *nextLetters, int nextLettersSize)
+{
+
+    initSuggestions(codes, codesSize, outWords, frequencies);
+
+    int suggestedWordsCount = getSuggestionCandidates(codesSize, -1, nextLetters,
+            nextLettersSize);
+
+    // If there aren't sufficient suggestions, search for words by allowing wild cards at
+    // the different character positions. This feature is not ready for prime-time as we need
+    // to figure out the best ranking for such words compared to proximity corrections and
+    // completions.
+    if (SUGGEST_MISSING_CHARACTERS && suggestedWordsCount < SUGGEST_MISSING_CHARACTERS_THRESHOLD) {
+        for (int i = 0; i < codesSize; ++i) {
+            int tempCount = getSuggestionCandidates(codesSize, i, NULL, 0);
+            if (tempCount > suggestedWordsCount) {
+                suggestedWordsCount = tempCount;
+                break;
+            }
+        }
+    }
+
+    if (DEBUG_DICT) {
+        LOGI("Returning %d words", suggestedWordsCount);
+        LOGI("Next letters: ");
+        for (int k = 0; k < nextLettersSize; k++) {
+            if (nextLetters[k] > 0) {
+                LOGI("%c = %d,", k, nextLetters[k]);
+            }
+        }
+        LOGI("\n");
+    }
+    return suggestedWordsCount;
+}
+
+void UnigramDictionary::initSuggestions(int *codes, int codesSize, unsigned short *outWords,
+        int *frequencies) {
+    mFrequencies = frequencies;
+    mOutputChars = outWords;
+    mInputCodes = codes;
+    mInputLength = codesSize;
+    mMaxEditDistance = mInputLength < 5 ? 2 : mInputLength / 2;
+}
+
+int UnigramDictionary::getSuggestionCandidates(int inputLength, int skipPos,
+        int *nextLetters, int nextLettersSize) {
+    int initialPos = 0;
+    if (IS_LATEST_DICT_VERSION) {
+        initialPos = DICTIONARY_HEADER_SIZE;
+    }
+    getWords(initialPos, inputLength, skipPos, nextLetters, nextLettersSize);
+
+    // Get the word count
+    int suggestedWordsCount = 0;
+    while (suggestedWordsCount < MAX_WORDS && mFrequencies[suggestedWordsCount] > 0) {
+        suggestedWordsCount++;
+    }
+    return suggestedWordsCount;
+}
+
+void UnigramDictionary::registerNextLetter(
+        unsigned short c, int *nextLetters, int nextLettersSize) {
+    if (c < nextLettersSize) {
+        nextLetters[c]++;
+    }
+}
+
+bool UnigramDictionary::addWord(unsigned short *word, int length, int frequency) {
+    word[length] = 0;
+    if (DEBUG_DICT) {
+        char s[length + 1];
+        for (int i = 0; i <= length; i++) s[i] = word[i];
+        LOGI("Found word = %s, freq = %d : \n", s, frequency);
+    }
+
+    // Find the right insertion point
+    int insertAt = 0;
+    while (insertAt < MAX_WORDS) {
+        if (frequency > mFrequencies[insertAt] || (mFrequencies[insertAt] == frequency
+                && length < Dictionary::wideStrLen(mOutputChars + insertAt * MAX_WORD_LENGTH))) {
+            break;
+        }
+        insertAt++;
+    }
+    if (insertAt < MAX_WORDS) {
+        memmove((char*) mFrequencies + (insertAt + 1) * sizeof(mFrequencies[0]),
+               (char*) mFrequencies + insertAt * sizeof(mFrequencies[0]),
+               (MAX_WORDS - insertAt - 1) * sizeof(mFrequencies[0]));
+        mFrequencies[insertAt] = frequency;
+        memmove((char*) mOutputChars + (insertAt + 1) * MAX_WORD_LENGTH * sizeof(short),
+               (char*) mOutputChars + insertAt * MAX_WORD_LENGTH * sizeof(short),
+               (MAX_WORDS - insertAt - 1) * sizeof(short) * MAX_WORD_LENGTH);
+        unsigned short *dest = mOutputChars + insertAt * MAX_WORD_LENGTH;
+        while (length--) {
+            *dest++ = *word++;
+        }
+        *dest = 0; // NULL terminate
+        if (DEBUG_DICT) LOGI("Added word at %d\n", insertAt);
+        return true;
+    }
+    return false;
+}
+
+unsigned short UnigramDictionary::toLowerCase(unsigned short c) {
+    if (c < sizeof(BASE_CHARS) / sizeof(BASE_CHARS[0])) {
+        c = BASE_CHARS[c];
+    }
+    if (c >='A' && c <= 'Z') {
+        c |= 32;
+    } else if (c > 127) {
+        c = latin_tolower(c);
+    }
+    return c;
+}
+
+bool UnigramDictionary::sameAsTyped(unsigned short *word, int length) {
+    if (length != mInputLength) {
+        return false;
+    }
+    int *inputCodes = mInputCodes;
+    while (length--) {
+        if ((unsigned int) *inputCodes != (unsigned int) *word) {
+            return false;
+        }
+        inputCodes += MAX_ALTERNATIVES;
+        word++;
+    }
+    return true;
+}
+
+static const char QUOTE = '\'';
+
+void UnigramDictionary::getWords(const int initialPos, const int inputLength, const int skipPos,
+        int *nextLetters, const int nextLettersSize) {
+    int initialPosition = initialPos;
+    const int count = Dictionary::getCount(DICT, &initialPosition);
+    getWordsRec(count, initialPosition, 0, inputLength * MAX_DEPTH_MULTIPLIER,
+            mInputLength <= 0, 1, 0, 0, skipPos, nextLetters, nextLettersSize);
+}
+
+// snr : frequency?
+void UnigramDictionary::getWordsRec(const int childrenCount, const int pos, const int depth,
+        const int maxDepth, const bool traverseAllNodes, const int snr, const int inputIndex,
+        const int diffs, const int skipPos, int *nextLetters, const int nextLettersSize) {
+    int siblingPos = pos;
+    for (int i = 0; i < childrenCount; ++i) {
+        int newCount;
+        int newChildPosition;
+        int newDepth;
+        bool newTraverseAllNodes;
+        int newSnr;
+        int newInputIndex;
+        int newDiffs;
+        int newSiblingPos;
+        const bool needsToTraverseChildrenNodes = processCurrentNode(siblingPos, depth, maxDepth,
+                traverseAllNodes, snr, inputIndex, diffs, skipPos, nextLetters, nextLettersSize,
+                &newCount, &newChildPosition, &newDepth, &newTraverseAllNodes, &newSnr,
+                &newInputIndex, &newDiffs, &newSiblingPos);
+        siblingPos = newSiblingPos;
+
+        if (needsToTraverseChildrenNodes) {
+            getWordsRec(newCount, newChildPosition, newDepth, maxDepth, newTraverseAllNodes,
+                    newSnr, newInputIndex, newDiffs, skipPos, nextLetters, nextLettersSize);
+        }
+    }
+}
+
+inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsGreaterThanInputLength(
+        unsigned short *word, const int inputLength, const int depth, const int snr,
+        int *nextLetters, const int nextLettersSize, const int skipPos, const int freq) {
+    addWord(word, depth + 1, freq * snr);
+    if (depth >= inputLength && skipPos < 0) {
+        registerNextLetter(mWord[mInputLength], nextLetters, nextLettersSize);
+    }
+}
+
+inline void UnigramDictionary::onTerminalWhenUserTypedLengthIsSameAsInputLength(
+        unsigned short *word, const int depth, const int snr, const int skipPos, const int freq,
+        const int addedWeight) {
+    if (!sameAsTyped(word, depth + 1)) {
+        int finalFreq = freq * snr * addedWeight;
+        // Proximity collection will promote a word of the same length as
+        // what user typed.
+        if (skipPos < 0) finalFreq *= FULL_WORD_MULTIPLIER;
+        addWord(word, depth + 1, finalFreq);
+    }
+}
+
+inline bool UnigramDictionary::needsToSkipCurrentNode(const unsigned short c,
+        const int inputIndex, const int skipPos, const int depth) {
+    const unsigned short userTypedChar = (mInputCodes + (inputIndex * MAX_ALTERNATIVES))[0];
+    // Skip the ' or other letter and continue deeper
+    return (c == QUOTE && userTypedChar != QUOTE) || skipPos == depth;
+}
+
+inline int UnigramDictionary::getMatchedProximityId(const int *currentChars,
+        const unsigned short c, const int skipPos) {
+    const unsigned short lowerC = toLowerCase(c);
+    int j = 0;
+    while (currentChars[j] > 0) {
+        const bool matched = (currentChars[j] == lowerC || currentChars[j] == c);
+        // If skipPos is defined, not to search proximity collections.
+        // First char is what user typed.
+        if (matched) {
+            return j;
+        } else if (skipPos >= 0) {
+            return -1;
+        }
+        ++j;
+    }
+    return -1;
+}
+
+inline bool UnigramDictionary::processCurrentNode(const int pos, const int depth,
+        const int maxDepth, const bool traverseAllNodes, const int snr, const int inputIndex,
+        const int diffs, const int skipPos, int *nextLetters, const int nextLettersSize,
+        int *newCount, int *newChildPosition, int *newDepth, bool *newTraverseAllNodes,
+        int *newSnr, int*newInputIndex, int *newDiffs, int *nextSiblingPosition) {
+    unsigned short c;
+    int childPosition;
+    bool terminal;
+    int freq;
+    *nextSiblingPosition = Dictionary::setDictionaryValues(DICT, IS_LATEST_DICT_VERSION, pos, &c,
+            &childPosition, &terminal, &freq);
+
+    const bool needsToTraverseChildrenNodes = childPosition != 0;
+
+    // If we are only doing traverseAllNodes, no need to look at the typed characters.
+    if (traverseAllNodes || needsToSkipCurrentNode(c, inputIndex, skipPos, depth)) {
+        mWord[depth] = c;
+        if (traverseAllNodes && terminal) {
+            onTerminalWhenUserTypedLengthIsGreaterThanInputLength(mWord, mInputLength, depth,
+                    snr, nextLetters, nextLettersSize, skipPos, freq);
+        }
+        if (!needsToTraverseChildrenNodes) return false;
+        *newTraverseAllNodes = traverseAllNodes;
+        *newSnr = snr;
+        *newDiffs = diffs;
+        *newInputIndex = inputIndex;
+        *newDepth = depth + 1;
+    } else {
+        int *currentChars = mInputCodes + (inputIndex * MAX_ALTERNATIVES);
+        int matchedProximityCharId = getMatchedProximityId(currentChars, c, skipPos);
+        if (matchedProximityCharId < 0) return false;
+        mWord[depth] = c;
+        // If inputIndex is greater than mInputLength, that means there is no
+        // proximity chars. So, we don't need to check proximity.
+        const int addedWeight = matchedProximityCharId == 0 ? TYPED_LETTER_MULTIPLIER : 1;
+        const bool isSameAsUserTypedLength = mInputLength == inputIndex + 1;
+        if (isSameAsUserTypedLength && terminal) {
+            onTerminalWhenUserTypedLengthIsSameAsInputLength(mWord, depth, snr,
+                    skipPos, freq, addedWeight);
+        }
+        if (!needsToTraverseChildrenNodes) return false;
+        // Start traversing all nodes after the index exceeds the user typed length
+        *newTraverseAllNodes = isSameAsUserTypedLength;
+        *newSnr = snr * addedWeight;
+        *newDiffs = diffs + (matchedProximityCharId > 0);
+        *newInputIndex = inputIndex + 1;
+        *newDepth = depth + 1;
+    }
+    // Optimization: Prune out words that are too long compared to how much was typed.
+    if (*newDepth > maxDepth || *newDiffs > mMaxEditDistance) {
+        return false;
+    }
+
+    // If inputIndex is greater than mInputLength, that means there are no proximity chars.
+    if (mInputLength <= *newInputIndex) {
+        *newTraverseAllNodes = true;
+    }
+    // get the count of nodes and increment childAddress.
+    *newCount = Dictionary::getCount(DICT, &childPosition);
+    *newChildPosition = childPosition;
+    if (DEBUG_DICT) assert(needsToTraverseChildrenNodes);
+    return needsToTraverseChildrenNodes;
+}
+
+} // namespace latinime
diff --git a/native/src/unigram_dictionary.h b/native/src/unigram_dictionary.h
new file mode 100644
index 0000000..c02d366
--- /dev/null
+++ b/native/src/unigram_dictionary.h
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+#ifndef LATINIME_UNIGRAM_DICTIONARY_H
+#define LATINIME_UNIGRAM_DICTIONARY_H
+
+#include "defines.h"
+
+namespace latinime {
+
+class UnigramDictionary {
+public:
+    UnigramDictionary(const unsigned char *dict, int typedLetterMultipler, int fullWordMultiplier,
+            int maxWordLength, int maxWords, int maxAlternatives,  const bool isLatestDictVersion);
+    int getSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies,
+            int *nextLetters, int nextLettersSize);
+    ~UnigramDictionary();
+
+private:
+    void initSuggestions(int *codes, int codesSize, unsigned short *outWords, int *frequencies);
+    int getSuggestionCandidates(int inputLength, int skipPos, int *nextLetters,
+            int nextLettersSize);
+    void getVersionNumber();
+    bool checkIfDictVersionIsLatest();
+    int getAddress(int *pos);
+    int getFreq(int *pos);
+    int wideStrLen(unsigned short *str);
+    bool sameAsTyped(unsigned short *word, int length);
+    bool addWord(unsigned short *word, int length, int frequency);
+    unsigned short toLowerCase(unsigned short c);
+    void getWordsRec(const int childrenCount, const int pos, const int depth, const int maxDepth,
+            const bool traverseAllNodes, const int snr, const int inputIndex, const int diffs,
+            const int skipPos, int *nextLetters, const int nextLettersSize);
+    void getWords(const int initialPos, const int inputLength, const int skipPos, int *nextLetters,
+            const int nextLettersSize);
+    void registerNextLetter(unsigned short c, int *nextLetters, int nextLettersSize);
+    void onTerminalWhenUserTypedLengthIsGreaterThanInputLength(unsigned short *word,
+            const int mInputLength, const int depth, const int snr, int *nextLetters,
+            const int nextLettersSize, const int skipPos, const int freq);
+    void onTerminalWhenUserTypedLengthIsSameAsInputLength(unsigned short *word, const int depth,
+            const int snr, const int skipPos, const int freq, const int addedWeight);
+    bool needsToSkipCurrentNode(const unsigned short c,
+            const int inputIndex, const int skipPos, const int depth);
+    int getMatchedProximityId(const int *currentChars, const unsigned short c, const int skipPos);
+    bool processCurrentNode(const int pos, const int depth,
+            const int maxDepth, const bool traverseAllNodes, const int snr, const int inputIndex,
+            const int diffs, const int skipPos, int *nextLetters, const int nextLettersSize,
+            int *newCount, int *newChildPosition, int *newDepth, bool *newTraverseAllNodes,
+            int *newSnr, int*newInputIndex, int *newDiffs, int *nextSiblingPosition);
+    const unsigned char *DICT;
+    const int MAX_WORDS;
+    const int MAX_WORD_LENGTH;
+    const int MAX_ALTERNATIVES;
+    const bool IS_LATEST_DICT_VERSION;
+    const int TYPED_LETTER_MULTIPLIER;
+    const int FULL_WORD_MULTIPLIER;
+
+    int *mFrequencies;
+    unsigned short *mOutputChars;
+    int *mInputCodes;
+    int mInputLength;
+    // MAX_WORD_LENGTH_INTERNAL must be bigger than MAX_WORD_LENGTH
+    unsigned short mWord[MAX_WORD_LENGTH_INTERNAL];
+    int mMaxEditDistance;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace latinime
+
+#endif // LATINIME_UNIGRAM_DICTIONARY_H
diff --git a/tests/src/com/android/inputmethod/latin/EditDistanceTests.java b/tests/src/com/android/inputmethod/latin/EditDistanceTests.java
new file mode 100644
index 0000000..a9ed89d
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/EditDistanceTests.java
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.test.AndroidTestCase;
+
+public class EditDistanceTests extends AndroidTestCase {
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /*
+     * dist(kitten, sitting) == 3
+     *
+     * kitten-
+     * .|||.|
+     * sitting
+     */
+    public void testExample1() {
+        final int dist = LatinIMEUtil.editDistance("kitten", "sitting");
+        assertEquals("edit distance between 'kitten' and 'sitting' is 3",
+                3, dist);
+    }
+
+    /*
+     * dist(Sunday, Saturday) == 3
+     *
+     * Saturday
+     * |  |.|||
+     * S--unday
+     */
+    public void testExample2() {
+        final int dist = LatinIMEUtil.editDistance("Saturday", "Sunday");
+        assertEquals("edit distance between 'Saturday' and 'Sunday' is 3",
+                3, dist);
+    }
+
+    public void testBothEmpty() {
+        final int dist = LatinIMEUtil.editDistance("", "");
+        assertEquals("when both string are empty, no edits are needed",
+                0, dist);
+    }
+
+    public void testFirstArgIsEmpty() {
+        final int dist = LatinIMEUtil.editDistance("", "aaaa");
+        assertEquals("when only one string of the arguments is empty,"
+                 + " the edit distance is the length of the other.",
+                 4, dist);
+    }
+
+    public void testSecoondArgIsEmpty() {
+        final int dist = LatinIMEUtil.editDistance("aaaa", "");
+        assertEquals("when only one string of the arguments is empty,"
+                 + " the edit distance is the length of the other.",
+                 4, dist);
+    }
+
+    public void testSameStrings() {
+        final String arg1 = "The quick brown fox jumps over the lazy dog.";
+        final String arg2 = "The quick brown fox jumps over the lazy dog.";
+        final int dist = LatinIMEUtil.editDistance(arg1, arg2);
+        assertEquals("when same strings are passed, distance equals 0.",
+                0, dist);
+    }
+
+    public void testSameReference() {
+        final String arg = "The quick brown fox jumps over the lazy dog.";
+        final int dist = LatinIMEUtil.editDistance(arg, arg);
+        assertEquals("when same string references are passed, the distance equals 0.",
+                0, dist);
+    }
+
+    public void testNullArg() {
+        try {
+            LatinIMEUtil.editDistance(null, "aaa");
+            fail("IllegalArgumentException should be thrown.");
+        } catch (Exception e) {
+            assertTrue(e instanceof IllegalArgumentException);
+        }
+        try {
+            LatinIMEUtil.editDistance("aaa", null);
+            fail("IllegalArgumentException should be thrown.");
+        } catch (Exception e) {
+            assertTrue(e instanceof IllegalArgumentException);
+        }
+    }
+}
diff --git a/tests/src/com/android/inputmethod/latin/EventRingBufferTests.java b/tests/src/com/android/inputmethod/latin/EventRingBufferTests.java
index 620f036..869781f 100644
--- a/tests/src/com/android/inputmethod/latin/EventRingBufferTests.java
+++ b/tests/src/com/android/inputmethod/latin/EventRingBufferTests.java
@@ -16,7 +16,7 @@
 
 package com.android.inputmethod.latin;
 
-import com.android.inputmethod.latin.SwipeTracker.EventRingBuffer;
+import com.android.inputmethod.keyboard.SwipeTracker.EventRingBuffer;
 
 import android.test.AndroidTestCase;