Merge "Added virtual view hierarchy for keyboard accessibility."
diff --git a/java/res/drawable-hdpi/more_keys_divider.png b/java/res/drawable-hdpi/more_keys_divider.png
new file mode 100644
index 0000000..a5912f9
--- /dev/null
+++ b/java/res/drawable-hdpi/more_keys_divider.png
Binary files differ
diff --git a/java/res/drawable-mdpi/more_keys_divider.png b/java/res/drawable-mdpi/more_keys_divider.png
new file mode 100644
index 0000000..a46284f
--- /dev/null
+++ b/java/res/drawable-mdpi/more_keys_divider.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/more_keys_divider.png b/java/res/drawable-xhdpi/more_keys_divider.png
new file mode 100644
index 0000000..178594b
--- /dev/null
+++ b/java/res/drawable-xhdpi/more_keys_divider.png
Binary files differ
diff --git a/java/res/values-be/donottranslate-more-keys.xml b/java/res/values-be/donottranslate-more-keys.xml
index 0917f11..1550ddb 100644
--- a/java/res/values-be/donottranslate-more-keys.xml
+++ b/java/res/values-be/donottranslate-more-keys.xml
@@ -19,7 +19,7 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- U+045E: "ў" CYRILLIC SMALL LETTER SHORT U -->
-    <string name="keylabel_for_slavic_shcha">&#x045E;</string>
+    <string name="keylabel_for_cyrillic_shcha">&#x045E;</string>
     <!-- U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I -->
-    <string name="keylabel_for_slavic_i">&#x0456;</string>
+    <string name="keylabel_for_cyrillic_i">&#x0456;</string>
 </resources>
diff --git a/java/res/values-ky/donottranslate-more-keys.xml b/java/res/values-ky/donottranslate-more-keys.xml
index 8246209..b67a9f1 100644
--- a/java/res/values-ky/donottranslate-more-keys.xml
+++ b/java/res/values-ky/donottranslate-more-keys.xml
@@ -19,9 +19,9 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U -->
-    <string name="more_keys_for_slavic_u">&#x04AF;</string>
+    <string name="more_keys_for_cyrillic_u">&#x04AF;</string>
     <!-- U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER -->
-    <string name="more_keys_for_slavic_en">&#x04A3;</string>
+    <string name="more_keys_for_cyrillic_en">&#x04A3;</string>
     <!-- U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O -->
-    <string name="more_keys_for_slavic_o">&#x04E9;</string>
+    <string name="more_keys_for_cyrillic_o">&#x04E9;</string>
 </resources>
diff --git a/java/res/values-mk/donottranslate-more-keys.xml b/java/res/values-mk/donottranslate-more-keys.xml
new file mode 100644
index 0000000..e96a306
--- /dev/null
+++ b/java/res/values-mk/donottranslate-more-keys.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- NOTE: Macedonian layouts are based on Serbian ones with the following key replacements. -->
+    <!-- U+0455: "ѕ" CYRILLIC SMALL LETTER DZE -->
+    <string name="keylabel_for_cyrillic_ze">&#x0455;</string>
+    <!-- U+045C: "ќ" CYRILLIC SMALL LETTER KJE -->
+    <string name="keylabel_for_cyrillic_tshe">&#x045C;</string>
+    <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
+    <string name="keylabel_for_cyrillic_dze">&#x0437;</string>
+    <!-- U+0453: "ѓ" CYRILLIC SMALL LETTER GJE -->
+    <string name="keylabel_for_cyrillic_dje">&#x0453;</string>
+    <!-- U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE -->
+    <string name="more_keys_for_cyrillic_ie">&#x0450;</string>
+    <!-- U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE -->
+    <string name="more_keys_for_cyrillic_i">&#x045D;</string>
+    <!-- U+2018: "‘" LEFT SINGLE QUOTATION MARK
+         U+2019: "’" RIGHT SINGLE QUOTATION MARK
+         U+201A: "‚" SINGLE LOW-9 QUOTATION MARK
+         U+201B: "‛" SINGLE HIGH-REVERSED-9 QUOTATION MARK
+         U+201C: "“" LEFT DOUBLE QUOTATION MARK
+         U+201D: "”" RIGHT DOUBLE QUOTATION MARK
+         U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
+         U+201F: "‟" DOUBLE HIGH-REVERSED-9 QUOTATION MARK -->
+    <!-- TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. -->
+    <!-- <string name="more_keys_for_double_quote">!fixedColumnOrder!6,&#x201E;,&#x201C;,&#x201D;,&#x201F;,&#x00AB;,&#x00BB;</string> -->
+    <string name="more_keys_for_double_quote">!fixedColumnOrder!5,&#x201E;,&#x201C;,&#x201D;,&#x00AB;,&#x00BB;</string>
+    <!-- TODO: Neither DroidSans nor Roboto have the glyph for U+201F DOUBLE HIGH-REVERSED-9 QUOTATION MARK. -->
+    <!-- <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!6,&#x201C;,&#x201D;,&#x201E;,&#x201F;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string> -->
+    <string name="more_keys_for_tablet_double_quote">!fixedColumnOrder!5,&#x201E;,&#x201C;,&#x201D;,&#x00AB;,&#x00BB;,&#x2018;,&#x2019;,&#x201A;,&#x201B;</string>
+</resources>
diff --git a/java/res/values-ru/donottranslate-more-keys.xml b/java/res/values-ru/donottranslate-more-keys.xml
index 45c4551..a1a22e5 100644
--- a/java/res/values-ru/donottranslate-more-keys.xml
+++ b/java/res/values-ru/donottranslate-more-keys.xml
@@ -19,5 +19,5 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO -->
-    <string name="more_keys_for_slavic_ye">&#x0451;</string>
+    <string name="more_keys_for_cyrillic_ye">&#x0451;</string>
 </resources>
diff --git a/java/res/values-uk/donottranslate-more-keys.xml b/java/res/values-uk/donottranslate-more-keys.xml
index 3208a66..323eaaf 100644
--- a/java/res/values-uk/donottranslate-more-keys.xml
+++ b/java/res/values-uk/donottranslate-more-keys.xml
@@ -19,7 +19,7 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I -->
-    <string name="keylabel_for_slavic_yery">&#x0456;</string>
+    <string name="keylabel_for_cyrillic_yery">&#x0456;</string>
     <!-- U+0457: "ї" CYRILLIC SMALL LETTER YI -->
-    <string name="more_keys_for_slavic_yery">&#x0457;</string>
+    <string name="more_keys_for_cyrillic_yery">&#x0457;</string>
 </resources>
diff --git a/java/res/values/donottranslate-more-keys.xml b/java/res/values/donottranslate-more-keys.xml
index 0581a61..6577acd 100644
--- a/java/res/values/donottranslate-more-keys.xml
+++ b/java/res/values/donottranslate-more-keys.xml
@@ -41,20 +41,30 @@
     <string name="more_keys_for_scandinavia_row2_10"></string>
     <string name="more_keys_for_scandinavia_row2_11"></string>
     <!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA -->
-    <string name="keylabel_for_slavic_shcha">&#x0449;</string>
+    <string name="keylabel_for_cyrillic_shcha">&#x0449;</string>
     <!-- U+044B: "ы" CYRILLIC SMALL LETTER YERU -->
-    <string name="keylabel_for_slavic_yery">&#x044B;</string>
+    <string name="keylabel_for_cyrillic_yery">&#x044B;</string>
     <!-- U+0438: "и" CYRILLIC SMALL LETTER I -->
-    <string name="keylabel_for_slavic_i">&#x0438;</string>
-    <string name="more_keys_for_slavic_u"></string>
-    <string name="more_keys_for_slavic_ye"></string>
-    <string name="more_keys_for_slavic_en"></string>
+    <string name="keylabel_for_cyrillic_i">&#x0438;</string>
+    <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
+    <string name="keylabel_for_cyrillic_ze">&#x0437;</string>
+    <!-- U+045B: "ћ" CYRILLIC SMALL LETTER TSHE -->
+    <string name="keylabel_for_cyrillic_tshe">&#x045B;</string>
+    <!-- U+0455: "ѕ" CYRILLIC SMALL LETTER DZE -->
+    <string name="keylabel_for_cyrillic_dze">&#x0455;</string>
+    <!-- U+0452: "ђ" CYRILLIC SMALL LETTER DJE -->
+    <string name="keylabel_for_cyrillic_dje">&#x0452;</string>
+    <string name="more_keys_for_cyrillic_u"></string>
+    <string name="more_keys_for_cyrillic_ye"></string>
+    <string name="more_keys_for_cyrillic_en"></string>
     <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN -->
-    <string name="more_keys_for_slavic_ha">&#x044A;</string>
-    <string name="more_keys_for_slavic_yery"></string>
-    <string name="more_keys_for_slavic_o"></string>
+    <string name="more_keys_for_cyrillic_ha">&#x044A;</string>
+    <string name="more_keys_for_cyrillic_yery"></string>
+    <string name="more_keys_for_cyrillic_o"></string>
     <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN -->
-    <string name="more_keys_for_slavic_soft_sign">&#x044A;</string>
+    <string name="more_keys_for_cyrillic_soft_sign">&#x044A;</string>
+    <string name="more_keys_for_cyrillic_ie"></string>
+    <string name="more_keys_for_cyrillic_i"></string>
     <!-- U+00A2: "¢" CENT SIGN
          U+00A3: "£" POUND SIGN
          U+20AC: "€" EURO SIGN
@@ -64,12 +74,12 @@
     <string name="more_keys_for_currency_euro">&#x00A2;,&#x00A3;,$,&#x00A5;,&#x20B1;</string>
     <string name="more_keys_for_currency_pound">&#x00A2;,$,&#x20AC;,&#x00A5;,&#x20B1;</string>
     <string name="more_keys_for_currency_general">&#x00A2;,$,&#x20AC;,&#x00A3;,&#x00A5;,&#x20B1;</string>
-    <string name="more_keys_for_smiley">"!fixedColumnOrder!5,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ "</string>
+    <string name="more_keys_for_smiley">"!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ "</string>
     <string name="more_keys_for_punctuation">"!fixedColumnOrder!8,\",\',#,-,:,!,\\,,\?,\@,&amp;,\\%,+,;,/,(,)"</string>
     <string name="keyhintlabel_for_punctuation"></string>
     <string name="keylabel_for_popular_domain">".com"</string>
     <!-- popular web domains for the locale - most popular, displayed on the keyboard -->
-    <string name="more_keys_for_popular_domain">".net,.org,.gov,.edu"</string>
+    <string name="more_keys_for_popular_domain">"!hasLabels!,.net,.org,.gov,.edu"</string>
     <string name="keylabel_for_symbols_1">1</string>
     <string name="keylabel_for_symbols_2">2</string>
     <string name="keylabel_for_symbols_3">3</string>
@@ -115,11 +125,12 @@
     <!-- U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
          U+2205: "∅" EMPTY SET -->
     <string name="more_keys_for_symbols_0">&#x207F;,&#x2205;</string>
+    <string name="more_keys_for_am_pm">!fixedColumnOrder!2,!hasLabels!,\@string/label_time_am,\@string/label_time_pm</string>
     <string name="settings_as_more_key">\@icon/settingsKey|\@integer/key_settings</string>
     <string name="keylabel_for_comma">,</string>
     <string name="more_keys_for_comma"></string>
-    <string name="action_next_as_more_key">\@string/label_next_key|\@integer/key_action_next</string>
-    <string name="action_previous_as_more_key">\@string/label_previous_key|\@integer/key_action_previous</string>
+    <string name="action_next_as_more_key">!hasLabels!,\@string/label_next_key|\@integer/key_action_next</string>
+    <string name="action_previous_as_more_key">!hasLabels!,\@string/label_previous_key|\@integer/key_action_previous</string>
     <string name="keylabel_for_symbols_question">\?</string>
     <string name="keylabel_for_symbols_semicolon">;</string>
     <string name="keylabel_for_symbols_percent">%</string>
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index 94da946..d6a15de 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -58,6 +58,10 @@
     <!-- U+FF0A: "*" FULLWIDTH ASTERISK
          U+FF03: "#" FULLWIDTH NUMBER SIGN -->
     <string name="label_to_phone_symbols_key">&#xFF0A;&#xFF03;</string>
+    <!-- Key label for "ante meridiem" -->
+    <string name="label_time_am">"AM"</string>
+    <!-- Key label for "post meridiem" -->
+    <string name="label_time_pm">"PM"</string>
 
     <!--  Always show the suggestion strip -->
     <string name="prefs_suggestion_visibility_show_value">0</string>
diff --git a/java/res/xml-el/keyboard_set.xml b/java/res/xml-el/keyboard_set.xml
new file mode 100644
index 0000000..19ecb77
--- /dev/null
+++ b/java/res/xml-el/keyboard_set.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<KeyboardSet
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyboardLocale="el">
+    <Element
+        latin:elementName="alphabet"
+        latin:elementKeyboard="@xml/kbd_greek" />
+    <Element
+        latin:elementName="symbols"
+        latin:elementKeyboard="@xml/kbd_symbols" />
+    <Element
+        latin:elementName="symbolsShifted"
+        latin:elementKeyboard="@xml/kbd_symbols_shift" />
+    <Element
+        latin:elementName="phone"
+        latin:elementKeyboard="@xml/kbd_phone" />
+    <Element
+        latin:elementName="phoneSymbols"
+        latin:elementKeyboard="@xml/kbd_phone_symbols" />
+    <Element
+        latin:elementName="number"
+        latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardSet>
diff --git a/java/res/xml-mk/keyboard_set.xml b/java/res/xml-mk/keyboard_set.xml
new file mode 100644
index 0000000..31199cb
--- /dev/null
+++ b/java/res/xml-mk/keyboard_set.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<KeyboardSet
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+    latin:keyboardLocale="mk">
+    <Element
+        latin:elementName="alphabet"
+        latin:elementKeyboard="@xml/kbd_serbian" />
+    <Element
+        latin:elementName="symbols"
+        latin:elementKeyboard="@xml/kbd_symbols" />
+    <Element
+        latin:elementName="symbolsShifted"
+        latin:elementKeyboard="@xml/kbd_symbols_shift" />
+    <Element
+        latin:elementName="phone"
+        latin:elementKeyboard="@xml/kbd_phone" />
+    <Element
+        latin:elementName="phoneSymbols"
+        latin:elementKeyboard="@xml/kbd_phone_symbols" />
+    <Element
+        latin:elementName="number"
+        latin:elementKeyboard="@xml/kbd_number" />
+</KeyboardSet>
diff --git a/java/res/xml-sw600dp/rows_greek.xml b/java/res/xml-sw600dp/rows_greek.xml
new file mode 100644
index 0000000..c77627e
--- /dev/null
+++ b/java/res/xml-sw600dp/rows_greek.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/key_styles_common" />
+    <Row
+        latin:keyWidth="9.0%p"
+    >
+        <Key
+            latin:keyLabel=";" />
+        <!-- TODO: Should find a way to compound Greek dialytika tonos and other Greek letters. -->
+        <!--
+        <switch>
+            <case
+                latin:keyboardSetElement="alphabetManualShifted|alphabetShiftLockShifted"
+            >
+                U+0385: "΅" GREEK DIALYTIKA TONOS
+                <Key
+                    latin:keyLabel="&#x0385;" />
+            </case>
+            <default>
+        -->
+                <!-- U+03C2: "ς" GREEK SMALL LETTER FINAL SIGMA -->
+                <Key
+                    latin:keyLabel="&#x03C2;"
+                    latin:keyLabelFlags="preserveCase" />
+        <!--
+            </default>
+        </switch>
+        -->
+        <!-- U+03B5: "ε" GREEK SMALL LETTER EPSILON
+             U+03AD: "έ" GREEK SMALL LETTER EPSILON WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03B5;"
+            latin:moreKeys="&#x03AD;" />
+        <!-- U+03C1: "ρ" GREEK SMALL LETTER RHO -->
+        <Key
+            latin:keyLabel="&#x03C1;" />
+        <!-- U+03C4: "τ" GREEK SMALL LETTER TAU -->
+        <Key
+            latin:keyLabel="&#x03C4;" />
+        <!-- U+03C5: "υ" GREEK SMALL LETTER UPSILON
+             U+03CD: "ύ" GREEK SMALL LETTER UPSILON WITH TONOS
+             U+03CB: "ϋ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+             U+03B0: "ΰ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -->
+        <Key
+            latin:keyLabel="&#x03C5;"
+            latin:moreKeys="&#x03CD;,&#x03CB;,&#x03B0;" />
+        <!-- U+03B8: "θ" GREEK SMALL LETTER THETA -->
+        <Key
+            latin:keyLabel="&#x03B8;" />
+        <!-- U+03B9: "ι" GREEK SMALL LETTER IOTA
+             U+03AF: "ί" GREEK SMALL LETTER IOTA WITH TONOS
+             U+03CA: "ϊ" GREEK SMALL LETTER IOTA WITH DIALYTIKA
+             U+0390: "ΐ" GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -->
+        <Key
+            latin:keyLabel="&#x03B9;"
+            latin:moreKeys="&#x03AF;,&#x03CA;,&#x0390;" />
+        <!-- U+03BF: "ο" GREEK SMALL LETTER OMICRON
+             U+03CC: "ό" GREEK SMALL LETTER OMICRON WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03BF;"
+            latin:moreKeys="&#x03CC;" />
+        <!-- U+03C0: "π" GREEK SMALL LETTER PI -->
+        <Key
+            latin:keyLabel="&#x03C0;" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyXPos="-10.0%p"
+            latin:keyWidth="fillBoth" />
+    </Row>
+    <Row
+        latin:keyWidth="9.0%p"
+    >
+        <!-- U+03B1: "α" GREEK SMALL LETTER ALPHA
+             U+03AC: "ά" GREEK SMALL LETTER ALPHA WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03B1;"
+            latin:moreKeys="&#x03AC;"
+            latin:keyXPos="4.5%p" />
+        <!-- U+03C3: "σ" GREEK SMALL LETTER SIGMA -->
+        <Key
+            latin:keyLabel="&#x03C3;" />
+        <!-- U+03B4: "δ" GREEK SMALL LETTER DELTA -->
+        <Key
+            latin:keyLabel="&#x03B4;" />
+        <!-- U+03C6: "φ" GREEK SMALL LETTER PHI -->
+        <Key
+            latin:keyLabel="&#x03C6;" />
+        <!-- U+03B3: "γ" GREEK SMALL LETTER GAMMA -->
+        <Key
+            latin:keyLabel="&#x03B3;" />
+        <!-- U+03B7: "η" GREEK SMALL LETTER ETA
+             U+03AE: "ή" GREEK SMALL LETTER ETA WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03B7;"
+            latin:moreKeys="&#x03AE;" />
+        <!-- U+03BE: "ξ" GREEK SMALL LETTER XI -->
+        <Key
+            latin:keyLabel="&#x03BE;" />
+        <!-- U+03BA: "κ" GREEK SMALL LETTER KAPPA -->
+        <Key
+            latin:keyLabel="&#x03BA;" />
+        <!-- U+03BB: "λ" GREEK SMALL LETTER LAMDA -->
+        <Key
+            latin:keyLabel="&#x03BB;" />
+        <Key
+            latin:keyStyle="enterKeyStyle"
+            latin:keyXPos="-14.6%p"
+            latin:keyWidth="fillBoth" />
+    </Row>
+    <Row
+        latin:keyWidth="8.9%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="10.0%p" />
+        <!-- U+03B6: "ζ" GREEK SMALL LETTER ZETA -->
+        <Key
+            latin:keyLabel="&#x03B6;" />
+        <!-- U+03C7: "χ" GREEK SMALL LETTER CHI -->
+        <Key
+            latin:keyLabel="&#x03C7;" />
+        <!-- U+03C8: "ψ" GREEK SMALL LETTER PSI -->
+        <Key
+            latin:keyLabel="&#x03C8;" />
+        <!-- U+03C9: "ω" GREEK SMALL LETTER OMEGA
+             U+03CE: "ώ" GREEK SMALL LETTER OMEGA WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03C9;"
+            latin:moreKeys="&#x03CE;" />
+        <!-- U+03B2: "β" GREEK SMALL LETTER BETA -->
+        <Key
+            latin:keyLabel="&#x03B2;" />
+        <!-- U+03BD: "ν" GREEK SMALL LETTER NU -->
+        <Key
+            latin:keyLabel="&#x03BD;" />
+        <!-- U+03BC: "μ" GREEK SMALL LETTER MU -->
+        <Key
+            latin:keyLabel="&#x03BC;" />
+        <include
+            latin:keyboardLayout="@xml/keys_comma_period" />
+        <include
+            latin:keyboardLayout="@xml/key_smiley"
+            latin:keyXPos="-8.9%p"
+            latin:keyWidth="fillBoth" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/res/xml-sw600dp/rows_number_normal.xml b/java/res/xml-sw600dp/rows_number_normal.xml
index 1c38a62..3704c52 100644
--- a/java/res/xml-sw600dp/rows_number_normal.xml
+++ b/java/res/xml-sw600dp/rows_number_normal.xml
@@ -63,10 +63,24 @@
             latin:keyLabel="/"
             latin:keyStyle="numKeyStyle"
             latin:keyWidth="9.25%p" />
-        <Key
-            latin:keyLabel=","
-            latin:keyStyle="numKeyStyle"
-            latin:keyWidth="9.25%p" />
+        <switch>
+            <case
+                latin:mode="time|datetime"
+            >
+                <Key
+                    latin:keyLabel=","
+                    latin:keyLabelFlags="hasPopupHint"
+                    latin:moreKeys="@string/more_keys_for_am_pm"
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="9.25%p" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel=","
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="9.25%p" />
+            </default>
+        </switch>
         <Key
             latin:keyLabel="4"
             latin:keyStyle="numKeyStyle"
@@ -94,10 +108,22 @@
             latin:keyLabel=")"
             latin:keyStyle="numKeyStyle"
             latin:keyWidth="9.25%p" />
-        <Key
-            latin:keyLabel="="
-            latin:keyStyle="numKeyStyle"
-            latin:keyWidth="9.25%p" />
+        <switch>
+            <case
+                latin:mode="time|datetime"
+            >
+                <Key
+                    latin:keyLabel=":"
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="9.25%p" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel="="
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="9.25%p" />
+            </default>
+        </switch>
         <Key
             latin:keyLabel="7"
             latin:keyStyle="numKeyStyle"
diff --git a/java/res/xml-sw600dp/rows_serbian.xml b/java/res/xml-sw600dp/rows_serbian.xml
index 5730aa0..989fa48 100644
--- a/java/res/xml-sw600dp/rows_serbian.xml
+++ b/java/res/xml-sw600dp/rows_serbian.xml
@@ -35,22 +35,23 @@
             latin:keyLabel="&#x045A;" />
         <!-- U+0435: "е" CYRILLIC SMALL LETTER IE -->
         <Key
-            latin:keyLabel="&#x0435;" />
+            latin:keyLabel="&#x0435;"
+            latin:moreKeys="@string/more_keys_for_cyrillic_ie" />
         <!-- U+0440: "р" CYRILLIC SMALL LETTER ER -->
         <Key
             latin:keyLabel="&#x0440;" />
         <!-- U+0442: "т" CYRILLIC SMALL LETTER TE -->
         <Key
             latin:keyLabel="&#x0442;" />
-        <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
         <Key
-            latin:keyLabel="&#x0437;" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_ze" />
         <!-- U+0443: "у" CYRILLIC SMALL LETTER U -->
         <Key
             latin:keyLabel="&#x0443;" />
         <!-- U+0438: "и" CYRILLIC SMALL LETTER I -->
         <Key
-            latin:keyLabel="&#x0438;" />
+            latin:keyLabel="&#x0438;"
+            latin:moreKeys="@string/more_keys_for_cyrillic_i" />
         <!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
         <Key
             latin:keyLabel="&#x043E;" />
@@ -98,9 +99,8 @@
         <!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE -->
         <Key
             latin:keyLabel="&#x0447;" />
-        <!-- U+045B: "ћ" CYRILLIC SMALL LETTER TSHE -->
         <Key
-            latin:keyLabel="&#x045B;" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_tshe" />
         <Key
             latin:keyStyle="enterKeyStyle"
             latin:keyXPos="-14.6%p"
@@ -112,9 +112,8 @@
         <Key
             latin:keyStyle="shiftKeyStyle"
             latin:keyWidth="8.0%p" />
-        <!-- U+0455: "ѕ" CYRILLIC SMALL LETTER DZE -->
         <Key
-            latin:keyLabel="&#x0455;" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_dze" />
         <!-- U+045F: "џ" CYRILLIC SMALL LETTER DZHE -->
         <Key
             latin:keyLabel="&#x045F;" />
@@ -133,9 +132,8 @@
         <!-- U+043C: "м" CYRILLIC SMALL LETTER EM -->
         <Key
             latin:keyLabel="&#x043C;" />
-        <!-- U+0452: "ђ" CYRILLIC SMALL LETTER DJE -->
         <Key
-            latin:keyLabel="&#x0452;" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_dje" />
         <!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE -->
         <Key
             latin:keyLabel="&#x0436;" />
diff --git a/java/res/xml-sw600dp/rows_slavic.xml b/java/res/xml-sw600dp/rows_slavic.xml
index 58f0b39..7ff63bc 100644
--- a/java/res/xml-sw600dp/rows_slavic.xml
+++ b/java/res/xml-sw600dp/rows_slavic.xml
@@ -35,18 +35,18 @@
         <!-- U+0443: "у" CYRILLIC SMALL LETTER U -->
         <Key
             latin:keyLabel="&#x0443;"
-            latin:moreKeys="@string/more_keys_for_slavic_u" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_u" />
         <!-- U+043A: "к" CYRILLIC SMALL LETTER KA -->
         <Key
             latin:keyLabel="&#x043A;" />
         <!-- U+0435: "е" CYRILLIC SMALL LETTER IE -->
         <Key
             latin:keyLabel="&#x0435;"
-            latin:moreKeys="@string/more_keys_for_slavic_ye" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_ye" />
         <!-- U+043D: "н" CYRILLIC SMALL LETTER EN -->
         <Key
             latin:keyLabel="&#x043D;"
-            latin:moreKeys="@string/more_keys_for_slavic_en" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_en" />
         <!-- U+0433: "г" CYRILLIC SMALL LETTER GHE -->
         <Key
             latin:keyLabel="&#x0433;" />
@@ -54,7 +54,7 @@
         <Key
             latin:keyLabel="&#x0448;" />
         <Key
-            latin:keyLabel="@string/keylabel_for_slavic_shcha" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_shcha" />
         <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
         <Key
             latin:keyLabel="&#x0437;" />
@@ -77,8 +77,8 @@
             latin:keyLabel="&#x0444;"
             latin:keyXPos="2.25%p" />
         <Key
-            latin:keyLabel="@string/keylabel_for_slavic_yery"
-            latin:moreKeys="@string/more_keys_for_slavic_yery" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_yery"
+            latin:moreKeys="@string/more_keys_for_cyrillic_yery" />
         <!-- U+0432: "в" CYRILLIC SMALL LETTER VE -->
         <Key
             latin:keyLabel="&#x0432;" />
@@ -94,7 +94,7 @@
         <!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
         <Key
             latin:keyLabel="&#x043E;"
-            latin:moreKeys="@string/more_keys_for_slavic_o" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_o" />
         <!-- U+043B: "л" CYRILLIC SMALL LETTER EL -->
         <Key
             latin:keyLabel="&#x043B;" />
@@ -130,7 +130,7 @@
         <Key
             latin:keyLabel="&#x043C;" />
         <Key
-            latin:keyLabel="@string/keylabel_for_slavic_i" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_i" />
         <!-- U+0442: "т" CYRILLIC SMALL LETTER TE -->
         <Key
             latin:keyLabel="&#x0442;" />
diff --git a/java/res/xml-sw768dp/rows_greek.xml b/java/res/xml-sw768dp/rows_greek.xml
new file mode 100644
index 0000000..e9a76a5
--- /dev/null
+++ b/java/res/xml-sw768dp/rows_greek.xml
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/key_styles_common" />
+    <Row
+        latin:keyWidth="8.282%p"
+    >
+        <Key
+            latin:keyStyle="tabKeyStyle"
+            latin:keyLabelFlags="alignLeft"
+            latin:keyWidth="7.969%p" />
+        <Key
+            latin:keyLabel=";" />
+        <!-- TODO: Should find a way to compound Greek dialytika tonos and other Greek letters. -->
+        <!--
+        <switch>
+            <case
+                latin:keyboardSetElement="alphabetManualShifted|alphabetShiftLockShifted"
+            >
+                U+0385: "΅" GREEK DIALYTIKA TONOS
+                <Key
+                    latin:keyLabel="&#x0385;" />
+            </case>
+            <default>
+        -->
+                <!-- U+03C2: "ς" GREEK SMALL LETTER FINAL SIGMA -->
+                <Key
+                    latin:keyLabel="&#x03C2;"
+                    latin:keyLabelFlags="preserveCase" />
+        <!--
+            </default>
+        </switch>
+        -->
+        <!-- U+03B5: "ε" GREEK SMALL LETTER EPSILON
+             U+03AD: "έ" GREEK SMALL LETTER EPSILON WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03B5;"
+            latin:moreKeys="&#x03AD;" />
+        <!-- U+03C1: "ρ" GREEK SMALL LETTER RHO -->
+        <Key
+            latin:keyLabel="&#x03C1;" />
+        <!-- U+03C4: "τ" GREEK SMALL LETTER TAU -->
+        <Key
+            latin:keyLabel="&#x03C4;" />
+        <!-- U+03C5: "υ" GREEK SMALL LETTER UPSILON
+             U+03CD: "ύ" GREEK SMALL LETTER UPSILON WITH TONOS
+             U+03CB: "ϋ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+             U+03B0: "ΰ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -->
+        <Key
+            latin:keyLabel="&#x03C5;"
+            latin:moreKeys="&#x03CD;,&#x03CB;,&#x03B0;" />
+        <!-- U+03B8: "θ" GREEK SMALL LETTER THETA -->
+        <Key
+            latin:keyLabel="&#x03B8;" />
+        <!-- U+03B9: "ι" GREEK SMALL LETTER IOTA
+             U+03AF: "ί" GREEK SMALL LETTER IOTA WITH TONOS
+             U+03CA: "ϊ" GREEK SMALL LETTER IOTA WITH DIALYTIKA
+             U+0390: "ΐ" GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -->
+        <Key
+            latin:keyLabel="&#x03B9;"
+            latin:moreKeys="&#x03AF;,&#x03CA;,&#x0390;" />
+        <!-- U+03BF: "ο" GREEK SMALL LETTER OMICRON
+             U+03CC: "ό" GREEK SMALL LETTER OMICRON WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03BF;"
+            latin:moreKeys="&#x03CC;" />
+        <!-- U+03C0: "π" GREEK SMALL LETTER PI -->
+        <Key
+            latin:keyLabel="&#x03C0;" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyXPos="-9.219%p"
+            latin:keyWidth="fillBoth" />
+    </Row>
+    <Row
+        latin:keyWidth="8.125%p"
+    >
+        <Key
+            latin:keyStyle="toSymbolKeyStyle"
+            latin:keyLabelFlags="alignLeft"
+            latin:keyWidth="11.172%p"/>
+        <!-- U+03B1: "α" GREEK SMALL LETTER ALPHA
+             U+03AC: "ά" GREEK SMALL LETTER ALPHA WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03B1;"
+            latin:moreKeys="&#x03AC;" />
+        <!-- U+03C3: "σ" GREEK SMALL LETTER SIGMA -->
+        <Key
+            latin:keyLabel="&#x03C3;" />
+        <!-- U+03B4: "δ" GREEK SMALL LETTER DELTA -->
+        <Key
+            latin:keyLabel="&#x03B4;" />
+        <!-- U+03C6: "φ" GREEK SMALL LETTER PHI -->
+        <Key
+            latin:keyLabel="&#x03C6;" />
+        <!-- U+03B3: "γ" GREEK SMALL LETTER GAMMA -->
+        <Key
+            latin:keyLabel="&#x03B3;" />
+        <!-- U+03B7: "η" GREEK SMALL LETTER ETA
+             U+03AE: "ή" GREEK SMALL LETTER ETA WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03B7;"
+            latin:moreKeys="&#x03AE;" />
+        <!-- U+03BE: "ξ" GREEK SMALL LETTER XI -->
+        <Key
+            latin:keyLabel="&#x03BE;" />
+        <!-- U+03BA: "κ" GREEK SMALL LETTER KAPPA -->
+        <Key
+            latin:keyLabel="&#x03BA;" />
+        <!-- U+03BB: "λ" GREEK SMALL LETTER LAMDA -->
+        <Key
+            latin:keyLabel="&#x03BB;" />
+        <Key
+            latin:keyStyle="enterKeyStyle"
+            latin:keyXPos="-15.704%p"
+            latin:keyWidth="fillBoth" />
+    </Row>
+    <Row
+        latin:keyWidth="8.047%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="13.829%p" />
+        <!-- U+03B6: "ζ" GREEK SMALL LETTER ZETA -->
+        <Key
+            latin:keyLabel="&#x03B6;" />
+        <!-- U+03C7: "χ" GREEK SMALL LETTER CHI -->
+        <Key
+            latin:keyLabel="&#x03C7;" />
+        <!-- U+03C8: "ψ" GREEK SMALL LETTER PSI -->
+        <Key
+            latin:keyLabel="&#x03C8;" />
+        <!-- U+03C9: "ω" GREEK SMALL LETTER OMEGA
+             U+03CE: "ώ" GREEK SMALL LETTER OMEGA WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03C9;"
+            latin:moreKeys="&#x03CE;" />
+        <!-- U+03B2: "β" GREEK SMALL LETTER BETA -->
+        <Key
+            latin:keyLabel="&#x03B2;" />
+        <!-- U+03BD: "ν" GREEK SMALL LETTER NU -->
+        <Key
+            latin:keyLabel="&#x03BD;" />
+        <!-- U+03BC: "μ" GREEK SMALL LETTER MU -->
+        <Key
+            latin:keyLabel="&#x03BC;" />
+        <include
+            latin:keyboardLayout="@xml/keys_comma_period" />
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyXPos="-13.750%p"
+            latin:keyWidth="fillBoth" />
+    </Row>
+   <include
+        latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/res/xml-sw768dp/rows_number_normal.xml b/java/res/xml-sw768dp/rows_number_normal.xml
index 60674cd..8bf1a17 100644
--- a/java/res/xml-sw768dp/rows_number_normal.xml
+++ b/java/res/xml-sw768dp/rows_number_normal.xml
@@ -65,10 +65,24 @@
             latin:keyLabel="/"
             latin:keyStyle="numKeyStyle"
             latin:keyWidth="8.047%p" />
-        <Key
-            latin:keyLabel=","
-            latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+        <switch>
+            <case
+                latin:mode="time|datetime"
+            >
+                <Key
+                    latin:keyLabel=","
+                    latin:keyLabelFlags="hasPopupHint"
+                    latin:moreKeys="@string/more_keys_for_am_pm"
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="8.047%p" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel=","
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="8.047%p" />
+            </default>
+        </switch>
         <Key
             latin:keyLabel="4"
             latin:keyStyle="numKeyStyle"
@@ -96,10 +110,22 @@
             latin:keyLabel=")"
             latin:keyStyle="numKeyStyle"
             latin:keyWidth="8.047%p" />
-        <Key
-            latin:keyLabel="="
-            latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+        <switch>
+            <case
+                latin:mode="time|datetime"
+            >
+                <Key
+                    latin:keyLabel=":"
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="8.047%p" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel="="
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="8.047%p" />
+            </default>
+        </switch>
         <Key
             latin:keyLabel="7"
             latin:keyStyle="numKeyStyle"
diff --git a/java/res/xml-sw768dp/rows_serbian.xml b/java/res/xml-sw768dp/rows_serbian.xml
index 39907c8..62668e5 100644
--- a/java/res/xml-sw768dp/rows_serbian.xml
+++ b/java/res/xml-sw768dp/rows_serbian.xml
@@ -37,22 +37,23 @@
             latin:keyLabel="&#x045A;" />
         <!-- U+0435: "е" CYRILLIC SMALL LETTER IE -->
         <Key
-            latin:keyLabel="&#x0435;" />
+            latin:keyLabel="&#x0435;"
+            latin:moreKeys="@string/more_keys_for_cyrillic_ie" />
         <!-- U+0440: "р" CYRILLIC SMALL LETTER ER -->
         <Key
             latin:keyLabel="&#x0440;" />
         <!-- U+0442: "т" CYRILLIC SMALL LETTER TE -->
         <Key
             latin:keyLabel="&#x0442;" />
-        <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
         <Key
-            latin:keyLabel="&#x0437;" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_ze" />
         <!-- U+0443: "у" CYRILLIC SMALL LETTER U -->
         <Key
             latin:keyLabel="&#x0443;" />
         <!-- U+0438: "и" CYRILLIC SMALL LETTER I -->
         <Key
-            latin:keyLabel="&#x0438;" />
+            latin:keyLabel="&#x0438;"
+            latin:moreKeys="@string/more_keys_for_cyrillic_i" />
         <!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
         <Key
             latin:keyLabel="&#x043E;" />
@@ -107,9 +108,8 @@
         <!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE -->
         <Key
             latin:keyLabel="&#x0447;" />
-        <!-- U+045B: "ћ" CYRILLIC SMALL LETTER TSHE -->
         <Key
-            latin:keyLabel="&#x045B;" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_tshe" />
         <Key
             latin:keyStyle="deleteKeyStyle"
             latin:keyXPos="-9.219%p"
@@ -121,9 +121,8 @@
         <Key
             latin:keyStyle="shiftKeyStyle"
             latin:keyWidth="13.829%p" />
-        <!-- U+0455: "ѕ" CYRILLIC SMALL LETTER DZE -->
         <Key
-            latin:keyLabel="&#x0455;" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_dze" />
         <!-- U+045F: "џ" CYRILLIC SMALL LETTER DZHE -->
         <Key
             latin:keyLabel="&#x045F;" />
@@ -142,6 +141,8 @@
         <!-- U+043C: "м" CYRILLIC SMALL LETTER EM -->
         <Key
             latin:keyLabel="&#x043C;" />
+        <Key
+            latin:keyLabel="@string/keylabel_for_cyrillic_dje" />
         <include
             latin:keyboardLayout="@xml/keys_comma_period" />
         <Key
diff --git a/java/res/xml-sw768dp/rows_slavic.xml b/java/res/xml-sw768dp/rows_slavic.xml
index 26857ae..3611ef6 100644
--- a/java/res/xml-sw768dp/rows_slavic.xml
+++ b/java/res/xml-sw768dp/rows_slavic.xml
@@ -38,18 +38,18 @@
         <!-- U+0443: "у" CYRILLIC SMALL LETTER U -->
         <Key
             latin:keyLabel="&#x0443;"
-            latin:moreKeys="@string/more_keys_for_slavic_u" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_u" />
         <!-- U+043A: "к" CYRILLIC SMALL LETTER KA -->
         <Key
             latin:keyLabel="&#x043A;" />
         <!-- U+0435: "е" CYRILLIC SMALL LETTER IE -->
         <Key
             latin:keyLabel="&#x0435;"
-            latin:moreKeys="@string/more_keys_for_slavic_ye" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_ye" />
         <!-- U+043D: "н" CYRILLIC SMALL LETTER EN -->
         <Key
             latin:keyLabel="&#x043D;"
-            latin:moreKeys="@string/more_keys_for_slavic_en" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_en" />
         <!-- U+0433: "г" CYRILLIC SMALL LETTER GHE -->
         <Key
             latin:keyLabel="&#x0433;" />
@@ -57,7 +57,7 @@
         <Key
             latin:keyLabel="&#x0448;" />
         <Key
-            latin:keyLabel="@string/keylabel_for_slavic_shcha" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_shcha" />
         <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
         <Key
             latin:keyLabel="&#x0437;" />
@@ -82,8 +82,8 @@
         <Key
             latin:keyLabel="&#x0444;" />
         <Key
-            latin:keyLabel="@string/keylabel_for_slavic_yery"
-            latin:moreKeys="@string/more_keys_for_slavic_yery" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_yery"
+            latin:moreKeys="@string/more_keys_for_cyrillic_yery" />
         <!-- U+0432: "в" CYRILLIC SMALL LETTER VE -->
         <Key
             latin:keyLabel="&#x0432;" />
@@ -99,7 +99,7 @@
         <!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
         <Key
             latin:keyLabel="&#x043E;"
-            latin:moreKeys="@string/more_keys_for_slavic_o" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_o" />
         <!-- U+043B: "л" CYRILLIC SMALL LETTER EL -->
         <Key
             latin:keyLabel="&#x043B;" />
@@ -136,7 +136,7 @@
         <Key
             latin:keyLabel="&#x043C;" />
         <Key
-            latin:keyLabel="@string/keylabel_for_slavic_i" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_i" />
         <!-- U+0442: "т" CYRILLIC SMALL LETTER TE -->
         <Key
             latin:keyLabel="&#x0442;" />
diff --git a/java/res/xml/kbd_greek.xml b/java/res/xml/kbd_greek.xml
new file mode 100644
index 0000000..7056efb
--- /dev/null
+++ b/java/res/xml/kbd_greek.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/rows_greek" />
+</Keyboard>
diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml
index f0ea8ce..76eacb6 100644
--- a/java/res/xml/key_styles_common.xml
+++ b/java/res/xml/key_styles_common.xml
@@ -79,6 +79,15 @@
     <include
         latin:keyboardLayout="@xml/key_styles_enter" />
     <switch>
+        <!-- Shift + Enter in textMultiLine field. -->
+        <case
+            latin:isMultiLine="true"
+            latin:keyboardSetElement="alphabetManualShifted|alphabetShiftLockShifted"
+        >
+            <key-style
+                latin:styleName="enterKeyStyle"
+                latin:parentStyle="defaultEnterKeyStyle" />
+        </case>
         <!-- Smiley in textShortMessage field.
              Overrides common enter key style. -->
         <case
diff --git a/java/res/xml/key_styles_enter.xml b/java/res/xml/key_styles_enter.xml
index 4c31c3e..03bcb86 100644
--- a/java/res/xml/key_styles_enter.xml
+++ b/java/res/xml/key_styles_enter.xml
@@ -49,7 +49,7 @@
             <key-style
                 latin:styleName="navigateMoreKeysStyle"
                 latin:keyLabelFlags="hasPopupHint|preserveCase"
-                latin:moreKeys="!fixedColumnOrder!2,\@string/action_previous_as_more_key,\@string/action_next_as_more_key" />
+                latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,@string/action_previous_as_more_key,@string/action_next_as_more_key" />
         </case>
         <case
             latin:navigateNext="true"
diff --git a/java/res/xml/key_styles_number.xml b/java/res/xml/key_styles_number.xml
index 01f7aee..3627836 100644
--- a/java/res/xml/key_styles_number.xml
+++ b/java/res/xml/key_styles_number.xml
@@ -41,9 +41,12 @@
         latin:styleName="numberKeyStyle"
         latin:keyLabelFlags="alignLeftOfCenter|hasHintLabel"
         latin:parentStyle="numKeyStyle" />
+    <!-- U+0030: "0" DIGIT ZERO
+         U+002B: "+" PLUS SIGN -->
     <key-style
         latin:styleName="num0KeyStyle"
-        latin:code="48"
+        latin:code="0x0030"
+        latin:altCode="0x002B"
         latin:keyLabel="0 +"
         latin:keyActionFlags="enableLongPress"
         latin:parentStyle="numberKeyStyle" />
@@ -91,10 +94,11 @@
         latin:keyLabel="9"
         latin:keyHintLabel="WXYZ"
         latin:parentStyle="numberKeyStyle" />
-    <!-- U+FF0A: "*" FULLWIDTH ASTERISK -->
+    <!-- U+002A: "*" ASTERISK
+         U+FF0A: "*" FULLWIDTH ASTERISK -->
     <key-style
         latin:styleName="numStarKeyStyle"
-        latin:code="42"
+        latin:code="0x002A"
         latin:keyLabel="&#xFF0A;"
         latin:parentStyle="numKeyStyle" />
     <!-- Only for non-tablet device -->
@@ -108,15 +112,17 @@
         latin:code="@integer/key_switch_alpha_symbol"
         latin:keyLabel="@string/label_to_phone_numeric_key"
         latin:parentStyle="numModeKeyStyle" />
+    <!-- U+002C: "," COMMA -->
     <key-style
         latin:styleName="numPauseKeyStyle"
-        latin:code="44"
+        latin:code="0x002C"
         latin:keyLabel="@string/label_pause_key"
         latin:keyLabelFlags="followKeyHintLabelRatio|autoXScale"
         latin:parentStyle="numKeyBaseStyle" />
+    <!-- U+003B: ";" SEMICOLON -->
     <key-style
         latin:styleName="numWaitKeyStyle"
-        latin:code="59"
+        latin:code="0x003B"
         latin:keyLabel="@string/label_wait_key"
         latin:keyLabelFlags="followKeyHintLabelRatio|autoXScale"
         latin:parentStyle="numKeyBaseStyle" />
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index 98dc766..8b1a3ef 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -20,8 +20,9 @@
 <!-- The attributes in this XML file provide configuration information -->
 <!-- for the Input Method Manager. -->
 
-<!-- Keyboard: en_US, en_GB, ar, be, bg, cs, da, de, de(QWERTY), es, es_US, et, fi, fr, fr_CA,
-     fr_CH, hr, hu, it, iw, ka, ky, lt, lv, nb, nl, pl, pt, ro, ru, sk, sl, sr, sv, tr, uk, vi -->
+<!-- Keyboard: en_US, en_GB, ar, be, bg, cs, da, de, de(QWERTY), el, es, es_US, et, fi, fr, fr_CA,
+     fr_CH, hr, hu, it, iw, ka, ky, lt, lv, mk, nb, nl, pl, pt, ro, ru, sk, sl, sr, sv, tr, uk,
+     vi -->
 <!-- TODO: use <lang>_keyboard icon instead of a common keyboard icon. -->
 <!-- If IME doesn't have an applicable subtype, the first subtype will be used as a default
      subtype.-->
@@ -84,6 +85,12 @@
     />
     <subtype android:icon="@drawable/ic_subtype_keyboard"
             android:label="@string/subtype_generic"
+            android:imeSubtypeLocale="el"
+            android:imeSubtypeMode="keyboard"
+            android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard"
+            android:label="@string/subtype_generic"
             android:imeSubtypeLocale="es"
             android:imeSubtypeMode="keyboard"
             android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
@@ -169,6 +176,12 @@
     />
     <subtype android:icon="@drawable/ic_subtype_keyboard"
             android:label="@string/subtype_generic"
+            android:imeSubtypeLocale="mk"
+            android:imeSubtypeMode="keyboard"
+            android:imeSubtypeExtraValue="SupportTouchPositionCorrection"
+    />
+    <subtype android:icon="@drawable/ic_subtype_keyboard"
+            android:label="@string/subtype_generic"
             android:imeSubtypeLocale="nb"
             android:imeSubtypeMode="keyboard"
             android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
diff --git a/java/res/xml/rows_greek.xml b/java/res/xml/rows_greek.xml
new file mode 100644
index 0000000..1602c50
--- /dev/null
+++ b/java/res/xml/rows_greek.xml
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/key_styles_common" />
+    <Row
+        latin:keyWidth="10%p"
+    >
+        <Key
+            latin:keyLabel=";"
+            latin:keyHintLabel="1"
+            latin:additionalMoreKeys="1" />
+        <!-- TODO: Should find a way to compound Greek dialytika tonos and other Greek letters. -->
+        <!--
+        <switch>
+            <case
+                latin:keyboardSetElement="alphabetManualShifted|alphabetShiftLockShifted"
+            >
+                U+0385: "΅" GREEK DIALYTIKA TONOS
+                <Key
+                    latin:keyLabel="&#x0385;"
+                    latin:keyHintLabel="2"
+                    latin:additionalMoreKeys="2" />
+            </case>
+            <default>
+        -->
+                <!-- U+03C2: "ς" GREEK SMALL LETTER FINAL SIGMA -->
+                <Key
+                    latin:keyLabel="&#x03C2;"
+                    latin:keyLabelFlags="preserveCase"
+                    latin:keyHintLabel="2"
+                    latin:additionalMoreKeys="2" />
+        <!--
+            </default>
+        </switch>
+        -->
+        <!-- U+03B5: "ε" GREEK SMALL LETTER EPSILON
+             U+03AD: "έ" GREEK SMALL LETTER EPSILON WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03B5;"
+            latin:keyHintLabel="3"
+            latin:additionalMoreKeys="3"
+            latin:moreKeys="&#x03AD;" />
+        <!-- U+03C1: "ρ" GREEK SMALL LETTER RHO -->
+        <Key
+            latin:keyLabel="&#x03C1;"
+            latin:keyHintLabel="4"
+            latin:additionalMoreKeys="4" />
+        <!-- U+03C4: "τ" GREEK SMALL LETTER TAU -->
+        <Key
+            latin:keyLabel="&#x03C4;"
+            latin:keyHintLabel="5"
+            latin:additionalMoreKeys="5" />
+        <!-- U+03C5: "υ" GREEK SMALL LETTER UPSILON
+             U+03CD: "ύ" GREEK SMALL LETTER UPSILON WITH TONOS
+             U+03CB: "ϋ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+             U+03B0: "ΰ" GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -->
+        <Key
+            latin:keyLabel="&#x03C5;"
+            latin:keyHintLabel="6"
+            latin:additionalMoreKeys="6"
+            latin:moreKeys="&#x03CD;,&#x03CB;,&#x03B0;" />
+        <!-- U+03B8: "θ" GREEK SMALL LETTER THETA -->
+        <Key
+            latin:keyLabel="&#x03B8;"
+            latin:keyHintLabel="7"
+            latin:additionalMoreKeys="7" />
+        <!-- U+03B9: "ι" GREEK SMALL LETTER IOTA
+             U+03AF: "ί" GREEK SMALL LETTER IOTA WITH TONOS
+             U+03CA: "ϊ" GREEK SMALL LETTER IOTA WITH DIALYTIKA
+             U+0390: "ΐ" GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -->
+        <Key
+            latin:keyLabel="&#x03B9;"
+            latin:keyHintLabel="8"
+            latin:additionalMoreKeys="8"
+            latin:moreKeys="&#x03AF;,&#x03CA;,&#x0390;" />
+        <!-- U+03BF: "ο" GREEK SMALL LETTER OMICRON
+             U+03CC: "ό" GREEK SMALL LETTER OMICRON WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03BF;"
+            latin:keyHintLabel="9"
+            latin:additionalMoreKeys="9"
+            latin:moreKeys="&#x03CC;" />
+        <!-- U+03C0: "π" GREEK SMALL LETTER PI -->
+        <Key
+            latin:keyLabel="&#x03C0;"
+            latin:keyHintLabel="0"
+            latin:additionalMoreKeys="0"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <Row
+        latin:keyWidth="10%p"
+    >
+        <!-- U+03B1: "α" GREEK SMALL LETTER ALPHA
+             U+03AC: "ά" GREEK SMALL LETTER ALPHA WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03B1;"
+            latin:moreKeys="&#x03AC;"
+            latin:keyXPos="5%p" />
+        <!-- U+03C3: "σ" GREEK SMALL LETTER SIGMA -->
+        <Key
+            latin:keyLabel="&#x03C3;" />
+        <!-- U+03B4: "δ" GREEK SMALL LETTER DELTA -->
+        <Key
+            latin:keyLabel="&#x03B4;" />
+        <!-- U+03C6: "φ" GREEK SMALL LETTER PHI -->
+        <Key
+            latin:keyLabel="&#x03C6;" />
+        <!-- U+03B3: "γ" GREEK SMALL LETTER GAMMA -->
+        <Key
+            latin:keyLabel="&#x03B3;" />
+        <!-- U+03B7: "η" GREEK SMALL LETTER ETA
+             U+03AE: "ή" GREEK SMALL LETTER ETA WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03B7;"
+            latin:moreKeys="&#x03AE;" />
+        <!-- U+03BE: "ξ" GREEK SMALL LETTER XI -->
+        <Key
+            latin:keyLabel="&#x03BE;" />
+        <!-- U+03BA: "κ" GREEK SMALL LETTER KAPPA -->
+        <Key
+            latin:keyLabel="&#x03BA;" />
+        <!-- U+03BB: "λ" GREEK SMALL LETTER LAMDA -->
+        <Key
+            latin:keyLabel="&#x03BB;" />
+        <!-- Here is 5%p space -->
+    </Row>
+    <Row
+        latin:keyWidth="10%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="15%p"
+            latin:visualInsetsRight="1%p" />
+        <!-- U+03B6: "ζ" GREEK SMALL LETTER ZETA -->
+        <Key
+            latin:keyLabel="&#x03B6;" />
+        <!-- U+03C7: "χ" GREEK SMALL LETTER CHI -->
+        <Key
+            latin:keyLabel="&#x03C7;" />
+        <!-- U+03C8: "ψ" GREEK SMALL LETTER PSI -->
+        <Key
+            latin:keyLabel="&#x03C8;" />
+        <!-- U+03C9: "ω" GREEK SMALL LETTER OMEGA
+             U+03CE: "ώ" GREEK SMALL LETTER OMEGA WITH TONOS -->
+        <Key
+            latin:keyLabel="&#x03C9;"
+            latin:moreKeys="&#x03CE;" />
+        <!-- U+03B2: "β" GREEK SMALL LETTER BETA -->
+        <Key
+            latin:keyLabel="&#x03B2;" />
+        <!-- U+03BD: "ν" GREEK SMALL LETTER NU -->
+        <Key
+            latin:keyLabel="&#x03BD;" />
+        <!-- U+03BC: "μ" GREEK SMALL LETTER MU -->
+        <Key
+            latin:keyLabel="&#x03BC;" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="fillRight"
+            latin:visualInsetsLeft="1%p" />
+    </Row>
+   <include
+        latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/res/xml/rows_number_normal.xml b/java/res/xml/rows_number_normal.xml
index b581fb5..91b1fe9 100644
--- a/java/res/xml/rows_number_normal.xml
+++ b/java/res/xml/rows_number_normal.xml
@@ -46,10 +46,32 @@
         <Key
             latin:keyLabel="6"
             latin:keyStyle="numKeyStyle" />
-        <Key
-            latin:keyLabel=","
-            latin:keyStyle="numFunctionalKeyStyle"
-            latin:keyWidth="fillRight" />
+        <switch>
+            <case
+                latin:mode="date"
+            >
+                <Key
+                    latin:keyLabel="."
+                    latin:keyStyle="numFunctionalKeyStyle"
+                    latin:keyWidth="fillRight" />
+            </case>
+            <case
+                latin:mode="time|datetime"
+            >
+                <Key
+                    latin:keyLabel="."
+                    latin:keyLabelFlags="hasPopupHint"
+                    latin:moreKeys="@string/more_keys_for_am_pm"
+                    latin:keyStyle="numFunctionalKeyStyle"
+                    latin:keyWidth="fillRight" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel=","
+                    latin:keyStyle="numFunctionalKeyStyle"
+                    latin:keyWidth="fillRight" />
+            </default>
+        </switch>
     </Row>
     <Row>
         <Key
@@ -71,9 +93,39 @@
         <Key
             latin:keyLabel="0"
             latin:keyStyle="numKeyStyle" />
-        <Key
-            latin:keyLabel="."
-            latin:keyStyle="numKeyStyle" />
+        <switch>
+            <case
+                latin:mode="date"
+            >
+                <Key
+                    latin:keyLabel="/"
+                    latin:keyStyle="numKeyStyle" />
+            </case>
+            <case
+                latin:mode="time"
+            >
+                <Key
+                    latin:keyLabel=":"
+                    latin:keyStyle="numKeyStyle" />
+            </case>
+            <case
+                latin:mode="datetime"
+            >
+                <!-- U+002F: "/" SOLIDUS
+                     U+003A: ":" COLON -->
+                <Key
+                    latin:code="0x002F"
+                    latin:altCode="0x003A"
+                    latin:keyLabel="/ :"
+                    latin:keyActionFlags="enableLongPress"
+                    latin:keyStyle="numKeyStyle" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel="."
+                    latin:keyStyle="numKeyStyle" />
+            </default>
+        </switch>
         <Key
             latin:keyStyle="enterKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/res/xml/rows_serbian.xml b/java/res/xml/rows_serbian.xml
index cf52fe0..ed33dc7 100644
--- a/java/res/xml/rows_serbian.xml
+++ b/java/res/xml/rows_serbian.xml
@@ -40,7 +40,8 @@
         <Key
             latin:keyLabel="&#x0435;"
             latin:keyHintLabel="3"
-            latin:additionalMoreKeys="3" />
+            latin:additionalMoreKeys="3"
+            latin:moreKeys="@string/more_keys_for_cyrillic_ie" />
         <!-- U+0440: "р" CYRILLIC SMALL LETTER ER -->
         <Key
             latin:keyLabel="&#x0440;"
@@ -51,9 +52,8 @@
             latin:keyLabel="&#x0442;"
             latin:keyHintLabel="5"
             latin:additionalMoreKeys="5" />
-        <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
         <Key
-            latin:keyLabel="&#x0437;"
+            latin:keyLabel="@string/keylabel_for_cyrillic_ze"
             latin:keyHintLabel="6"
             latin:additionalMoreKeys="6" />
         <!-- U+0443: "у" CYRILLIC SMALL LETTER U -->
@@ -65,7 +65,8 @@
         <Key
             latin:keyLabel="&#x0438;"
             latin:keyHintLabel="8"
-            latin:additionalMoreKeys="8" />
+            latin:additionalMoreKeys="8"
+            latin:moreKeys="@string/more_keys_for_cyrillic_i" />
         <!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
         <Key
             latin:keyLabel="&#x043E;"
@@ -114,9 +115,8 @@
         <!-- U+0447: "ч" CYRILLIC SMALL LETTER CHE -->
         <Key
             latin:keyLabel="&#x0447;" />
-        <!-- U+045B: "ћ" CYRILLIC SMALL LETTER TSHE -->
         <Key
-            latin:keyLabel="&#x045B;"
+            latin:keyLabel="@string/keylabel_for_cyrillic_tshe"
             latin:keyWidth="fillRight" />
     </Row>
     <Row
@@ -125,9 +125,8 @@
         <Key
             latin:keyStyle="shiftKeyStyle"
             latin:keyWidth="11.75%p" />
-        <!-- U+0455: "ѕ" CYRILLIC SMALL LETTER DZE -->
         <Key
-            latin:keyLabel="&#x0455;" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_dze" />
         <!-- U+045F: "џ" CYRILLIC SMALL LETTER DZHE -->
         <Key
             latin:keyLabel="&#x045F;" />
@@ -146,9 +145,8 @@
         <!-- U+043C: "м" CYRILLIC SMALL LETTER EM -->
         <Key
             latin:keyLabel="&#x043C;" />
-        <!-- U+0452: "ђ" CYRILLIC SMALL LETTER DJE -->
         <Key
-            latin:keyLabel="&#x0452;" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_dje" />
         <!-- U+0436: "ж" CYRILLIC SMALL LETTER ZHE -->
         <Key
             latin:keyLabel="&#x0436;" />
diff --git a/java/res/xml/rows_slavic.xml b/java/res/xml/rows_slavic.xml
index 4099edd..d75f209 100644
--- a/java/res/xml/rows_slavic.xml
+++ b/java/res/xml/rows_slavic.xml
@@ -41,7 +41,7 @@
             latin:keyLabel="&#x0443;"
             latin:keyHintLabel="3"
             latin:additionalMoreKeys="3"
-            latin:moreKeys="@string/more_keys_for_slavic_u" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_u" />
         <!-- U+043A: "к" CYRILLIC SMALL LETTER KA -->
         <Key
             latin:keyLabel="&#x043A;"
@@ -52,13 +52,13 @@
             latin:keyLabel="&#x0435;"
             latin:keyHintLabel="5"
             latin:additionalMoreKeys="5"
-            latin:moreKeys="@string/more_keys_for_slavic_ye" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_ye" />
         <!-- U+043D: "н" CYRILLIC SMALL LETTER EN -->
         <Key
             latin:keyLabel="&#x043D;"
             latin:keyHintLabel="6"
             latin:additionalMoreKeys="6"
-            latin:moreKeys="@string/more_keys_for_slavic_en" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_en" />
         <!-- U+0433: "г" CYRILLIC SMALL LETTER GHE -->
         <Key
             latin:keyLabel="&#x0433;"
@@ -70,7 +70,7 @@
             latin:keyHintLabel="8"
             latin:additionalMoreKeys="8" />
         <Key
-            latin:keyLabel="@string/keylabel_for_slavic_shcha"
+            latin:keyLabel="@string/keylabel_for_cyrillic_shcha"
             latin:keyHintLabel="9"
             latin:additionalMoreKeys="9" />
         <!-- U+0437: "з" CYRILLIC SMALL LETTER ZE -->
@@ -81,7 +81,7 @@
         <!-- U+0445: "х" CYRILLIC SMALL LETTER HA -->
         <Key
             latin:keyLabel="&#x0445;"
-            latin:moreKeys="@string/more_keys_for_slavic_ha"
+            latin:moreKeys="@string/more_keys_for_cyrillic_ha"
             latin:keyWidth="fillRight" />
     </Row>
     <Row
@@ -91,8 +91,8 @@
         <Key
             latin:keyLabel="&#x0444;" />
         <Key
-            latin:keyLabel="@string/keylabel_for_slavic_yery"
-            latin:moreKeys="@string/more_keys_for_slavic_yery" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_yery"
+            latin:moreKeys="@string/more_keys_for_cyrillic_yery" />
         <!-- U+0432: "в" CYRILLIC SMALL LETTER VE -->
         <Key
             latin:keyLabel="&#x0432;" />
@@ -108,7 +108,7 @@
         <!-- U+043E: "о" CYRILLIC SMALL LETTER O -->
         <Key
             latin:keyLabel="&#x043E;"
-            latin:moreKeys="@string/more_keys_for_slavic_o" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_o" />
         <!-- U+043B: "л" CYRILLIC SMALL LETTER EL -->
         <Key
             latin:keyLabel="&#x043B;" />
@@ -142,14 +142,14 @@
         <Key
             latin:keyLabel="&#x043C;" />
         <Key
-            latin:keyLabel="@string/keylabel_for_slavic_i" />
+            latin:keyLabel="@string/keylabel_for_cyrillic_i" />
         <!-- U+0442: "т" CYRILLIC SMALL LETTER TE -->
         <Key
             latin:keyLabel="&#x0442;" />
         <!-- U+044C: "ь" CYRILLIC SMALL LETTER SOFT SIGN -->
         <Key
             latin:keyLabel="&#x044C;"
-            latin:moreKeys="@string/more_keys_for_slavic_soft_sign" />
+            latin:moreKeys="@string/more_keys_for_cyrillic_soft_sign" />
         <!-- U+0431: "б" CYRILLIC SMALL LETTER BE -->
         <Key
             latin:keyLabel="&#x0431;" />
diff --git a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
index 5c4e9af..700709d 100644
--- a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
+++ b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java
@@ -435,44 +435,6 @@
         }
     }
 
-    /**
-     * 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(EditingUtils.SelectedWord touching) {
-        if (!VOICE_INSTALLED) {
-            return false;
-        }
-        // Search for result in spoken word alternatives
-        String selectedWord = touching.mWord.toString().trim();
-        if (!mWordToSuggestions.containsKey(selectedWord)) {
-            selectedWord = selectedWord.toLowerCase();
-        }
-        if (mWordToSuggestions.containsKey(selectedWord)) {
-            mShowingVoiceSuggestions = true;
-            List<CharSequence> suggestions = mWordToSuggestions.get(selectedWord);
-            SuggestedWords.Builder builder = new SuggestedWords.Builder();
-            // If the first letter of touching is capitalized, make all the suggestions
-            // start with a capital letter.
-            if (Character.isUpperCase(touching.mWord.charAt(0))) {
-                for (CharSequence word : suggestions) {
-                    String str = word.toString();
-                    word = Character.toUpperCase(str.charAt(0)) + str.substring(1);
-                    builder.addWord(word);
-                }
-            } else {
-                builder.addWords(suggestions, null);
-            }
-            builder.setTypedWordValid(true).setHasMinimalSuggestion(true);
-            mService.setSuggestions(builder.build());
-//            mService.setCandidatesViewShown(true);
-            return true;
-        }
-        return false;
-    }
-
     public void handleBackspace() {
         if (!VOICE_INSTALLED) {
             return;
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index f839376..a719b4a 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -62,7 +62,7 @@
     private static final int LABEL_FLAGS_LARGE_LETTER = 0x10;
     private static final int LABEL_FLAGS_FONT_NORMAL = 0x20;
     private static final int LABEL_FLAGS_FONT_MONO_SPACE = 0x40;
-    private static final int LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO = 0x80;
+    public static final int LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO = 0x80;
     private static final int LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO = 0x100;
     private static final int LABEL_FLAGS_HAS_POPUP_HINT = 0x200;
     private static final int LABEL_FLAGS_HAS_SHIFTED_LETTER_HINT = 0x400;
@@ -103,11 +103,16 @@
     public final CharSequence mOutputText;
     /** More keys */
     public final String[] mMoreKeys;
-    /** More keys maximum column number */
-    public final int mMaxMoreKeysColumn;
-    public static final int MORE_KEYS_FIXED_COLUMN_ORDER = 0x80000000;
-    private static final String AUTO_COLUMN_ORDER = "!autoColumnOrder!";
-    private static final String FIXED_COLUMN_ORDER = "!fixedColumnOrder!";
+    /** More keys column number and flags */
+    private final int mMoreKeysColumnAndFlags;
+    private static final int MORE_KEYS_COLUMN_MASK = 0x000000ff;
+    private static final int MORE_KEYS_FLAGS_FIXED_COLUMN_ORDER = 0x80000000;
+    private static final int MORE_KEYS_FLAGS_HAS_LABELS = 0x40000000;
+    private static final int MORE_KEYS_FLAGS_NEEDS_DIVIDERS = 0x40000000;
+    private static final String MORE_KEYS_AUTO_COLUMN_ORDER = "!autoColumnOrder!";
+    private static final String MORE_KEYS_FIXED_COLUMN_ORDER = "!fixedColumnOrder!";
+    private static final String MORE_KEYS_HAS_LABELS = "!hasLabels!";
+    private static final String MORE_KEYS_NEEDS_DIVIDERS = "!needsDividers!";
 
     /** Background type that represents different key background visual than normal one. */
     public final int mBackgroundType;
@@ -134,33 +139,34 @@
      * This constructor is being used only for key in more keys keyboard.
      */
     public Key(Resources res, Keyboard.Params params, String moreKeySpec,
-            int x, int y, int width, int height) {
+            int x, int y, int width, int height, int labelFlags) {
         this(params, KeySpecParser.getLabel(moreKeySpec), null,
                 KeySpecParser.getIconId(moreKeySpec),
                 KeySpecParser.getCode(res, moreKeySpec),
                 KeySpecParser.getOutputText(moreKeySpec),
-                x, y, width, height);
+                x, y, width, height, labelFlags);
     }
 
     /**
      * This constructor is being used only for key in popup suggestions pane.
      */
     public Key(Keyboard.Params params, String label, String hintLabel, int iconId,
-            int code, CharSequence outputText, int x, int y, int width, int height) {
+            int code, String outputText, int x, int y, int width, int height, int labelFlags) {
         mHeight = height - params.mVerticalGap;
         mHorizontalGap = params.mHorizontalGap;
         mVerticalGap = params.mVerticalGap;
         mVisualInsetsLeft = mVisualInsetsRight = 0;
         mWidth = width - mHorizontalGap;
         mHintLabel = hintLabel;
-        mLabelFlags = 0;
+        mLabelFlags = labelFlags;
         mBackgroundType = BACKGROUND_TYPE_NORMAL;
         mActionFlags = 0;
         mMoreKeys = null;
-        mMaxMoreKeysColumn = 0;
+        mMoreKeysColumnAndFlags = 0;
         mLabel = label;
         mOutputText = outputText;
         mCode = code;
+        mEnabled = (code != Keyboard.CODE_UNSPECIFIED);
         mAltCode = Keyboard.CODE_UNSPECIFIED;
         mIconId = iconId;
         mDisabledIconId = KeyboardIconsSet.ICON_UNDEFINED;
@@ -236,15 +242,24 @@
         final boolean preserveCase = (mLabelFlags & LABEL_FLAGS_PRESERVE_CASE) != 0;
         int actionFlags = style.getFlag(keyAttr, R.styleable.Keyboard_Key_keyActionFlags);
         String[] moreKeys = style.getStringArray(keyAttr, R.styleable.Keyboard_Key_moreKeys);
-        int column;
-        if ((column = parseMoreKeysColumnOrder(moreKeys, AUTO_COLUMN_ORDER)) > 0) {
-            mMaxMoreKeysColumn = column;
-        } else if ((column = parseMoreKeysColumnOrder(moreKeys, FIXED_COLUMN_ORDER)) > 0) {
-            mMaxMoreKeysColumn = column | MORE_KEYS_FIXED_COLUMN_ORDER;
-        } else {
-            mMaxMoreKeysColumn = style.getInt(keyAttr,
-                    R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMoreKeysKeyboardColumn);
+
+        int moreKeysColumn = style.getInt(keyAttr,
+                R.styleable.Keyboard_Key_maxMoreKeysColumn, params.mMaxMoreKeysKeyboardColumn);
+        int value;
+        if ((value = KeySpecParser.getIntValue(moreKeys, MORE_KEYS_AUTO_COLUMN_ORDER, -1)) > 0) {
+            moreKeysColumn = value & MORE_KEYS_COLUMN_MASK;
         }
+        if ((value = KeySpecParser.getIntValue(moreKeys, MORE_KEYS_FIXED_COLUMN_ORDER, -1)) > 0) {
+            moreKeysColumn = MORE_KEYS_FLAGS_FIXED_COLUMN_ORDER | (value & MORE_KEYS_COLUMN_MASK);
+        }
+        if (KeySpecParser.getBooleanValue(moreKeys, MORE_KEYS_HAS_LABELS)) {
+            moreKeysColumn |= MORE_KEYS_FLAGS_HAS_LABELS;
+        }
+        if (KeySpecParser.getBooleanValue(moreKeys, MORE_KEYS_NEEDS_DIVIDERS)) {
+            moreKeysColumn |= MORE_KEYS_FLAGS_NEEDS_DIVIDERS;
+        }
+        mMoreKeysColumnAndFlags = moreKeysColumn;
+
         final String[] additionalMoreKeys = style.getStringArray(
                 keyAttr, R.styleable.Keyboard_Key_additionalMoreKeys);
         moreKeys = KeySpecParser.insertAddtionalMoreKeys(moreKeys, additionalMoreKeys);
@@ -311,21 +326,6 @@
         }
     }
 
-    private static int parseMoreKeysColumnOrder(String[] moreKeys, String key) {
-        if (moreKeys == null || moreKeys.length == 0 || moreKeys[0] == null
-                || !moreKeys[0].startsWith(key)) {
-            return -1;
-        }
-        try {
-            final int column = Integer.parseInt(moreKeys[0].substring(key.length()));
-            moreKeys[0] = null;
-            return column;
-        } catch (NumberFormatException e) {
-            Log.w(TAG, "column number should follow after " + key);
-            return 0;
-        }
-    }
-
     private static int adjustCaseOfCodeForKeyboardId(int code, boolean preserveCase,
             KeyboardId id) {
         if (!Keyboard.isLetterCode(code) || preserveCase) return code;
@@ -479,7 +479,7 @@
     }
 
     public int selectTextSize(int letter, int largeLetter, int label, int hintLabel) {
-        if (mLabel.length() > 1
+        if (Utils.codePointCount(mLabel) > 1
                 && (mLabelFlags & (LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO
                         | LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO)) == 0) {
             return label;
@@ -532,6 +532,22 @@
         return (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0;
     }
 
+    public int getMoreKeysColumn() {
+        return mMoreKeysColumnAndFlags & MORE_KEYS_COLUMN_MASK;
+    }
+
+    public boolean isFixedColumnOrderMoreKeys() {
+        return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_FIXED_COLUMN_ORDER) != 0;
+    }
+
+    public boolean hasLabelsInMoreKeys() {
+        return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_HAS_LABELS) != 0;
+    }
+
+    public boolean needsDividersInMoreKeys() {
+        return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_NEEDS_DIVIDERS) != 0;
+    }
+
     public Drawable getIcon(KeyboardIconsSet iconSet) {
         return iconSet.getIconDrawable(mIconId);
     }
@@ -682,7 +698,7 @@
          */
         protected Spacer(Keyboard.Params params, int x, int y, int width, int height) {
             super(params, null, null, KeyboardIconsSet.ICON_UNDEFINED, Keyboard.CODE_UNSPECIFIED,
-                    null, x, y, width, height);
+                    null, x, y, width, height, 0);
         }
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyDetector.java b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
index 0ce98d2..10cf1d1 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyDetector.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyDetector.java
@@ -267,7 +267,7 @@
                 addDelimiter = false;
             } else {
                 if (addDelimiter) sb.append(", ");
-                sb.append(code);
+                sb.append(Keyboard.printableCode(code));
                 addDelimiter = true;
             }
         }
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 30ed59e..c6cdf79 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -85,8 +85,6 @@
     public static final int CODE_CLOSING_SQUARE_BRACKET = ']';
     public static final int CODE_CLOSING_CURLY_BRACKET = '}';
     public static final int CODE_CLOSING_ANGLE_BRACKET = '>';
-    public static final int CODE_DIGIT0 = '0';
-    public static final int CODE_PLUS = '+';
     private static final int MINIMUM_LETTER_CODE = CODE_TAB;
 
     /** Special keys code. Must be negative.
@@ -185,18 +183,11 @@
     }
 
     // TODO: Remove this method.
-    public boolean isShiftLocked() {
-        return mId.isAlphabetShiftLockedKeyboard();
-    }
-
-    // TODO: Remove this method.
     public boolean isShiftedOrShiftLocked() {
-        return mId.isAlphabetShiftedOrShiftLockedKeyboard();
-    }
-
-    // TODO: Remove this method.
-    public boolean isManualShifted() {
-        return mId.isAlphabetManualShiftedKeyboard();
+        // Alphabet mode have unshifted, manual shifted, automatic shifted, shift locked, and
+        // shift lock shifted element. So that unshifed element is the only one that is NOT in
+        // shifted or shift locked state.
+        return mId.isAlphabetKeyboard() && mId.mElementId != KeyboardId.ELEMENT_ALPHABET;
     }
 
     public static boolean isLetterCode(int code) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index ed4a89e..f575296 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -36,6 +36,9 @@
     public static final int MODE_IM = 3;
     public static final int MODE_PHONE = 4;
     public static final int MODE_NUMBER = 5;
+    public static final int MODE_DATE = 6;
+    public static final int MODE_TIME = 7;
+    public static final int MODE_DATETIME = 8;
 
     public static final int ELEMENT_ALPHABET = 0;
     public static final int ELEMENT_ALPHABET_MANUAL_SHIFTED = 1;
@@ -123,31 +126,6 @@
         return mElementId < ELEMENT_SYMBOLS;
     }
 
-    public boolean isAlphabetShiftLockedKeyboard() {
-        return mElementId == ELEMENT_ALPHABET_SHIFT_LOCKED
-                || mElementId == ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED;
-    }
-
-    public boolean isAlphabetShiftedOrShiftLockedKeyboard() {
-        return isAlphabetKeyboard() && mElementId != ELEMENT_ALPHABET;
-    }
-
-    public boolean isAlphabetManualShiftedKeyboard() {
-        return mElementId == ELEMENT_ALPHABET_MANUAL_SHIFTED;
-    }
-
-    public boolean isSymbolsKeyboard() {
-        return mElementId == ELEMENT_SYMBOLS || mElementId == ELEMENT_SYMBOLS_SHIFTED;
-    }
-
-    public boolean isPhoneKeyboard() {
-        return mElementId == ELEMENT_PHONE || mElementId == ELEMENT_PHONE_SYMBOLS;
-    }
-
-    public boolean isPhoneShiftKeyboard() {
-        return mElementId == ELEMENT_PHONE_SYMBOLS;
-    }
-
     public boolean navigateNext() {
         return EditorInfoCompatUtils.hasFlagNavigateNext(mEditorInfo.imeOptions);
     }
@@ -242,6 +220,9 @@
         case MODE_IM: return "im";
         case MODE_PHONE: return "phone";
         case MODE_NUMBER: return "number";
+        case MODE_DATE: return "date";
+        case MODE_TIME: return "time";
+        case MODE_DATETIME: return "datetime";
         default: return null;
         }
     }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
index 6e62f74..ee882ed 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
@@ -131,6 +131,9 @@
             }
             break;
         case KeyboardId.MODE_NUMBER:
+        case KeyboardId.MODE_DATE:
+        case KeyboardId.MODE_TIME:
+        case KeyboardId.MODE_DATETIME:
             keyboardSetElementId = KeyboardId.ELEMENT_NUMBER;
             break;
         default:
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index d65253e..78e0ee2 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -849,7 +849,7 @@
         final KeyPreviewDrawParams params = mKeyPreviewDrawParams;
         final int keyDrawX = key.mX + key.mVisualInsetsLeft;
         final int keyDrawWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight;
-        // What we show as preview should match what we show on key top in onBufferDraw(). 
+        // What we show as preview should match what we show on a key top in onBufferDraw().
         if (key.mLabel != null) {
             // TODO Should take care of temporaryShiftLabel here.
             previewText.setCompoundDrawables(null, null, null, null);
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 00570fb..99bd080 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -41,7 +41,6 @@
 import com.android.inputmethod.deprecated.VoiceProxy;
 import com.android.inputmethod.keyboard.PointerTracker.DrawingProxy;
 import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
-import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.R;
@@ -80,8 +79,6 @@
     private float mSpacebarTextSize;
     private final int mSpacebarTextColor;
     private final int mSpacebarTextShadowColor;
-    // 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;
@@ -398,7 +395,7 @@
         mMoreKeysPanelCache.clear();
 
         mSpaceKey = keyboard.getKey(Keyboard.CODE_SPACE);
-        mSpaceIcon = keyboard.mIconsSet.getIconDrawable(KeyboardIconsSet.ICON_SPACE);
+        mSpaceIcon = (mSpaceKey != null) ? mSpaceKey.getIcon(keyboard.mIconsSet) : null;
         final int keyHeight = keyboard.mMostCommonKeyHeight - keyboard.mVerticalGap;
         mSpacebarTextSize = keyHeight * mSpacebarTextRatio;
         mSpacebarLocale = keyboard.mId.mLocale;
@@ -483,11 +480,13 @@
      */
     protected boolean onLongPress(Key parentKey, PointerTracker tracker) {
         final int primaryCode = parentKey.mCode;
-        final Keyboard keyboard = getKeyboard();
-        if (primaryCode == Keyboard.CODE_DIGIT0 && keyboard.mId.isPhoneKeyboard()) {
+        if (parentKey.mMoreKeys == null && !parentKey.altCodeWhileTyping()
+                && parentKey.mAltCode != Keyboard.CODE_UNSPECIFIED) {
+            // Long press on a key that has no more keys and not altCodeWhileTyping but altCode
+            // defined, such as "0 +" key on phone layout and "/ :" key on datetime
+            // layout.
             tracker.onLongPressed();
-            // Long pressing on 0 in phone number keypad gives you a '+'.
-            invokeCodeInput(Keyboard.CODE_PLUS);
+            invokeCodeInput(parentKey.mAltCode);
             invokeReleaseKey(primaryCode);
             KeyboardSwitcher.getInstance().hapticAndAudioFeedback(primaryCode);
             return true;
@@ -776,8 +775,6 @@
 
     @Override
     protected void onDrawKeyTopVisuals(Key key, Canvas canvas, Paint paint, KeyDrawParams params) {
-        super.onDrawKeyTopVisuals(key, canvas, paint, params);
-
         if (key.mCode == Keyboard.CODE_SPACE) {
             drawSpacebar(key, canvas, paint);
 
@@ -786,6 +783,8 @@
                     && Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
                 drawKeyPopupHint(key, canvas, paint, params);
             }
+        } else {
+            super.onDrawKeyTopVisuals(key, canvas, paint, params);
         }
     }
 
@@ -840,7 +839,7 @@
 
     private void drawSpacebar(Key key, Canvas canvas, Paint paint) {
         final int width = key.mWidth;
-        final int height = mSpaceIcon != null ? mSpaceIcon.getIntrinsicHeight() : key.mHeight;
+        final int height = key.mHeight;
 
         // If application locales are explicitly selected.
         if (mNeedsToDisplayLanguage) {
@@ -851,8 +850,7 @@
             // spacebar.
             final float descent = paint.descent();
             final float textHeight = -paint.ascent() + descent;
-            final float baseline = (mSpaceIcon != null) ? height * SPACEBAR_LANGUAGE_BASELINE
-                    : height / 2 + textHeight / 2;
+            final float baseline = height / 2 + textHeight / 2;
             paint.setColor(getSpacebarTextColor(mSpacebarTextShadowColor, mSpacebarTextFadeFactor));
             canvas.drawText(language, width / 2, baseline - descent - 1, paint);
             paint.setColor(getSpacebarTextColor(mSpacebarTextColor, mSpacebarTextFadeFactor));
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index 7d8181d..9f735cf 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -17,9 +17,12 @@
 package com.android.inputmethod.keyboard;
 
 import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
 
 import com.android.inputmethod.keyboard.internal.KeySpecParser;
+import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
 import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.Utils;
 
 public class MoreKeysKeyboard extends Keyboard {
     private final int mDefaultKeyCoordX;
@@ -34,7 +37,11 @@
     }
 
     public static class Builder extends Keyboard.Builder<Builder.MoreKeysKeyboardParams> {
-        private final String[] mMoreKeys;
+        private final Key mParentKey;
+        private final Drawable mDivider;
+
+        private static final float LABEL_PADDING_RATIO = 0.2f;
+        private static final float DIVIDER_RATIO = 0.2f;
 
         public static class MoreKeysKeyboardParams extends Keyboard.Params {
             public boolean mIsFixedOrder;
@@ -44,33 +51,29 @@
             public int mTopKeys;
             public int mLeftKeys;
             public int mRightKeys; // includes default key.
+            public int mDividerWidth;
+            public int mColumnWidth;
 
             public MoreKeysKeyboardParams() {
                 super();
             }
 
-            /* package for test */MoreKeysKeyboardParams(int numKeys, int maxColumns, int keyWidth,
-                    int rowHeight, int coordXInParent, int parentKeyboardWidth) {
-                super();
-                setParameters(numKeys, maxColumns, keyWidth, rowHeight, coordXInParent,
-                        parentKeyboardWidth);
-            }
-
             /**
              * Set keyboard parameters of more keys keyboard.
              *
              * @param numKeys number of keys in this more keys keyboard.
-             * @param maxColumnsAndFlags number of maximum columns of this more keys keyboard.
-             * This might have {@link Key#MORE_KEYS_FIXED_COLUMN_ORDER} flag.
+             * @param maxColumns number of maximum columns of this more keys keyboard.
              * @param keyWidth more keys keyboard key width in pixel, including horizontal gap.
              * @param rowHeight more keys keyboard row height in pixel, including vertical gap.
              * @param coordXInParent coordinate x of the key preview in parent keyboard.
              * @param parentKeyboardWidth parent keyboard width in pixel.
+             * @param isFixedColumnOrder if true, more keys should be laid out in fixed order.
+             * @param dividerWidth width of divider, zero for no dividers.
              */
-            public void setParameters(int numKeys, int maxColumnsAndFlags, int keyWidth,
-                    int rowHeight, int coordXInParent, int parentKeyboardWidth) {
-                mIsFixedOrder = (maxColumnsAndFlags & Key.MORE_KEYS_FIXED_COLUMN_ORDER) != 0;
-                final int maxColumns = maxColumnsAndFlags & ~Key.MORE_KEYS_FIXED_COLUMN_ORDER;
+            public void setParameters(int numKeys, int maxColumns, int keyWidth, int rowHeight,
+                    int coordXInParent, int parentKeyboardWidth, boolean isFixedColumnOrder,
+                    int dividerWidth) {
+                mIsFixedOrder = isFixedColumnOrder;
                 if (parentKeyboardWidth / keyWidth < maxColumns) {
                     throw new IllegalArgumentException(
                             "Keyboard is too small to hold more keys keyboard: "
@@ -121,7 +124,9 @@
                 // Adjustment of the top row.
                 mTopRowAdjustment = mIsFixedOrder ? getFixedOrderTopRowAdjustment()
                         : getAutoOrderTopRowAdjustment();
-                mBaseWidth = mOccupiedWidth = mNumColumns * mDefaultKeyWidth;
+                mDividerWidth = dividerWidth;
+                mColumnWidth = mDefaultKeyWidth + mDividerWidth;
+                mBaseWidth = mOccupiedWidth = mNumColumns * mColumnWidth - mDividerWidth;
                 // Need to subtract the bottom row's gutter only.
                 mBaseHeight = mOccupiedHeight = mNumRows * mDefaultRowHeight - mVerticalGap
                         + mTopPadding + mBottomPadding;
@@ -219,13 +224,13 @@
             }
 
             public int getDefaultKeyCoordX() {
-                return mLeftKeys * mDefaultKeyWidth;
+                return mLeftKeys * mColumnWidth;
             }
 
             public int getX(int n, int row) {
-                final int x = getColumnPos(n) * mDefaultKeyWidth + getDefaultKeyCoordX();
+                final int x = getColumnPos(n) * mColumnWidth + getDefaultKeyCoordX();
                 if (isTopRow(row)) {
-                    return x + mTopRowAdjustment * (mDefaultKeyWidth / 2);
+                    return x + mTopRowAdjustment * (mColumnWidth / 2);
                 }
                 return x;
             }
@@ -253,7 +258,7 @@
             // TODO: More keys keyboard's vertical gap is currently calculated heuristically.
             // Should revise the algorithm.
             mParams.mVerticalGap = parentKeyboard.mVerticalGap / 2;
-            mMoreKeys = parentKey.mMoreKeys;
+            mParentKey = parentKey;
 
             final int previewWidth = view.mKeyPreviewDrawParams.mPreviewBackgroundWidth;
             final int previewHeight = view.mKeyPreviewDrawParams.mPreviewBackgroundHeight;
@@ -261,27 +266,42 @@
             // Use pre-computed width and height if these values are available and more keys
             // keyboard has only one key to mitigate visual flicker between key preview and more
             // keys keyboard.
-            if (view.isKeyPreviewPopupEnabled() && mMoreKeys.length == 1 && previewWidth > 0
-                    && previewHeight > 0) {
+            final boolean validKeyPreview = view.isKeyPreviewPopupEnabled()
+                    && !parentKey.noKeyPreview() && (previewWidth > 0) && (previewHeight > 0);
+            final boolean singleMoreKeyWithPreview = validKeyPreview
+                    && parentKey.mMoreKeys.length == 1;
+            if (singleMoreKeyWithPreview) {
                 width = previewWidth;
                 height = previewHeight + mParams.mVerticalGap;
             } else {
-                width = getMaxKeyWidth(view, parentKey.mMoreKeys, mParams.mDefaultKeyWidth);
+                width = getMaxKeyWidth(view, parentKey, mParams.mDefaultKeyWidth);
                 height = parentKeyboard.mMostCommonKeyHeight;
             }
-            mParams.setParameters(mMoreKeys.length, parentKey.mMaxMoreKeysColumn, width, height,
-                    parentKey.mX + parentKey.mWidth / 2, view.getMeasuredWidth());
+            final int dividerWidth;
+            if (parentKey.needsDividersInMoreKeys()) {
+                mDivider = mResources.getDrawable(R.drawable.more_keys_divider);
+                // TODO: Drawable itself should have an alpha value.
+                mDivider.setAlpha(128);
+                dividerWidth = (int)(width * DIVIDER_RATIO);
+            } else {
+                mDivider = null;
+                dividerWidth = 0;
+            }
+            mParams.setParameters(parentKey.mMoreKeys.length, parentKey.getMoreKeysColumn(),
+                    width, height, parentKey.mX + parentKey.mWidth / 2, view.getMeasuredWidth(),
+                    parentKey.isFixedColumnOrderMoreKeys(), dividerWidth);
         }
 
-        private static int getMaxKeyWidth(KeyboardView view, String[] moreKeys, int minKeyWidth) {
-            final int padding = (int) view.getContext().getResources()
-                    .getDimension(R.dimen.more_keys_keyboard_key_horizontal_padding);
+        private static int getMaxKeyWidth(KeyboardView view, Key parentKey, int minKeyWidth) {
+            final int padding = (int)(view.getResources()
+                    .getDimension(R.dimen.more_keys_keyboard_key_horizontal_padding)
+                    + (parentKey.hasLabelsInMoreKeys() ? minKeyWidth * LABEL_PADDING_RATIO : 0));
             Paint paint = null;
             int maxWidth = minKeyWidth;
-            for (String moreKeySpec : moreKeys) {
+            for (String moreKeySpec : parentKey.mMoreKeys) {
                 final String label = KeySpecParser.getLabel(moreKeySpec);
                 // If the label is single letter, minKeyWidth is enough to hold the label.
-                if (label != null && label.length() > 1) {
+                if (label != null && Utils.codePointCount(label) > 1) {
                     if (paint == null) {
                         paint = new Paint();
                         paint.setAntiAlias(true);
@@ -295,16 +315,48 @@
             return maxWidth;
         }
 
+        private static class MoreKeyDivider extends Key.Spacer {
+            private final Drawable mIcon;
+
+            public MoreKeyDivider(MoreKeysKeyboardParams params, Drawable icon, int x, int y) {
+                super(params, x, y, params.mDividerWidth, params.mDefaultRowHeight);
+                mIcon = icon;
+            }
+
+            @Override
+            public Drawable getIcon(KeyboardIconsSet iconSet) {
+                // KeyboardIconsSet is unused. Use the icon that has been passed to the constructor.
+                return mIcon;
+            }
+        }
+
         @Override
         public MoreKeysKeyboard build() {
             final MoreKeysKeyboardParams params = mParams;
-            for (int n = 0; n < mMoreKeys.length; n++) {
-                final String moreKeySpec = mMoreKeys[n];
+            // moreKeyFlags == 0 means that the rendered text size will be determined by its
+            // label's code point count.
+            final int moreKeyFlags = mParentKey.hasLabelsInMoreKeys() ? 0
+                    : Key.LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO;
+            final String[] moreKeys = mParentKey.mMoreKeys;
+            for (int n = 0; n < moreKeys.length; n++) {
+                final String moreKeySpec = moreKeys[n];
                 final int row = n / params.mNumColumns;
-                final Key key = new Key(mResources, params, moreKeySpec, params.getX(n, row),
-                        params.getY(row), params.mDefaultKeyWidth, params.mDefaultRowHeight);
+                final int x = params.getX(n, row);
+                final int y = params.getY(row);
+                final Key key = new Key(mResources, params, moreKeySpec, x, y,
+                        params.mDefaultKeyWidth, params.mDefaultRowHeight, moreKeyFlags);
                 params.markAsEdgeKey(key, row);
                 params.onAddKey(key);
+
+                final int pos = params.getColumnPos(n);
+                // The "pos" value represents the offset from the default position. Negative means
+                // left of the default position.
+                if (params.mDividerWidth > 0 && pos != 0) {
+                    final int dividerX = (pos > 0) ? x - params.mDividerWidth
+                            : x + params.mDefaultKeyWidth;
+                    final Key divider = new MoreKeyDivider(params, mDivider, dividerX, y);
+                    params.onAddKey(divider);
+                }
             }
             return new MoreKeysKeyboard(params);
         }
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
index f61eefd..e3fea3d 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
@@ -426,4 +426,44 @@
             return list.toArray(new String[list.size()]);
         }
     }
+
+    public static int getIntValue(String[] moreKeys, String key, int defaultValue) {
+        if (moreKeys == null) {
+            return defaultValue;
+        }
+        boolean foundValue = false;
+        int value = defaultValue;
+        for (int i = 0; i < moreKeys.length; i++) {
+            final String moreKeySpec = moreKeys[i];
+            if (moreKeySpec == null || !moreKeySpec.startsWith(key)) {
+                continue;
+            }
+            moreKeys[i] = null;
+            try {
+                if (!foundValue) {
+                    value = Integer.parseInt(moreKeySpec.substring(key.length()));
+                }
+            } catch (NumberFormatException e) {
+                throw new RuntimeException(
+                        "integer should follow after " + key + ": " + moreKeySpec);
+            }
+        }
+        return value;
+    }
+
+    public static boolean getBooleanValue(String[] moreKeys, String key) {
+        if (moreKeys == null) {
+            return false;
+        }
+        boolean value = false;
+        for (int i = 0; i < moreKeys.length; i++) {
+            final String moreKeySpec = moreKeys[i];
+            if (moreKeySpec == null || !moreKeySpec.equals(key)) {
+                continue;
+            }
+            moreKeys[i] = null;
+            value = true;
+        }
+        return value;
+    }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
index 162e96d..7c8fd12 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java
@@ -29,9 +29,8 @@
 public class KeyboardIconsSet {
     private static final String TAG = KeyboardIconsSet.class.getSimpleName();
 
-    public static final int ICON_UNDEFINED = 0;
     // The value should be aligned with the enum value of Key.keyIcon.
-    public static final int ICON_SPACE = 4;
+    public static final int ICON_UNDEFINED = 0;
     private static final int NUM_ICONS = 13;
 
     private final Drawable[] mIcons = new Drawable[NUM_ICONS + 1];
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index 6a8a036..18a3f97 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -546,16 +546,19 @@
                     || code == Keyboard.CODE_OUTPUT_TEXT)) {
                 mSwitchState = SWITCH_STATE_SYMBOL;
             }
-            // Switch back to alpha keyboard mode immediately if user types a quote character.
+            // Switch back to alpha keyboard mode immediately if user types one of the switch back
+            // characters.
             if (isLayoutSwitchBackCharacter(code)) {
                 toggleAlphabetAndSymbols();
+                mPrevSymbolsKeyboardWasShifted = false;
             }
             break;
         case SWITCH_STATE_SYMBOL:
             // Switch back to alpha keyboard mode if user types one or more non-space/enter
-            // characters followed by a space/enter or a quote character.
+            // characters followed by a space/enter or one of the switch back characters.
             if (isSpaceCharacter(code) || isLayoutSwitchBackCharacter(code)) {
                 toggleAlphabetAndSymbols();
+                mPrevSymbolsKeyboardWasShifted = false;
             }
             break;
         }
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 47ec40f..98bdef6 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -242,7 +242,6 @@
     public final UIHandler mHandler = new UIHandler(this);
 
     public static class UIHandler extends StaticInnerHandlerWrapper<LatinIME> {
-        private static final int MSG_UPDATE_SUGGESTIONS = 0;
         private static final int MSG_UPDATE_SHIFT_STATE = 1;
         private static final int MSG_VOICE_RESULTS = 2;
         private static final int MSG_FADEOUT_LANGUAGE_ON_SPACEBAR = 3;
@@ -250,6 +249,7 @@
         private static final int MSG_SPACE_TYPED = 5;
         private static final int MSG_SET_BIGRAM_PREDICTIONS = 6;
         private static final int MSG_PENDING_IMS_CALLBACK = 7;
+        private static final int MSG_UPDATE_SUGGESTIONS = 8;
 
         private int mDelayBeforeFadeoutLanguageOnSpacebar;
         private int mDelayUpdateSuggestions;
@@ -979,7 +979,10 @@
                     .setTypedWordValid(false)
                     .setHasMinimalSuggestion(false);
             // When in fullscreen mode, show completions generated by the application
-            setSuggestions(builder.build());
+            final SuggestedWords words = builder.build();
+            final boolean isAutoCorrection = Utils.willAutoCorrect(words);
+            setSuggestions(words, isAutoCorrection);
+            setAutoCorrectionIndicator(isAutoCorrection);
             // TODO: is this the right thing to do? What should we auto-correct to in
             // this case? This says to keep whatever the user typed.
             mWordComposer.setAutoCorrection(mWordComposer.getTypedWord());
@@ -1712,22 +1715,23 @@
     }
 
     public void clearSuggestions() {
-        setSuggestions(SuggestedWords.EMPTY);
+        setSuggestions(SuggestedWords.EMPTY, false);
+        setAutoCorrectionIndicator(false);
     }
 
-    public void setSuggestions(SuggestedWords words) {
+    public void setSuggestions(final SuggestedWords words, final boolean isAutoCorrection) {
         if (mSuggestionsView != null) {
             mSuggestionsView.setSuggestions(words);
-            mKeyboardSwitcher.onAutoCorrectionStateChanged(
-                    words.hasWordAboveAutoCorrectionScoreThreshold());
+            mKeyboardSwitcher.onAutoCorrectionStateChanged(isAutoCorrection);
         }
+    }
 
+    private void setAutoCorrectionIndicator(final boolean newAutoCorrectionIndicator) {
         // Put a blue underline to a word in TextView which will be auto-corrected.
         final InputConnection ic = getCurrentInputConnection();
         if (ic != null) {
             final boolean oldAutoCorrectionIndicator =
                     mComposingStateManager.isAutoCorrectionIndicatorOn();
-            final boolean newAutoCorrectionIndicator = Utils.willAutoCorrect(words);
             if (oldAutoCorrectionIndicator != newAutoCorrectionIndicator) {
                 mComposingStateManager.setAutoCorrectionIndicatorOn(newAutoCorrectionIndicator);
                 if (DEBUG) {
@@ -1738,9 +1742,9 @@
                         throw new RuntimeException("Couldn't flip the indicator!");
                     }
                 }
-                final CharSequence textWithUnderline =
-                        getTextWithUnderline(mWordComposer.getTypedWord());
-                if (!TextUtils.isEmpty(textWithUnderline)) {
+                if (mWordComposer.isComposingWord()) {
+                    final CharSequence textWithUnderline =
+                            getTextWithUnderline(mWordComposer.getTypedWord());
                     ic.setComposingText(textWithUnderline, 1);
                 }
             }
@@ -1830,25 +1834,26 @@
         showSuggestions(builder.build(), typedWord);
     }
 
-    public void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) {
+    public void showSuggestions(final SuggestedWords suggestedWords, final CharSequence typedWord) {
         final boolean shouldBlockAutoCorrectionBySafetyNet =
                 Utils.shouldBlockAutoCorrectionBySafetyNet(suggestedWords, mSuggest);
         if (shouldBlockAutoCorrectionBySafetyNet) {
             suggestedWords.setShouldBlockAutoCorrection();
         }
-        setSuggestions(suggestedWords);
+        final CharSequence autoCorrection;
         if (suggestedWords.size() > 0) {
-            if (shouldBlockAutoCorrectionBySafetyNet) {
-                mWordComposer.setAutoCorrection(typedWord);
-            } else if (suggestedWords.hasAutoCorrectionWord()) {
-                mWordComposer.setAutoCorrection(suggestedWords.getWord(1));
+            if (!shouldBlockAutoCorrectionBySafetyNet && suggestedWords.hasAutoCorrectionWord()) {
+                autoCorrection = suggestedWords.getWord(1);
             } else {
-                mWordComposer.setAutoCorrection(typedWord);
+                autoCorrection = typedWord;
             }
         } else {
-            // TODO: replace with mWordComposer.deleteAutoCorrection()?
-            mWordComposer.setAutoCorrection(null);
+            autoCorrection = null;
         }
+        mWordComposer.setAutoCorrection(autoCorrection);
+        final boolean isAutoCorrection = Utils.willAutoCorrect(suggestedWords);
+        setSuggestions(suggestedWords, isAutoCorrection);
+        setAutoCorrectionIndicator(isAutoCorrection);
         setSuggestionStripShown(isSuggestionsStripVisible());
     }
 
@@ -2021,7 +2026,8 @@
     }
 
     public void setPunctuationSuggestions() {
-        setSuggestions(mSettingsValues.mSuggestPuncList);
+        setSuggestions(mSettingsValues.mSuggestPuncList, false);
+        setAutoCorrectionIndicator(false);
         setSuggestionStripShown(isSuggestionsStripVisible());
     }
 
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index ed6359c..993ae3b 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -65,10 +65,6 @@
         return mHasAutoCorrectionCandidate && size() > 1 && !mTypedWordValid;
     }
 
-    public boolean hasWordAboveAutoCorrectionScoreThreshold() {
-        return mHasAutoCorrectionCandidate && ((size() > 1 && !mTypedWordValid) || mTypedWordValid);
-    }
-
     public boolean isPunctuationSuggestions() {
         return mIsPunctuationSuggestions;
     }
diff --git a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java
index f80534c..e6a59d0 100644
--- a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java
@@ -212,7 +212,8 @@
     @Override
     public void loadDictionaryAsync() {
         // Load the words that correspond to the current input locale
-        Cursor cursor = query(MAIN_COLUMN_LOCALE + "=?", new String[] { mLocale });
+        final Cursor cursor = query(MAIN_COLUMN_LOCALE + "=?", new String[] { mLocale });
+        if (null == cursor) return;
         try {
             if (cursor.moveToFirst()) {
                 int word1Index = cursor.getColumnIndex(MAIN_COLUMN_WORD1);
@@ -249,11 +250,17 @@
         qb.setProjectionMap(sDictProjectionMap);
 
         // Get the database and run the query
-        SQLiteDatabase db = sOpenHelper.getReadableDatabase();
-        Cursor c = qb.query(db,
-                new String[] { MAIN_COLUMN_WORD1, MAIN_COLUMN_WORD2, FREQ_COLUMN_FREQUENCY },
-                selection, selectionArgs, null, null, null);
-        return c;
+        try {
+            SQLiteDatabase db = sOpenHelper.getReadableDatabase();
+            Cursor c = qb.query(db,
+                    new String[] { MAIN_COLUMN_WORD1, MAIN_COLUMN_WORD2, FREQ_COLUMN_FREQUENCY },
+                    selection, selectionArgs, null, null, null);
+            return c;
+        } catch (android.database.sqlite.SQLiteCantOpenDatabaseException e) {
+            // Can't open the database : presumably we can't access storage. That may happen
+            // when the device is wedged; do a best effort to still start the keyboard.
+            return null;
+        }
     }
 
     /**
@@ -344,7 +351,18 @@
 
         @Override
         protected Void doInBackground(Void... v) {
-            SQLiteDatabase db = mDbHelper.getWritableDatabase();
+            SQLiteDatabase db = null;
+            try {
+                db = mDbHelper.getWritableDatabase();
+            } catch (android.database.sqlite.SQLiteCantOpenDatabaseException e) {
+                // If we can't open the db, don't do anything. Exit through the next test
+                // for non-nullity of the db variable.
+            }
+            if (null == db) {
+                // Not much we can do. Just exit.
+                sUpdatingDB = false;
+                return null;
+            }
             db.execSQL("PRAGMA foreign_keys = ON;");
             // Write all the entries to the db
             Iterator<Bigram> iterator = mMap.iterator();
diff --git a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java
index a7f57ae..869865d 100644
--- a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java
@@ -121,7 +121,8 @@
     public void loadDictionaryAsync() {
         if (!ENABLE_USER_UNIGRAM_DICTIONARY) return;
         // Load the words that correspond to the current input locale
-        Cursor cursor = query(COLUMN_LOCALE + "=?", new String[] { mLocale });
+        final Cursor cursor = query(COLUMN_LOCALE + "=?", new String[] { mLocale });
+        if (null == cursor) return;
         try {
             if (cursor.moveToFirst()) {
                 int wordIndex = cursor.getColumnIndex(COLUMN_WORD);
@@ -212,10 +213,16 @@
         qb.setProjectionMap(sDictProjectionMap);
 
         // Get the database and run the query
-        SQLiteDatabase db = sOpenHelper.getReadableDatabase();
-        Cursor c = qb.query(db, null, selection, selectionArgs, null, null,
-                DEFAULT_SORT_ORDER);
-        return c;
+        try {
+            SQLiteDatabase db = sOpenHelper.getReadableDatabase();
+            Cursor c = qb.query(db, null, selection, selectionArgs, null, null,
+                    DEFAULT_SORT_ORDER);
+            return c;
+        } catch (android.database.sqlite.SQLiteCantOpenDatabaseException e) {
+            // Can't open the database : presumably we can't access storage. That may happen
+            // when the device is wedged; do a best effort to still start the keyboard.
+            return null;
+        }
     }
 
     /**
@@ -236,7 +243,14 @@
 
         @Override
         protected Void doInBackground(Void... v) {
-            SQLiteDatabase db = mDbHelper.getWritableDatabase();
+            SQLiteDatabase db = null;
+            try {
+                db = mDbHelper.getWritableDatabase();
+            } catch (android.database.sqlite.SQLiteCantOpenDatabaseException e) {
+                // With no access to the DB, this is moot. Do nothing: we'll exit through the
+                // test for null == db.
+            }
+            if (null == db) return null;
             // Write all the entries to the db
             Set<Entry<String,Integer>> mEntries = mMap.entrySet();
             for (Entry<String,Integer> entry : mEntries) {
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 6d63e95..47ea9ee 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -563,8 +563,16 @@
 
         switch (inputType & InputType.TYPE_MASK_CLASS) {
         case InputType.TYPE_CLASS_NUMBER:
-        case InputType.TYPE_CLASS_DATETIME:
             return KeyboardId.MODE_NUMBER;
+        case InputType.TYPE_CLASS_DATETIME:
+            switch (variation) {
+            case InputType.TYPE_DATETIME_VARIATION_DATE:
+                return KeyboardId.MODE_DATE;
+            case InputType.TYPE_DATETIME_VARIATION_TIME:
+                return KeyboardId.MODE_TIME;
+            default: // InputType.TYPE_DATETIME_VARIATION_NORMAL
+                return KeyboardId.MODE_DATETIME;
+            }
         case InputType.TYPE_CLASS_PHONE:
             return KeyboardId.MODE_PHONE;
         case InputType.TYPE_CLASS_TEXT:
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index 4ef5bd3..cb1b49c 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -34,7 +34,7 @@
 public class MoreSuggestions extends Keyboard {
     public static final int SUGGESTION_CODE_BASE = 1024;
 
-    private MoreSuggestions(Builder.MoreSuggestionsParam params) {
+    MoreSuggestions(Builder.MoreSuggestionsParam params) {
         super(params);
     }
 
@@ -63,7 +63,7 @@
                 paint.setAntiAlias(true);
                 final Resources res = view.getContext().getResources();
                 mDivider = res.getDrawable(R.drawable.more_suggestions_divider);
-                // TODO: Drawable itself should has an alpha value.
+                // TODO: Drawable itself should have an alpha value.
                 mDivider.setAlpha(128);
                 mDividerWidth = mDivider.getIntrinsicWidth();
                 final int padding = (int) res.getDimension(
@@ -227,7 +227,7 @@
                 final int index = pos + SUGGESTION_CODE_BASE;
                 final Key key = new Key(
                         params, word, info, KeyboardIconsSet.ICON_UNDEFINED, index, null, x, y,
-                        width, params.mDefaultRowHeight);
+                        width, params.mDefaultRowHeight, 0);
                 params.markAsEdgeKey(key, pos);
                 params.onAddKey(key);
                 final int columnNumber = params.getColumnNumber(pos);
diff --git a/native/src/correction.h b/native/src/correction.h
index 2114eff..ee55c96 100644
--- a/native/src/correction.h
+++ b/native/src/correction.h
@@ -17,6 +17,7 @@
 #ifndef LATINIME_CORRECTION_H
 #define LATINIME_CORRECTION_H
 
+#include <assert.h>
 #include <stdint.h>
 #include "correction_state.h"
 
@@ -50,7 +51,14 @@
         const int temp = *base;
         if (temp != S_INT_MAX) {
             // Branch if multiplier == 2 for the optimization
-            if (multiplier == 2) {
+            if (multiplier < 0) {
+                if (DEBUG_DICT) {
+                    assert(false);
+                }
+                AKLOGI("--- Invalid multiplier: %d", multiplier);
+            } else if (multiplier == 0) {
+                *base = 0;
+            } else if (multiplier == 2) {
                 *base = TWO_31ST_DIV_2 >= temp ? temp << 1 : S_INT_MAX;
             } else {
                 // TODO: This overflow check gives a wrong answer when, for example,
diff --git a/tests/res/raw/test.dict b/tests/res/raw/test.dict
deleted file mode 100644
index 453fc9f..0000000
--- a/tests/res/raw/test.dict
+++ /dev/null
Binary files differ
diff --git a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java
index c0b3445..5c6c834 100644
--- a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderFixedOrderTests.java
@@ -41,10 +41,12 @@
         super.setUp();
     }
 
-    private static MoreKeysKeyboardParams createParams(int numKeys, int fixColumns,
+    private static MoreKeysKeyboardParams createParams(int numKeys, int columnNum,
             int coordXInParnet) {
-        return new MoreKeysKeyboardParams(numKeys, fixColumns | Key.MORE_KEYS_FIXED_COLUMN_ORDER,
-                WIDTH, HEIGHT, coordXInParnet, KEYBOARD_WIDTH);
+        final MoreKeysKeyboardParams params = new MoreKeysKeyboardParams();
+        params.setParameters(numKeys, columnNum, WIDTH, HEIGHT, coordXInParnet, KEYBOARD_WIDTH,
+                /* isFixedOrderColumn */true, /* dividerWidth */0);
+        return params;
     }
 
     public void testLayoutError() {
diff --git a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java
index 90bbf7e..31f0e0f 100644
--- a/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/MoreKeysKeyboardBuilderTests.java
@@ -43,8 +43,10 @@
 
     private static MoreKeysKeyboardParams createParams(int numKeys, int maxColumns,
             int coordXInParnet) {
-        return new MoreKeysKeyboardParams(numKeys, maxColumns, WIDTH, HEIGHT, coordXInParnet,
-                KEYBOARD_WIDTH);
+        final MoreKeysKeyboardParams params = new MoreKeysKeyboardParams();
+        params.setParameters(numKeys, maxColumns, WIDTH, HEIGHT, coordXInParnet, KEYBOARD_WIDTH,
+                /* isFixedOrderColumn */false, /* dividerWidth */0);
+        return params;
     }
 
     public void testLayoutError() {
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
index ef0facf..de2a50f 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
@@ -122,6 +122,8 @@
         pressAndReleaseKey('~', SYMBOLS_SHIFTED, SYMBOLS_SHIFTED);
         // Enter space, switch back to alphabet.
         pressAndReleaseKey(CODE_SPACE, SYMBOLS_SHIFTED, ALPHABET_UNSHIFTED);
+        // Press/release "?123" key, enter into symbols (not symbols shifted).
+        pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
     }
 
     // Automatic switch back to alphabet shift locked test by space key.
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
index 78bd4d7..9d53b63 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
@@ -19,9 +19,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.os.Looper;
+import android.os.MessageQueue;
 import android.preference.PreferenceManager;
 import android.test.ServiceTestCase;
 import android.text.InputType;
+import android.text.SpannableStringBuilder;
+import android.text.style.SuggestionSpan;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
@@ -127,6 +131,51 @@
         }
     }
 
+    // We need to run the messages added to the handler from LatinIME. The only way to do
+    // that is to call Looper#loop() on the right looper, so we're going to get the looper
+    // object and call #loop() here. The messages in the handler actually run on the UI
+    // thread of the keyboard by design of the handler, so we want to call it synchronously
+    // on the same thread that the tests are running on to mimic the actual environment as
+    // closely as possible.
+    // Now, Looper#loop() never exits in normal operation unless the Looper#quit() method
+    // is called, so we need to do that at the right time so that #loop() returns at some
+    // point and we don't end up in an infinite loop.
+    // After we quit, the looper is still technically ready to process more messages but
+    // the handler will refuse to enqueue any because #quit() has been called and it
+    // explicitly tests for it on message enqueuing, so we'll have to reset it so that
+    // it lets us continue normal operation.
+    private void runMessages() {
+        // Here begins deep magic.
+        final Looper looper = mLatinIME.mHandler.getLooper();
+        mLatinIME.mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    looper.quit();
+                }
+            });
+        // The only way to get out of Looper#loop() is to call #quit() on it (or on its queue).
+        // Once #quit() is called remaining messages are not processed, which is why we post
+        // a message that calls it instead of calling it directly.
+        looper.loop();
+
+        // Once #quit() has been called, the message queue has an "mQuiting" field that prevents
+        // any subsequent post in this queue. However the queue itself is still fully functional!
+        // If we have a way of resetting "queue.mQuiting" then we can continue using it as normal,
+        // coming back to this method to run the messages.
+        MessageQueue queue = looper.getQueue();
+        try {
+            // However there is no way of doing it externally, and mQuiting is private.
+            // So... get out the big guns.
+            java.lang.reflect.Field f = MessageQueue.class.getDeclaredField("mQuiting");
+            f.setAccessible(true); // What do you mean "private"?
+            f.setBoolean(queue, false);
+        } catch (NoSuchFieldException e) {
+            throw new RuntimeException(e);
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     // type(int) and type(String): helper methods to send a code point resp. a string to LatinIME.
     private void type(final int codePoint) {
         // onPressKey and onReleaseKey are explicitly deactivated here, but they do happen in the
@@ -152,6 +201,13 @@
         }
     }
 
+    // Helper to avoid writing the try{}catch block each time
+    private static void sleep(final int milliseconds) {
+        try {
+            Thread.sleep(milliseconds);
+        } catch (InterruptedException e) {}
+    }
+
     public void testTypeWord() {
         final String WORD_TO_TYPE = "abcd";
         type(WORD_TO_TYPE);
@@ -446,5 +502,115 @@
                 EXPECTED_RESULT, mTextView.getText().toString());
     }
 
+    // A helper class to ease span tests
+    private static class Span {
+        final SpannableStringBuilder mInputText;
+        final SuggestionSpan mSpan;
+        final int mStart;
+        final int mEnd;
+        // The supplied CharSequence should be an instance of SpannableStringBuilder,
+        // and it should contain exactly zero or one SuggestionSpan. Otherwise, an exception
+        // is thrown.
+        public Span(final CharSequence inputText) {
+            mInputText = (SpannableStringBuilder)inputText;
+            final SuggestionSpan[] spans =
+                    mInputText.getSpans(0, mInputText.length(), SuggestionSpan.class);
+            if (0 == spans.length) {
+                mSpan = null;
+                mStart = -1;
+                mEnd = -1;
+            } else if (1 == spans.length) {
+                mSpan = spans[0];
+                mStart = mInputText.getSpanStart(mSpan);
+                mEnd = mInputText.getSpanEnd(mSpan);
+            } else {
+                throw new RuntimeException("Expected one SuggestionSpan, found " + spans.length);
+            }
+        }
+        public boolean isAutoCorrectionIndicator() {
+            return 0 != (SuggestionSpan.FLAG_AUTO_CORRECTION & mSpan.getFlags());
+        }
+    }
+
+    static final int DELAY_TO_WAIT_FOR_UNDERLINE = 200; // The message is posted with a 100 ms delay
+    public void testBlueUnderline() {
+        final String STRING_TO_TYPE = "tgis";
+        final int EXPECTED_SPAN_START = 0;
+        final int EXPECTED_SPAN_END = 4;
+        type(STRING_TO_TYPE);
+        sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+        runMessages();
+        final Span span = new Span(mTextView.getText());
+        assertEquals("show blue underline, span start", EXPECTED_SPAN_START, span.mStart);
+        assertEquals("show blue underline, span end", EXPECTED_SPAN_END, span.mEnd);
+        assertEquals("show blue underline, span color", true, span.isAutoCorrectionIndicator());
+    }
+
+    public void testBlueUnderlineDisappears() {
+        final String STRING_1_TO_TYPE = "tgis";
+        final String STRING_2_TO_TYPE = "q";
+        final int EXPECTED_SPAN_START = 0;
+        final int EXPECTED_SPAN_END = 5;
+        type(STRING_1_TO_TYPE);
+        sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+        runMessages();
+        type(STRING_2_TO_TYPE);
+        // We haven't have time to look into the dictionary yet, so the line should still be
+        // blue to avoid any flicker.
+        final Span spanBefore = new Span(mTextView.getText());
+        assertEquals("extend blue underline, span start", EXPECTED_SPAN_START, spanBefore.mStart);
+        assertEquals("extend blue underline, span end", EXPECTED_SPAN_END, spanBefore.mEnd);
+        assertEquals("extend blue underline, span color", true,
+                spanBefore.isAutoCorrectionIndicator());
+        sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+        runMessages();
+        // Now we have been able to re-evaluate the word, there shouldn't be an auto-correction span
+        final Span spanAfter = new Span(mTextView.getText());
+        assertNull("hide blue underline", spanAfter.mSpan);
+    }
+
+    public void testBlueUnderlineOnBackspace() {
+        final String STRING_TO_TYPE = "tgis";
+        final int EXPECTED_SPAN_START = 0;
+        final int EXPECTED_SPAN_END = 4;
+        type(STRING_TO_TYPE);
+        sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+        runMessages();
+        type(Keyboard.CODE_SPACE);
+        sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+        runMessages();
+        type(Keyboard.CODE_DELETE);
+        sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+        runMessages();
+        type(Keyboard.CODE_DELETE);
+        sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+        runMessages();
+        final Span span = new Span(mTextView.getText());
+        assertEquals("show blue underline after backspace, span start",
+                EXPECTED_SPAN_START, span.mStart);
+        assertEquals("show blue underline after backspace, span end",
+                EXPECTED_SPAN_END, span.mEnd);
+        assertEquals("show blue underline after backspace, span color", true,
+                span.isAutoCorrectionIndicator());
+    }
+
+    public void testBlueUnderlineDisappearsWhenCursorMoved() {
+        final String STRING_TO_TYPE = "tgis";
+        final int NEW_CURSOR_POSITION = 0;
+        type(STRING_TO_TYPE);
+        sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+        // Simulate the onUpdateSelection() event
+        mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1);
+        runMessages();
+        // Here the blue underline has been set. testBlueUnderline() is testing for this already,
+        // so let's not test it here again.
+        // Now simulate the user moving the cursor.
+        mInputConnection.setSelection(NEW_CURSOR_POSITION, NEW_CURSOR_POSITION);
+        mLatinIME.onUpdateSelection(0, 0, NEW_CURSOR_POSITION, NEW_CURSOR_POSITION, -1, -1);
+        sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+        runMessages();
+        final Span span = new Span(mTextView.getText());
+        assertNull("blue underline removed when cursor is moved", span.mSpan);
+    }
     // TODO: Add some tests for non-BMP characters
 }
diff --git a/tests/src/com/android/inputmethod/latin/SuggestHelper.java b/tests/src/com/android/inputmethod/latin/SuggestHelper.java
deleted file mode 100644
index 0c023bd..0000000
--- a/tests/src/com/android/inputmethod/latin/SuggestHelper.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * 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.content.Context;
-import android.text.TextUtils;
-
-import com.android.inputmethod.keyboard.KeyDetector;
-import com.android.inputmethod.keyboard.Keyboard;
-import com.android.inputmethod.keyboard.KeyboardId;
-import com.android.inputmethod.keyboard.KeyboardSet;
-
-import java.io.File;
-import java.util.Locale;
-
-public class SuggestHelper {
-    protected final Suggest mSuggest;
-    protected int mCorrectionMode;
-    protected final Keyboard mKeyboard;
-    private final KeyDetector mKeyDetector;
-
-    public SuggestHelper(Context context, int dictionaryId, KeyboardSet keyboardSet) {
-        // Use null as the locale for Suggest so as to force it to use the internal dictionary
-        // (and not try to find a dictionary provider for a specified locale)
-        this(new Suggest(context, dictionaryId, null), keyboardSet);
-    }
-
-    protected SuggestHelper(final Context context, final File dictionaryPath,
-            final long startOffset, final long length, final KeyboardSet keyboardSet,
-            final Locale locale) {
-        this(new Suggest(context, dictionaryPath, startOffset, length, null, locale), keyboardSet);
-    }
-
-    private SuggestHelper(final Suggest suggest, final KeyboardSet keyboardSet) {
-        mSuggest = suggest;
-        mKeyboard = keyboardSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
-        mKeyDetector = new KeyDetector(0);
-
-        setCorrectionMode(Suggest.CORRECTION_FULL);
-        mKeyDetector.setKeyboard(mKeyboard, 0, 0);
-        mKeyDetector.setProximityCorrectionEnabled(true);
-        mKeyDetector.setProximityThreshold(mKeyboard.mMostCommonKeyWidth);
-    }
-
-    public void setCorrectionMode(int correctionMode) {
-        mCorrectionMode = correctionMode;
-    }
-
-    public boolean hasMainDictionary() {
-        return mSuggest.hasMainDictionary();
-    }
-
-    protected WordComposer createWordComposer(CharSequence s) {
-        WordComposer word = new WordComposer();
-        word.setComposingWord(s, mKeyboard, mKeyDetector);
-        return word;
-    }
-
-    public boolean isValidWord(CharSequence typed) {
-        return AutoCorrection.isValidWord(mSuggest.getUnigramDictionaries(),
-                typed, false);
-    }
-
-    // TODO: This may be slow, but is OK for test so far.
-    public SuggestedWords getSuggestions(CharSequence typed) {
-        return mSuggest.getSuggestions(createWordComposer(typed), null,
-                mKeyboard.getProximityInfo(), mCorrectionMode);
-    }
-
-    public CharSequence getFirstSuggestion(CharSequence typed) {
-        WordComposer word = createWordComposer(typed);
-        SuggestedWords suggestions = mSuggest.getSuggestions(word, null,
-                mKeyboard.getProximityInfo(), mCorrectionMode);
-        // Note that suggestions.getWord(0) is the word user typed.
-        return suggestions.size() > 1 ? suggestions.getWord(1) : null;
-    }
-
-    public CharSequence getAutoCorrection(CharSequence typed) {
-        WordComposer word = createWordComposer(typed);
-        SuggestedWords suggestions = mSuggest.getSuggestions(word, null,
-                mKeyboard.getProximityInfo(), mCorrectionMode);
-        // Note that suggestions.getWord(0) is the word user typed.
-        return (suggestions.size() > 1 && mSuggest.hasAutoCorrection())
-                ? suggestions.getWord(1) : null;
-    }
-
-    public int getSuggestIndex(CharSequence typed, CharSequence expected) {
-        WordComposer word = createWordComposer(typed);
-        SuggestedWords suggestions = mSuggest.getSuggestions(word, null,
-                mKeyboard.getProximityInfo(), mCorrectionMode);
-        // Note that suggestions.getWord(0) is the word user typed.
-        for (int i = 1; i < suggestions.size(); i++) {
-            if (TextUtils.equals(suggestions.getWord(i), expected))
-                return i;
-        }
-        return -1;
-    }
-
-    private void getBigramSuggestions(CharSequence previous, CharSequence typed) {
-        if (!TextUtils.isEmpty(previous) && (typed.length() > 1)) {
-            WordComposer firstChar = createWordComposer(Character.toString(typed.charAt(0)));
-            mSuggest.getSuggestions(firstChar, previous, mKeyboard.getProximityInfo(),
-                    mCorrectionMode);
-        }
-    }
-
-    public CharSequence getBigramFirstSuggestion(CharSequence previous, CharSequence typed) {
-        WordComposer word = createWordComposer(typed);
-        getBigramSuggestions(previous, typed);
-        SuggestedWords suggestions = mSuggest.getSuggestions(word, previous,
-                mKeyboard.getProximityInfo(), mCorrectionMode);
-        return suggestions.size() > 1 ? suggestions.getWord(1) : null;
-    }
-
-    public CharSequence getBigramAutoCorrection(CharSequence previous, CharSequence typed) {
-        WordComposer word = createWordComposer(typed);
-        getBigramSuggestions(previous, typed);
-        SuggestedWords suggestions = mSuggest.getSuggestions(word, previous,
-                mKeyboard.getProximityInfo(), mCorrectionMode);
-        return (suggestions.size() > 1 && mSuggest.hasAutoCorrection())
-                ? suggestions.getWord(1) : null;
-    }
-
-    public int searchBigramSuggestion(CharSequence previous, CharSequence typed,
-            CharSequence expected) {
-        WordComposer word = createWordComposer(typed);
-        getBigramSuggestions(previous, typed);
-        SuggestedWords suggestions = mSuggest.getSuggestions(word, previous,
-                mKeyboard.getProximityInfo(), mCorrectionMode);
-        for (int i = 1; i < suggestions.size(); i++) {
-            if (TextUtils.equals(suggestions.getWord(i), expected))
-                return i;
-        }
-        return -1;
-    }
-}
diff --git a/tests/src/com/android/inputmethod/latin/SuggestTests.java b/tests/src/com/android/inputmethod/latin/SuggestTests.java
deleted file mode 100644
index e12ae58..0000000
--- a/tests/src/com/android/inputmethod/latin/SuggestTests.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2010,2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.inputmethod.latin;
-
-import com.android.inputmethod.latin.tests.R;
-
-import android.content.res.AssetFileDescriptor;
-import android.content.res.Configuration;
-
-import java.util.Locale;
-
-public class SuggestTests extends SuggestTestsBase {
-    private SuggestHelper mHelper;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        final AssetFileDescriptor dict = openTestRawResourceFd(R.raw.test);
-        final Locale locale = Locale.US;
-        mHelper = new SuggestHelper(
-                getContext(), mTestPackageFile, dict.getStartOffset(), dict.getLength(),
-                createKeyboardSet(locale, Configuration.ORIENTATION_PORTRAIT), locale);
-        mHelper.setCorrectionMode(Suggest.CORRECTION_FULL_BIGRAM);
-    }
-
-    /************************** Tests ************************/
-
-    /**
-     * Tests for simple completions of one character.
-     */
-    public void testCompletion1char() {
-        suggested("people", mHelper.getFirstSuggestion("peopl"));
-        suggested("about", mHelper.getFirstSuggestion("abou"));
-        suggested("their", mHelper.getFirstSuggestion("thei"));
-    }
-
-    /**
-     * Tests for simple completions of two characters.
-     */
-    public void testCompletion2char() {
-        suggested("people", mHelper.getFirstSuggestion("peop"));
-        suggested("calling", mHelper.getFirstSuggestion("calli"));
-        suggested("business", mHelper.getFirstSuggestion("busine"));
-    }
-
-    /**
-     * Tests for proximity errors.
-     */
-    public void testProximityPositive() {
-        suggested("typed peiple", "people", mHelper.getFirstSuggestion("peiple"));
-        suggested("typed peoole", "people", mHelper.getFirstSuggestion("peoole"));
-        suggested("typed pwpple", "people", mHelper.getFirstSuggestion("pwpple"));
-    }
-
-    /**
-     * Tests for proximity errors - negative, when the error key is not close.
-     */
-    public void testProximityNegative() {
-        notSuggested("about", mHelper.getFirstSuggestion("arout"));
-        notSuggested("are", mHelper.getFirstSuggestion("ire"));
-    }
-
-    /**
-     * Tests for checking if apostrophes are added automatically.
-     */
-    public void testApostropheInsertion() {
-        suggested("I'm", mHelper.getFirstSuggestion("im"));
-        suggested("don't", mHelper.getFirstSuggestion("dont"));
-    }
-
-    /**
-     * Test to make sure apostrophed word is not suggested for an apostrophed word.
-     */
-    public void testApostrophe() {
-        notSuggested("don't", mHelper.getFirstSuggestion("don't"));
-    }
-
-    /**
-     * Tests for suggestion of capitalized version of a word.
-     */
-    public void testCapitalization() {
-        suggested("I'm", mHelper.getFirstSuggestion("i'm"));
-        suggested("Sunday", mHelper.getFirstSuggestion("sunday"));
-        suggested("Sunday", mHelper.getFirstSuggestion("sundat"));
-    }
-
-    /**
-     * Tests to see if more than one completion is provided for certain prefixes.
-     */
-    public void testMultipleCompletions() {
-        isInSuggestions("com: come", mHelper.getSuggestIndex("com", "come"));
-        isInSuggestions("com: company", mHelper.getSuggestIndex("com", "company"));
-        isInSuggestions("th: the", mHelper.getSuggestIndex("th", "the"));
-        isInSuggestions("th: that", mHelper.getSuggestIndex("th", "that"));
-        isInSuggestions("th: this", mHelper.getSuggestIndex("th", "this"));
-        isInSuggestions("th: they", mHelper.getSuggestIndex("th", "they"));
-    }
-
-    /**
-     * Does the suggestion engine recognize zero frequency words as valid words.
-     */
-    public void testZeroFrequencyAccepted() {
-        assertTrue("valid word yikes", mHelper.isValidWord("yikes"));
-        assertFalse("non valid word yike", mHelper.isValidWord("yike"));
-    }
-
-    /**
-     * Tests to make sure that zero frequency words are not suggested as completions.
-     */
-    public void testZeroFrequencySuggestionsNegative() {
-        assertTrue(mHelper.getSuggestIndex("yike", "yikes") < 0);
-        assertTrue(mHelper.getSuggestIndex("what", "whatcha") < 0);
-    }
-
-    /**
-     * Tests to ensure that words with large edit distances are not suggested, in some cases.
-     * Also such word is not considered auto correction, in some cases.
-     */
-    public void testTooLargeEditDistance() {
-        assertTrue(mHelper.getSuggestIndex("sniyr", "about") < 0);
-        // TODO: The following test fails.
-        // notSuggested("the", mHelper.getAutoCorrection("rjw"));
-    }
-
-    /**
-     * Make sure mHelper.isValidWord is case-sensitive.
-     */
-    public void testValidityCaseSensitivity() {
-        assertTrue("valid word Sunday", mHelper.isValidWord("Sunday"));
-        assertFalse("non valid word sunday", mHelper.isValidWord("sunday"));
-    }
-
-    /**
-     * Are accented forms of words suggested as corrections?
-     */
-    public void testAccents() {
-        // ni<LATIN SMALL LETTER N WITH TILDE>o
-        suggested("ni\u00F1o", mHelper.getAutoCorrection("nino"));
-        // ni<LATIN SMALL LETTER N WITH TILDE>o
-        suggested("ni\u00F1o", mHelper.getAutoCorrection("nimo"));
-        // Mar<LATIN SMALL LETTER I WITH ACUTE>a
-        suggested("Mar\u00EDa", mHelper.getAutoCorrection("maria"));
-    }
-
-    /**
-     * Make sure bigrams are showing when first character is typed
-     *  and don't show any when there aren't any
-     */
-    public void testBigramsAtFirstChar() {
-        suggested("bigram: about p[art]",
-                "part", mHelper.getBigramFirstSuggestion("about", "p"));
-        suggested("bigram: I'm a[bout]",
-                "about", mHelper.getBigramFirstSuggestion("I'm", "a"));
-        suggested("bigram: about b[usiness]",
-                "business", mHelper.getBigramFirstSuggestion("about", "b"));
-        isInSuggestions("bigram: about b[eing]",
-                mHelper.searchBigramSuggestion("about", "b", "being"));
-        notSuggested("bigram: about p",
-                "business", mHelper.getBigramFirstSuggestion("about", "p"));
-    }
-
-    /**
-     * Make sure bigrams score affects the original score
-     */
-    public void testBigramsScoreEffect() {
-        suggested("single: page",
-                "page", mHelper.getAutoCorrection("pa"));
-        suggested("bigram: about pa[rt]",
-                "part", mHelper.getBigramAutoCorrection("about", "pa"));
-        // TODO: The following test fails.
-        // suggested("single: said", "said", mHelper.getAutoCorrection("sa"));
-        // TODO: The following test fails due to "transpose correction".
-        // suggested("bigram: from sa[me]",
-        //        "same", mHelper.getBigramAutoCorrection("from", "sa"));
-    }
-}
diff --git a/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java b/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
deleted file mode 100644
index 73e34ba..0000000
--- a/tests/src/com/android/inputmethod/latin/SuggestTestsBase.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.inputmethod.latin;
-
-import android.content.res.AssetFileDescriptor;
-import android.content.res.Configuration;
-import android.test.AndroidTestCase;
-import android.text.InputType;
-import android.text.TextUtils;
-import android.util.DisplayMetrics;
-import android.view.inputmethod.EditorInfo;
-
-import com.android.inputmethod.keyboard.KeyboardSet;
-
-import java.io.File;
-import java.io.InputStream;
-import java.util.Locale;
-
-public class SuggestTestsBase extends AndroidTestCase {
-    protected File mTestPackageFile;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        mTestPackageFile = new File(getTestContext().getApplicationInfo().sourceDir);
-    }
-
-    protected KeyboardSet createKeyboardSet(Locale locale, int orientation) {
-        return createKeyboardSet(locale, orientation, false);
-    }
-
-    protected KeyboardSet createKeyboardSet(Locale locale, int orientation,
-            boolean touchPositionCorrectionEnabled) {
-        final DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
-        final int width;
-        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
-            width = Math.max(dm.widthPixels, dm.heightPixels);
-        } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
-            width = Math.min(dm.widthPixels, dm.heightPixels);
-        } else {
-            fail("Orientation should be ORIENTATION_LANDSCAPE or ORIENTATION_PORTRAIT: "
-                    + "orientation=" + orientation);
-            return null;
-        }
-        final EditorInfo editorInfo = new EditorInfo();
-        editorInfo.inputType = InputType.TYPE_CLASS_TEXT;
-        final KeyboardSet.Builder builder = new KeyboardSet.Builder(getContext(), editorInfo);
-        builder.setScreenGeometry(orientation, width);
-        builder.setSubtype(locale, true, touchPositionCorrectionEnabled);
-        return builder.build();
-    }
-
-    protected InputStream openTestRawResource(int resIdInTest) {
-        return getTestContext().getResources().openRawResource(resIdInTest);
-    }
-
-    protected AssetFileDescriptor openTestRawResourceFd(int resIdInTest) {
-        return getTestContext().getResources().openRawResourceFd(resIdInTest);
-    }
-
-    private static String format(String message, Object expected, Object actual) {
-        return message + " expected:<" + expected + "> but was:<" + actual + ">";
-    }
-
-    protected static void suggested(CharSequence expected, CharSequence actual) {
-        if (!TextUtils.equals(expected, actual))
-            fail(format("assertEquals", expected, actual));
-    }
-
-    protected static void suggested(String message, CharSequence expected, CharSequence actual) {
-        if (!TextUtils.equals(expected, actual))
-            fail(format(message, expected, actual));
-    }
-
-    protected static void notSuggested(CharSequence expected, CharSequence actual) {
-        if (TextUtils.equals(expected, actual))
-            fail(format("assertNotEquals", expected, actual));
-    }
-
-    protected static void notSuggested(String message, CharSequence expected, CharSequence actual) {
-        if (TextUtils.equals(expected, actual))
-            fail(format(message, expected, actual));
-    }
-
-    protected static void isInSuggestions(String message, int position) {
-        assertTrue(message, position >= 0);
-    }
-
-    protected static void isNotInSuggestions(String message, int position) {
-        assertTrue(message, position < 0);
-    }
-}
diff --git a/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java b/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java
deleted file mode 100644
index 74fadf7..0000000
--- a/tests/src/com/android/inputmethod/latin/UserBigramSuggestHelper.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.inputmethod.latin;
-
-import android.content.Context;
-import android.text.TextUtils;
-
-import com.android.inputmethod.keyboard.KeyboardSet;
-
-import java.io.File;
-import java.util.Locale;
-import java.util.StringTokenizer;
-
-public class UserBigramSuggestHelper extends SuggestHelper {
-    private final Context mContext;
-    private UserBigramDictionary mUserBigram;
-
-    public UserBigramSuggestHelper(final Context context, final File dictionaryPath,
-            final long startOffset, final long length, final int userBigramMax,
-            final int userBigramDelete, final KeyboardSet keyboardSet, final Locale locale) {
-        super(context, dictionaryPath, startOffset, length, keyboardSet, locale);
-        mContext = context;
-        mUserBigram = new UserBigramDictionary(context, null, locale.toString(),
-                Suggest.DIC_USER);
-        mUserBigram.setDatabaseMax(userBigramMax);
-        mUserBigram.setDatabaseDelete(userBigramDelete);
-        setCorrectionMode(Suggest.CORRECTION_FULL_BIGRAM);
-        mSuggest.setUserBigramDictionary(mUserBigram);
-    }
-
-    public void changeUserBigramLocale(Locale locale) {
-        if (mUserBigram != null) {
-            flushUserBigrams();
-            mUserBigram.close();
-            mUserBigram = new UserBigramDictionary(mContext, null, locale.toString(),
-                    Suggest.DIC_USER);
-            mSuggest.setUserBigramDictionary(mUserBigram);
-        }
-    }
-
-    public int searchUserBigramSuggestion(CharSequence previous, char typed,
-            CharSequence expected) {
-        if (mUserBigram == null) return -1;
-
-        flushUserBigrams();
-        if (!TextUtils.isEmpty(previous) && !TextUtils.isEmpty(Character.toString(typed))) {
-            WordComposer firstChar = createWordComposer(Character.toString(typed));
-            mSuggest.getSuggestions(firstChar, previous, mKeyboard.getProximityInfo(),
-                    mCorrectionMode);
-            boolean reloading = mUserBigram.reloadDictionaryIfRequired();
-            if (reloading) mUserBigram.waitForDictionaryLoading();
-            mUserBigram.getBigrams(firstChar, previous, mSuggest);
-        }
-
-        for (int i = 0; i < mSuggest.mBigramSuggestions.size(); i++) {
-            final CharSequence word = mSuggest.mBigramSuggestions.get(i);
-            if (TextUtils.equals(word, expected))
-                return i;
-        }
-
-        return -1;
-    }
-
-    public void addToUserBigram(String sentence) {
-        StringTokenizer st = new StringTokenizer(sentence);
-        String previous = null;
-        while (st.hasMoreTokens()) {
-            String current = st.nextToken();
-            if (previous != null) {
-                addToUserBigram(new String[] {previous, current});
-            }
-            previous = current;
-        }
-    }
-
-    public void addToUserBigram(String[] pair) {
-        if (mUserBigram != null && pair.length == 2) {
-            mUserBigram.addBigrams(pair[0], pair[1]);
-        }
-    }
-
-    public void flushUserBigrams() {
-        if (mUserBigram != null) {
-            mUserBigram.flushPendingWrites();
-            mUserBigram.waitUntilUpdateDBDone();
-        }
-    }
-}
diff --git a/tests/src/com/android/inputmethod/latin/UserBigramSuggestTests.java b/tests/src/com/android/inputmethod/latin/UserBigramSuggestTests.java
deleted file mode 100644
index 2b88a7c..0000000
--- a/tests/src/com/android/inputmethod/latin/UserBigramSuggestTests.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2010,2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package com.android.inputmethod.latin;
-import android.content.res.AssetFileDescriptor;
-import android.content.res.Configuration;
-
-import com.android.inputmethod.latin.tests.R;
-
-import java.util.Locale;
-
-public class UserBigramSuggestTests extends SuggestTestsBase {
-    private static final int SUGGESTION_STARTS = 1;
-    private static final int MAX_DATA = 20;
-    private static final int DELETE_DATA = 10;
-
-    private UserBigramSuggestHelper mHelper;
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        final AssetFileDescriptor dict = openTestRawResourceFd(R.raw.test);
-        final Locale locale = Locale.US;
-        mHelper = new UserBigramSuggestHelper(
-                getContext(), mTestPackageFile, dict.getStartOffset(), dict.getLength(),
-                MAX_DATA, DELETE_DATA,
-                createKeyboardSet(locale, Configuration.ORIENTATION_PORTRAIT), locale);
-    }
-
-    /************************** Tests ************************/
-
-    /**
-     * Test suggestion started at right time
-     */
-    public void testUserBigram() {
-        for (int i = 0; i < SUGGESTION_STARTS; i++) mHelper.addToUserBigram(pair1);
-        for (int i = 0; i < (SUGGESTION_STARTS - 1); i++) mHelper.addToUserBigram(pair2);
-
-        isInSuggestions("bigram", mHelper.searchUserBigramSuggestion("user", 'b', "bigram"));
-        isNotInSuggestions("platform",
-                mHelper.searchUserBigramSuggestion("android", 'p', "platform"));
-    }
-
-    /**
-     * Test loading correct (locale) bigrams
-     */
-    public void testOpenAndClose() {
-        for (int i = 0; i < SUGGESTION_STARTS; i++) mHelper.addToUserBigram(pair1);
-        isInSuggestions("bigram in default locale",
-                mHelper.searchUserBigramSuggestion("user", 'b', "bigram"));
-
-        // change to fr_FR
-        mHelper.changeUserBigramLocale(Locale.FRANCE);
-        for (int i = 0; i < SUGGESTION_STARTS; i++) mHelper.addToUserBigram(pair3);
-        isInSuggestions("france in fr_FR",
-                mHelper.searchUserBigramSuggestion("locale", 'f', "france"));
-        isNotInSuggestions("bigram in fr_FR",
-                mHelper.searchUserBigramSuggestion("user", 'b', "bigram"));
-
-        // change back to en_US
-        mHelper.changeUserBigramLocale(Locale.US);
-        isNotInSuggestions("france in en_US",
-                mHelper.searchUserBigramSuggestion("locale", 'f', "france"));
-        isInSuggestions("bigram in en_US",
-                mHelper.searchUserBigramSuggestion("user", 'b', "bigram"));
-    }
-
-    /**
-     * Test data gets pruned when it is over maximum
-     */
-    public void testPruningData() {
-        for (int i = 0; i < SUGGESTION_STARTS; i++) mHelper.addToUserBigram(sentence0);
-        mHelper.flushUserBigrams();
-        isInSuggestions("world after several sentence 0",
-                mHelper.searchUserBigramSuggestion("Hello", 'w', "world"));
-
-        mHelper.addToUserBigram(sentence1);
-        mHelper.addToUserBigram(sentence2);
-        isInSuggestions("world after sentence 1 and 2",
-                mHelper.searchUserBigramSuggestion("Hello", 'w', "world"));
-
-        // pruning should happen
-        mHelper.addToUserBigram(sentence3);
-        mHelper.addToUserBigram(sentence4);
-
-        // trying to reopen database to check pruning happened in database
-        mHelper.changeUserBigramLocale(Locale.US);
-        isNotInSuggestions("world after sentence 3 and 4",
-                mHelper.searchUserBigramSuggestion("Hello", 'w', "world"));
-    }
-
-    private static final String[] pair1 = {"user", "bigram"};
-    private static final String[] pair2 = {"android","platform"};
-    private static final String[] pair3 = {"locale", "france"};
-    private static final String sentence0 = "Hello world";
-    private static final String sentence1 = "This is a test for user input based bigram";
-    private static final String sentence2 = "It learns phrases that contain both dictionary and "
-        + "nondictionary words";
-    private static final String sentence3 = "This should give better suggestions than the previous "
-        + "version";
-    private static final String sentence4 = "Android stock keyboard is improving";
-}
diff --git a/tools/makedict/src/com/android/inputmethod/latin/BinaryDictInputOutput.java b/tools/makedict/src/com/android/inputmethod/latin/BinaryDictInputOutput.java
index 7aadc67..65b9074 100644
--- a/tools/makedict/src/com/android/inputmethod/latin/BinaryDictInputOutput.java
+++ b/tools/makedict/src/com/android/inputmethod/latin/BinaryDictInputOutput.java
@@ -112,8 +112,10 @@
      */
 
     private static final int MAGIC_NUMBER = 0x78B1;
-    private static final int VERSION = 1;
-    private static final int MAXIMUM_SUPPORTED_VERSION = VERSION;
+    private static final int MINIMUM_SUPPORTED_VERSION = 1;
+    private static final int MAXIMUM_SUPPORTED_VERSION = 2;
+    private static final int FIRST_VERSION_WITH_HEADER_SIZE = 2;
+
     // No options yet, reserved for future use.
     private static final int OPTIONS = 0;
 
@@ -797,9 +799,10 @@
      *
      * @param destination the stream to write the binary data to.
      * @param dict the dictionary to write.
+     * @param version the version of the format to write, currently either 1 or 2.
      */
-    public static void writeDictionaryBinary(OutputStream destination, FusionDictionary dict)
-            throws IOException {
+    public static void writeDictionaryBinary(OutputStream destination, FusionDictionary dict,
+            final int version) throws IOException, UnsupportedFormatException {
 
         // Addresses are limited to 3 bytes, so we'll just make a 16MB buffer. Since addresses
         // can be relative to each node, the structure itself is not limited to 16MB at all, but
@@ -811,16 +814,30 @@
         final byte[] buffer = new byte[1 << 24];
         int index = 0;
 
+        if (version < MINIMUM_SUPPORTED_VERSION || version > MAXIMUM_SUPPORTED_VERSION) {
+            throw new UnsupportedFormatException("Requested file format version " + version
+                    + ", but this implementation only supports versions "
+                    + MINIMUM_SUPPORTED_VERSION + " through " + MAXIMUM_SUPPORTED_VERSION);
+        }
+
         // Magic number in big-endian order.
         buffer[index++] = (byte) (0xFF & (MAGIC_NUMBER >> 8));
         buffer[index++] = (byte) (0xFF & MAGIC_NUMBER);
         // Dictionary version.
-        buffer[index++] = (byte) (0xFF & VERSION);
+        buffer[index++] = (byte) (0xFF & version);
         // Options flags
         buffer[index++] = (byte) (0xFF & (OPTIONS >> 8));
         buffer[index++] = (byte) (0xFF & OPTIONS);
+        if (version >= FIRST_VERSION_WITH_HEADER_SIZE) {
+            final int headerSizeOffset = index;
+            index += 3; // Size of the header size
 
-        // Should we include the locale and title of the dictionary ?
+            // Write out the header contents here.
+
+            buffer[headerSizeOffset] = (byte) (0xFF & (index >> 16));
+            buffer[headerSizeOffset + 1] = (byte) (0xFF & (index >> 8));
+            buffer[headerSizeOffset + 2] = (byte) (0xFF & (index >> 0));
+        }
 
         destination.write(buffer, 0, index);
         index = 0;
@@ -1125,7 +1142,16 @@
         // Read options
         source.readUnsignedShort();
 
-        long headerSize = source.getFilePointer();
+        final long headerSize;
+        if (version < FIRST_VERSION_WITH_HEADER_SIZE) {
+            headerSize = source.getFilePointer();
+        } else {
+            headerSize = source.readUnsignedByte() << 16 + source.readUnsignedByte() << 8
+                    + source.readUnsignedByte();
+            // read the header body
+            source.seek(headerSize);
+        }
+
         Map<Integer, Node> reverseNodeMapping = new TreeMap<Integer, Node>();
         Map<Integer, CharGroup> reverseGroupMapping = new TreeMap<Integer, CharGroup>();
         final Node root = readNode(source, headerSize, reverseNodeMapping, reverseGroupMapping);
diff --git a/tools/makedict/src/com/android/inputmethod/latin/DictionaryMaker.java b/tools/makedict/src/com/android/inputmethod/latin/DictionaryMaker.java
index 2fcd575..fbfa424 100644
--- a/tools/makedict/src/com/android/inputmethod/latin/DictionaryMaker.java
+++ b/tools/makedict/src/com/android/inputmethod/latin/DictionaryMaker.java
@@ -41,6 +41,7 @@
         private final static String OPTION_INPUT_BIGRAM_XML = "-b";
         private final static String OPTION_INPUT_SHORTCUT_XML = "-c";
         private final static String OPTION_OUTPUT_BINARY = "-d";
+        private final static String OPTION_OUTPUT_BINARY_FORMAT_VERSION_1 = "-d1";
         private final static String OPTION_OUTPUT_XML = "-x";
         private final static String OPTION_HELP = "-h";
         public final String mInputBinary;
@@ -48,11 +49,27 @@
         public final String mInputShortcutXml;
         public final String mInputBigramXml;
         public final String mOutputBinary;
+        public final String mOutputBinaryFormat1;
         public final String mOutputXml;
 
-        private void checkIntegrity() {
+        private void checkIntegrity() throws IOException {
             checkHasExactlyOneInput();
             checkHasAtLeastOneOutput();
+            checkNotSameFile(mInputBinary, mOutputBinary);
+            checkNotSameFile(mInputBinary, mOutputBinaryFormat1);
+            checkNotSameFile(mInputBinary, mOutputXml);
+            checkNotSameFile(mInputUnigramXml, mOutputBinary);
+            checkNotSameFile(mInputUnigramXml, mOutputBinaryFormat1);
+            checkNotSameFile(mInputUnigramXml, mOutputXml);
+            checkNotSameFile(mInputShortcutXml, mOutputBinary);
+            checkNotSameFile(mInputShortcutXml, mOutputBinaryFormat1);
+            checkNotSameFile(mInputShortcutXml, mOutputXml);
+            checkNotSameFile(mInputBigramXml, mOutputBinary);
+            checkNotSameFile(mInputBigramXml, mOutputBinaryFormat1);
+            checkNotSameFile(mInputBigramXml, mOutputXml);
+            checkNotSameFile(mOutputBinary, mOutputBinaryFormat1);
+            checkNotSameFile(mOutputBinary, mOutputXml);
+            checkNotSameFile(mOutputBinaryFormat1, mOutputXml);
         }
 
         private void checkHasExactlyOneInput() {
@@ -67,26 +84,40 @@
         }
 
         private void checkHasAtLeastOneOutput() {
-            if (null == mOutputBinary && null == mOutputXml) {
+            if (null == mOutputBinary && null == mOutputBinaryFormat1 && null == mOutputXml) {
                 throw new RuntimeException("No output specified");
             }
         }
 
+        /**
+         * Utility method that throws an exception if path1 and path2 point to the same file.
+         */
+        private static void checkNotSameFile(final String path1, final String path2)
+                throws IOException {
+            if (null == path1 || null == path2) return;
+            if (new File(path1).getCanonicalPath().equals(new File(path2).getCanonicalPath())) {
+                throw new RuntimeException(path1 + " and " + path2 + " are the same file: "
+                        + " refusing to process.");
+            }
+        }
+
         private void displayHelp() {
             MakedictLog.i("Usage: makedict "
                     + "[-s <unigrams.xml> [-b <bigrams.xml>] [-c <shortcuts.xml>] "
-                    + "| -s <binary input>] "
-                    + "[-d <binary output>] [-x <xml output>] [-2]\n"
+                    + "| -s <binary input>] [-d <binary output format version 2>] "
+                    + "[-d1 <binary output format version 1>] [-x <xml output>] [-2]\n"
                     + "\n"
                     + "  Converts a source dictionary file to one or several outputs.\n"
                     + "  Source can be an XML file, with an optional XML bigrams file, or a\n"
                     + "  binary dictionary file.\n"
-                    + "  Both binary and XML outputs are supported. Both can be output at\n"
-                    + "  the same time but outputting several files of the same type is not\n"
-                    + "  supported.");
+                    + "  Binary version 1 (Ice Cream Sandwich), 2 (Jelly Bean) and XML outputs\n"
+                    + "  are supported. All three can be output at the same time, but the same\n"
+                    + "  output format cannot be specified several times. The behavior is\n"
+                    + "  unspecified if the same file is specified for input and output, or for\n"
+                    + "  several outputs.");
         }
 
-        public Arguments(String[] argsArray) {
+        public Arguments(String[] argsArray) throws IOException {
             final LinkedList<String> args = new LinkedList<String>(Arrays.asList(argsArray));
             if (args.isEmpty()) {
                 displayHelp();
@@ -96,6 +127,7 @@
             String inputShortcutXml = null;
             String inputBigramXml = null;
             String outputBinary = null;
+            String outputBinaryFormat1 = null;
             String outputXml = null;
 
             while (!args.isEmpty()) {
@@ -126,6 +158,8 @@
                             inputBigramXml = filename;
                         } else if (OPTION_OUTPUT_BINARY.equals(arg)) {
                             outputBinary = filename;
+                        } else if (OPTION_OUTPUT_BINARY_FORMAT_VERSION_1.equals(arg)) {
+                            outputBinaryFormat1 = filename;
                         } else if (OPTION_OUTPUT_XML.equals(arg)) {
                             outputXml = filename;
                         } else {
@@ -152,6 +186,7 @@
             mInputShortcutXml = inputShortcutXml;
             mInputBigramXml = inputBigramXml;
             mOutputBinary = outputBinary;
+            mOutputBinaryFormat1 = outputBinaryFormat1;
             mOutputXml = outputXml;
             checkIntegrity();
         }
@@ -231,9 +266,13 @@
      * @throws IOException if one of the output files can't be written to.
      */
     private static void writeOutputToParsedArgs(final Arguments args, final FusionDictionary dict)
-            throws FileNotFoundException, IOException {
+            throws FileNotFoundException, IOException, UnsupportedFormatException,
+            IllegalArgumentException {
         if (null != args.mOutputBinary) {
-            writeBinaryDictionary(args.mOutputBinary, dict);
+            writeBinaryDictionary(args.mOutputBinary, dict, 2);
+        }
+        if (null != args.mOutputBinaryFormat1) {
+            writeBinaryDictionary(args.mOutputBinaryFormat1, dict, 1);
         }
         if (null != args.mOutputXml) {
             writeXmlDictionary(args.mOutputXml, dict);
@@ -245,13 +284,16 @@
      *
      * @param outputFilename the name of the file to write to.
      * @param dict the dictionary to write.
+     * @param version the binary format version to use.
      * @throws FileNotFoundException if the output file can't be created.
      * @throws IOException if the output file can't be written to.
      */
     private static void writeBinaryDictionary(final String outputFilename,
-            final FusionDictionary dict) throws FileNotFoundException, IOException {
+            final FusionDictionary dict, final int version)
+            throws FileNotFoundException, IOException, UnsupportedFormatException {
         final File outputFile = new File(outputFilename);
-        BinaryDictInputOutput.writeDictionaryBinary(new FileOutputStream(outputFilename), dict);
+        BinaryDictInputOutput.writeDictionaryBinary(new FileOutputStream(outputFilename), dict,
+                version);
     }
 
     /**