Merge "Move getPrevWordsInfoFromNthPreviousWord to StringUtlis."
diff --git a/dictionaries/es_wordlist.combined.gz b/dictionaries/es_wordlist.combined.gz
index c0a5264..41a914c 100644
--- a/dictionaries/es_wordlist.combined.gz
+++ b/dictionaries/es_wordlist.combined.gz
Binary files differ
diff --git a/java/res/raw/main_es.dict b/java/res/raw/main_es.dict
index 0911b70..3c99e73 100644
--- a/java/res/raw/main_es.dict
+++ b/java/res/raw/main_es.dict
Binary files differ
diff --git a/java/res/xml-sw600dp/rows_sinhala.xml b/java/res/xml-sw600dp/rows_sinhala.xml
new file mode 100644
index 0000000..23c3f3a
--- /dev/null
+++ b/java/res/xml-sw600dp/rows_sinhala.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/key_styles_common" />
+    <Row
+        latin:keyWidth="8.182%p"
+    >
+        <include
+            latin:keyboardLayout="@xml/rowkeys_sinhala1" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <Row
+        latin:keyWidth="8.182%p"
+    >
+        <include
+            latin:keyboardLayout="@xml/rowkeys_sinhala2" />
+        <Key
+            latin:keyStyle="enterKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <Row
+        latin:keyWidth="8.182%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="10.0%p" />
+        <include
+            latin:keyboardLayout="@xml/rowkeys_sinhala3" />
+        <include
+            latin:keyboardLayout="@xml/keys_exclamation_question" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/res/xml/kbd_sinhala.xml b/java/res/xml/kbd_sinhala.xml
new file mode 100644
index 0000000..6c0f4bc
--- /dev/null
+++ b/java/res/xml/kbd_sinhala.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/rows_sinhala" />
+</Keyboard>
diff --git a/java/res/xml/keyboard_layout_set_sinhala.xml b/java/res/xml/keyboard_layout_set_sinhala.xml
new file mode 100644
index 0000000..8e6e619
--- /dev/null
+++ b/java/res/xml/keyboard_layout_set_sinhala.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<KeyboardLayoutSet
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+    <Element
+        latin:elementName="alphabet"
+        latin:elementKeyboard="@xml/kbd_sinhala"
+        latin:enableProximityCharsCorrection="true" />
+    <Element
+        latin:elementName="alphabetAutomaticShifted"
+        latin:elementKeyboard="@xml/kbd_sinhala"
+        latin:enableProximityCharsCorrection="true" />
+    <!-- On these shifted alphabet layouts the proximity characters correction should be disabled
+         because the letters on these layouts aren't the ones in different case of the above
+         unshifted layouts. -->
+    <Element
+        latin:elementName="alphabetManualShifted"
+        latin:elementKeyboard="@xml/kbd_sinhala" />
+    <Element
+        latin:elementName="alphabetShiftLocked"
+        latin:elementKeyboard="@xml/kbd_sinhala" />
+    <Element
+        latin:elementName="alphabetShiftLockShifted"
+        latin:elementKeyboard="@xml/kbd_sinhala" />
+    <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" />
+</KeyboardLayoutSet>
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index 777a13d..68dce8a 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -81,6 +81,7 @@
     pt_PT: Portuguese (Portugal)/qwerty
     ro: Romanian/qwerty
     ru: Russian/east_slavic
+    (si_LK: Sinhala (Sri Lanka)/sinhala) # This is a preliminary keyboard layout.
     sk: Slovak/qwerty
     sl: Slovenian/qwerty
     sr: Serbian/south_slavic
@@ -332,7 +333,6 @@
     />
     <!-- TODO: This hindi_compact keyboard is a preliminary layout.
                This isn't based on the final specification. -->
-    <!--
     <subtype android:icon="@drawable/ic_ime_switcher_dark"
             android:label="@string/subtype_generic_compact"
             android:subtypeId="0xe49c89a1"
@@ -341,7 +341,6 @@
             android:imeSubtypeExtraValue="KeyboardLayoutSet=hindi_compact,EmojiCapable"
             android:isAsciiCapable="false"
     />
-    -->
     <subtype android:icon="@drawable/ic_ime_switcher_dark"
             android:label="@string/subtype_generic"
             android:subtypeId="0x35b7526a"
@@ -482,7 +481,6 @@
     />
     <!-- TODO: This marathi keyboard is a preliminary layout.
                This isn't based on the final specification. -->
-    <!--
     <subtype android:icon="@drawable/ic_ime_switcher_dark"
             android:label="@string/subtype_generic"
             android:subtypeId="0x747b9f03"
@@ -491,7 +489,6 @@
             android:imeSubtypeExtraValue="KeyboardLayoutSet=marathi,EmojiCapable"
             android:isAsciiCapable="false"
     />
-    -->
     <subtype android:icon="@drawable/ic_ime_switcher_dark"
             android:label="@string/subtype_generic"
             android:subtypeId="0x84c87c61"
@@ -502,7 +499,6 @@
     />
     <!-- TODO: This Myanmar keyboard is a preliminary layout.
                This isn't based on the final specification. -->
-    <!--
     <subtype android:icon="@drawable/ic_ime_switcher_dark"
             android:label="@string/subtype_generic"
             android:subtypeId="0xea266ea4"
@@ -511,7 +507,6 @@
             android:imeSubtypeExtraValue="KeyboardLayoutSet=myanmar,EmojiCapable,CombiningRules=MyanmarReordering"
             android:isAsciiCapable="false"
     />
-    -->
     <subtype android:icon="@drawable/ic_ime_switcher_dark"
             android:label="@string/subtype_generic"
             android:subtypeId="0x3f12ee14"
@@ -592,6 +587,16 @@
             android:imeSubtypeExtraValue="SupportTouchPositionCorrection,EmojiCapable"
             android:isAsciiCapable="false"
     />
+    <!-- TODO: This sinhala keyboard is a preliminary layout.
+               This isn't based on the final specification. -->
+    <subtype android:icon="@drawable/ic_ime_switcher_dark"
+            android:label="@string/subtype_generic"
+            android:subtypeId="0x5c6b3bde"
+            android:imeSubtypeLocale="si_LK"
+            android:imeSubtypeMode="keyboard"
+            android:imeSubtypeExtraValue="KeyboardLayoutSet=sinhala,EmojiCapable"
+            android:isAsciiCapable="false"
+    />
     <subtype android:icon="@drawable/ic_ime_switcher_dark"
             android:label="@string/subtype_generic"
             android:subtypeId="0x8e94d413"
diff --git a/java/res/xml/rowkeys_sinhala1.xml b/java/res/xml/rowkeys_sinhala1.xml
new file mode 100644
index 0000000..f258ae2
--- /dev/null
+++ b/java/res/xml/rowkeys_sinhala1.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <switch>
+        <case
+            latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+        >
+            <!-- U+0DD6: "ූ" SINHALA VOWEL SIGN DIGA PAA-PILLA -->
+            <Key
+                latin:keySpec="&#x0DD6;"
+                latin:additionalMoreKeys="1" />
+            <!-- U+0D8B: "උ" SINHALA LETTER UYANNA -->
+            <Key
+                latin:keySpec="&#x0D8B;"
+                latin:additionalMoreKeys="2" />
+            <!-- U+0DD1: "ෑ" SINHALA VOWEL SIGN DIGA AEDA-PILLA -->
+            <Key
+                latin:keySpec="&#x0DD1;"
+                latin:additionalMoreKeys="3" />
+            <!-- U+0D8D: "ඍ" SINHALA LETTER IRUYANNA -->
+            <Key
+                latin:keySpec="&#x0D8D;"
+                latin:additionalMoreKeys="4" />
+            <!-- U+0D94: "ඔ" SINHALA LETTER OYANNA -->
+            <Key
+                latin:keySpec="&#x0D94;"
+                latin:additionalMoreKeys="5" />
+            <!-- U+0DC1: "ශ" SINHALA LETTER TAALUJA SAYANNA -->
+            <Key
+                latin:keySpec="&#x0DC1;"
+                latin:additionalMoreKeys="6" />
+            <!-- U+0DB9: "ඹ" SINHALA LETTER AMBA BAYANNA -->
+            <Key
+                latin:keySpec="&#x0DB9;"
+                latin:additionalMoreKeys="7" />
+            <!-- U+0DC2: "ෂ" SINHALA LETTER MUURDHAJA SAYANNA -->
+            <Key
+                latin:keySpec="&#x0DC2;"
+                latin:additionalMoreKeys="8" />
+            <!-- U+0DB0: "ධ" SINHALA LETTER MAHAAPRAANA DAYANNA -->
+            <Key
+                latin:keySpec="&#x0DB0;"
+                latin:additionalMoreKeys="9" />
+            <!-- U+0DA1: "ඡ" SINHALA LETTER MAHAAPRAANA CAYANNA -->
+            <Key
+                latin:keySpec="&#x0DA1;"
+                latin:additionalMoreKeys="0" />
+            <!-- U+0DA5: "ඥ" SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA
+                 U+0DF4: "෴" SINHALA PUNCTUATION KUNDDALIYA  -->
+            <Key
+                latin:keySpec="&#x0DA5;"
+                latin:moreKeys="&#x0DF4;" />
+        </case>
+        <default>
+            <!-- U+0DD4: "ු" SINHALA VOWEL SIGN KETTI PAA-PILLA -->
+            <Key
+                latin:keySpec="&#x0DD4;"
+                latin:additionalMoreKeys="1" />
+            <!-- U+0D85: "අ" SINHALA LETTER AYANNA -->
+            <Key
+                latin:keySpec="&#x0D85;"
+                latin:additionalMoreKeys="2" />
+            <!-- U+0DD0: "ැ" SINHALA VOWEL SIGN KETTI AEDA-PILLA -->
+            <Key
+                latin:keySpec="&#x0DD0;"
+                latin:additionalMoreKeys="3" />
+            <!-- U+0DBB: "ර" SINHALA LETTER RAYANNA -->
+            <Key
+                latin:keySpec="&#x0DBB;"
+                latin:additionalMoreKeys="4" />
+            <!-- U+0D91: "එ" SINHALA LETTER EYANNA -->
+            <Key
+                latin:keySpec="&#x0D91;"
+                latin:additionalMoreKeys="5" />
+            <!-- U+0DC4: "හ" SINHALA LETTER HAYANNA -->
+            <Key
+                latin:keySpec="&#x0DC4;"
+                latin:additionalMoreKeys="6" />
+            <!-- U+0DB8: "ම" SINHALA LETTER MAYANNA -->
+            <Key
+                latin:keySpec="&#x0DB8;"
+                latin:additionalMoreKeys="7" />
+            <!-- U+0DC3: "ස" SINHALA LETTER DANTAJA SAYANNA -->
+            <Key
+                latin:keySpec="&#x0DC3;"
+                latin:additionalMoreKeys="8" />
+            <!-- U+0DAF: "ද" SINHALA LETTER ALPAPRAANA DAYANNA
+                 U+0DB3: "ඳ" SINHALA LETTER SANYAKA DAYANNA -->
+            <Key
+                latin:keySpec="&#x0DAF;"
+                latin:moreKeys="&#x0DB3;"
+                latin:additionalMoreKeys="9" />
+            <!-- U+0DA0: "ච" SINHALA LETTER ALPAPRAANA CAYANNA -->
+            <Key
+                latin:keySpec="&#x0DA0;"
+                latin:additionalMoreKeys="0" />
+            <!-- U+0DA4: "ඤ" SINHALA LETTER TAALUJA NAASIKYAYA
+                 U+0DF4: "෴" SINHALA PUNCTUATION KUNDDALIYA -->
+            <Key
+                latin:keySpec="&#x0DA4;"
+                latin:moreKeys="&#x0DF4;" />
+         </default>
+    </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_sinhala2.xml b/java/res/xml/rowkeys_sinhala2.xml
new file mode 100644
index 0000000..91c1928
--- /dev/null
+++ b/java/res/xml/rowkeys_sinhala2.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <switch>
+        <case
+            latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+        >
+            <!-- U+0DDF: "ෟ" SINHALA VOWEL SIGN GAYANUKITTA -->
+            <Key
+                latin:keySpec="&#x0DDF;" />
+            <!-- U+0DD3: "ී" SINHALA VOWEL SIGN DIGA IS-PILLA -->
+            <Key
+                latin:keySpec="&#x0DD3;" />
+            <!-- U+0DD8: "ෘ" SINHALA VOWEL SIGN GAETTA-PILLA -->
+            <Key
+                latin:keySpec="&#x0DD8;" />
+            <!-- U+0DC6: "ෆ" SINHALA LETTER FAYANNA -->
+            <Key
+                latin:keySpec="&#x0DC6;" />
+            <!-- U+0DA8: "ඨ" SINHALA LETTER MAHAAPRAANA TTAYANNA -->
+            <Key
+                latin:keySpec="&#x0DA8;" />
+            <!-- U+0DCA/U+200D/U+0DBA: "්‍ය" SINHALA SIGN AL-LAKUNA/ZERO WIDTH JOINER/SINHALA LETTER YAYANNA -->
+            <Key
+                latin:keySpec="&#x0DCA;&#x200D;&#x0DBA;" />
+            <!-- U+0DC5/U+0DD4: "ළු" SINHALA LETTER MUURDHAJA LAYANNA/SINHALA VOWEL SIGN KETTI PAA-PILLA -->
+            <Key
+                latin:keySpec="&#x0DC5;&#x0DD4;" />
+            <!-- U+0DAB: "ණ" SINHALA LETTER MUURDHAJA NAYANNA -->
+            <Key
+                latin:keySpec="&#x0DAB;" />
+            <!-- U+0D9B: "ඛ" SINHALA LETTER MAHAAPRAANA KAYANNA -->
+            <Key
+                latin:keySpec="&#x0D9B;" />
+            <!-- U+0DAE: "ථ" SINHALA LETTER MAHAAPRAANA TAYANNA -->
+            <Key
+                latin:keySpec="&#x0DAE;" />
+            <!-- U+0DCA/U+200D/U+0DBB: "්‍ර" SINHALA SIGN AL-LAKUNA/ZERO WIDTH JOINER/SINHALA LETTER RAYANNA -->
+            <Key
+                latin:keySpec="&#x0DCA;&#x200D;&#x0DBB;" />
+        </case>
+        <default>
+            <!-- U+0DCA: "්" SINHALA SIGN AL-LAKUNA -->
+            <Key
+                latin:keySpec="&#x0DCA;" />
+            <!-- U+0DD2: "ි" SINHALA VOWEL SIGN KETTI IS-PILLA -->
+            <Key
+                latin:keySpec="&#x0DD2;" />
+            <!-- U+0DCF: "ා" SINHALA VOWEL SIGN AELA-PILLA -->
+            <Key
+                latin:keySpec="&#x0DCF;" />
+            <!-- U+0DD9: "ෙ" SINHALA VOWEL SIGN KOMBUVA -->
+            <Key
+                latin:keySpec="&#x0DD9;" />
+            <!-- U+0DA7: "ට" SINHALA LETTER ALPAPRAANA TTAYANNA -->
+            <Key
+                latin:keySpec="&#x0DA7;" />
+            <!-- U+0DBA: "ය" SINHALA LETTER YAYANNA -->
+            <Key
+                latin:keySpec="&#x0DBA;" />
+            <!-- U+0DC0: "ව" SINHALA LETTER VAYANNA -->
+            <Key
+                latin:keySpec="&#x0DC0;" />
+            <!-- U+0DB1: "න" SINHALA LETTER DANTAJA NAYANNA -->
+            <Key
+                latin:keySpec="&#x0DB1;" />
+            <!-- U+0D9A: "ක" SINHALA LETTER ALPAPRAANA KAYANNA -->
+            <Key
+                latin:keySpec="&#x0D9A;" />
+            <!-- U+0DAD: "ත" SINHALA LETTER ALPAPRAANA TAYANNA -->
+            <Key
+                latin:keySpec="&#x0DAD;" />
+            <!-- U+0D8F: "ඏ" SINHALA LETTER ILUYANNA -->
+            <Key
+                latin:keySpec="&#x0D8F;" />
+         </default>
+    </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_sinhala3.xml b/java/res/xml/rowkeys_sinhala3.xml
new file mode 100644
index 0000000..64ba9f3
--- /dev/null
+++ b/java/res/xml/rowkeys_sinhala3.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <switch>
+        <case
+            latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+        >
+            <!-- U+0D9E: "ඞ" SINHALA LETTER KANTAJA NAASIKYAYA -->
+            <Key
+                latin:keySpec="&#x0D9E;" />
+            <!-- U+0DA3: "ඣ" SINHALA LETTER MAHAAPRAANA JAYANNA -->
+            <Key
+                latin:keySpec="&#x0DA3;" />
+            <!-- U+0DAA: "ඪ" SINHALA LETTER MAHAAPRAANA DDAYANNA -->
+            <Key
+                latin:keySpec="&#x0DAA;" />
+            <!-- U+0D8A: "ඊ" SINHALA LETTER IIYANNA -->
+            <Key
+                latin:keySpec="&#x0D8A;" />
+            <!-- U+0DB7: "භ" SINHALA LETTER MAHAAPRAANA BAYANNA -->
+            <Key
+                latin:keySpec="&#x0DB7;" />
+            <!-- U+0DB5: "ඵ" SINHALA LETTER MAHAAPRAANA PAYANNA -->
+            <Key
+                latin:keySpec="&#x0DB5;" />
+            <!-- U+0DC5: "ළ" SINHALA LETTER MUURDHAJA LAYANNA -->
+            <Key
+                latin:keySpec="&#x0DC5;" />
+            <!-- U+0D9D: "ඝ" SINHALA LETTER MAHAAPRAANA GAYANNA -->
+            <Key
+                latin:keySpec="&#x0D9D;" />
+            <!-- U+0DBB/U+0DCA/U+200D: "ර්‍" SINHALA LETTER RAYANNA/SINHALA SIGN AL-LAKUNA/ZERO WIDTH JOINER -->
+            <Key
+                latin:keySpec="&#x0DBB;&#x0DCA;&#x200D;" />
+        </case>
+        <default>
+            <!-- U+0D82: "ං" SINHALA SIGN ANUSVARAYA
+                 U+0D83: "ඃ" SINHALA SIGN VISARGAYA -->
+            <Key
+                latin:keySpec="&#x0D82;"
+                latin:moreKeys="&#x0D83;" />
+            <!-- U+0DA2: "ජ" SINHALA LETTER ALPAPRAANA JAYANNA
+                 U+0DA6: "ඦ" SINHALA LETTER SANYAKA JAYANNA -->
+            <Key
+                latin:keySpec="&#x0DA2;"
+                latin:moreKeys="&#x0DA6;" />
+            <!-- U+0DA9: "ඩ" SINHALA LETTER ALPAPRAANA DDAYANNA
+                 U+0DAC: "ඬ" SINHALA LETTER SANYAKA DDAYANNA -->
+            <Key
+                latin:keySpec="&#x0DA9;"
+                latin:moreKeys="&#x0DAC;" />
+            <!-- U+0D89: "ඉ" SINHALA LETTER IYANNA -->
+            <Key
+                latin:keySpec="&#x0D89;" />
+            <!-- U+0DB6: "බ" SINHALA LETTER ALPAPRAANA BAYANNA -->
+            <Key
+                latin:keySpec="&#x0DB6;" />
+            <!-- U+0DB4: "ප" SINHALA LETTER ALPAPRAANA PAYANNA -->
+            <Key
+                latin:keySpec="&#x0DB4;" />
+            <!-- U+0DBD: "ල" SINHALA LETTER DANTAJA LAYANNA -->
+            <Key
+                latin:keySpec="&#x0DBD;" />
+            <!-- U+0D9C: "ග" SINHALA LETTER ALPAPRAANA GAYANNA
+                 U+0D9F: "ඟ" SINHALA LETTER SANYAKA GAYANNA -->
+            <Key
+                latin:keySpec="&#x0D9C;"
+                latin:moreKeys="&#x0D9F;" />
+            <!-- U+0DF3: "ෳ" SINHALA VOWEL SIGN DIGA GAYANUKITTA -->
+            <Key
+                latin:keySpec="&#x0DF3;" />
+         </default>
+    </switch>
+</merge>
diff --git a/java/res/xml/rows_sinhala.xml b/java/res/xml/rows_sinhala.xml
new file mode 100644
index 0000000..b47b373
--- /dev/null
+++ b/java/res/xml/rows_sinhala.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+    xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+    <include
+        latin:keyboardLayout="@xml/key_styles_common" />
+    <Row
+        latin:keyWidth="9.091%p"
+    >
+        <include
+            latin:keyboardLayout="@xml/rowkeys_sinhala1" />
+    </Row>
+    <Row
+            latin:keyWidth="9.091%p"
+    >
+        <include
+            latin:keyboardLayout="@xml/rowkeys_sinhala2" />
+    </Row>
+    <Row
+        latin:keyWidth="8.711%p"
+    >
+        <Key
+            latin:keyStyle="shiftKeyStyle"
+            latin:keyWidth="10.8%p" />
+        <include
+            latin:keyboardLayout="@xml/rowkeys_sinhala3" />
+        <Key
+            latin:keyStyle="deleteKeyStyle"
+            latin:keyWidth="fillRight" />
+    </Row>
+    <include
+        latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java
index 3925fc6..eb5b663 100644
--- a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java
+++ b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityDelegate.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.support.v4.view.AccessibilityDelegateCompat;
 import android.support.v4.view.ViewCompat;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
 import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -31,7 +30,6 @@
 import com.android.inputmethod.keyboard.KeyDetector;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardView;
-import com.android.inputmethod.keyboard.PointerTracker;
 
 /**
  * This class represents a delegate that can be registered in a class that extends
@@ -264,33 +262,16 @@
     }
 
     /**
-     * Simulating a touch event by injecting a synthesized touch event into {@link PointerTracker}.
+     * Simulating a touch event by injecting a synthesized touch event into {@link KeyboardView}.
      *
      * @param touchAction The action of the synthesizing touch event.
      * @param hoverEvent The base hover event from that the touch event is synthesized.
      */
-    protected void simulateTouchEvent(final int touchAction, final MotionEvent hoverEvent) {
-        final MotionEvent touchEvent = synthesizeTouchEvent(touchAction, hoverEvent);
-        final int actionIndex = touchEvent.getActionIndex();
-        final int pointerId = touchEvent.getPointerId(actionIndex);
-        final PointerTracker tracker = PointerTracker.getPointerTracker(pointerId);
-        tracker.processMotionEvent(touchEvent, mKeyDetector);
-        touchEvent.recycle();
-    }
-
-    /**
-     * Synthesize a touch event from a hover event.
-     *
-     * @param touchAction The action of the synthesizing touch event.
-     * @param hoverEvent The base hover event from that the touch event is synthesized.
-     * @return The synthesized touch event of <code>touchAction</code> that has pointer information
-     * of <code>event</code>.
-     */
-    protected static MotionEvent synthesizeTouchEvent(final int touchAction,
-            final MotionEvent hoverEvent) {
+    private void simulateTouchEvent(final int touchAction, final MotionEvent hoverEvent) {
         final MotionEvent touchEvent = MotionEvent.obtain(hoverEvent);
         touchEvent.setAction(touchAction);
-        return touchEvent;
+        mKeyboardView.onTouchEvent(touchEvent);
+        touchEvent.recycle();
     }
 
     /**
diff --git a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java
index 61d066a..328d9ec 100644
--- a/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/KeyboardAccessibilityNodeProvider.java
@@ -68,7 +68,7 @@
     /** The virtual view identifier for the hovering node. */
     private int mHoveringNodeId = UNDEFINED;
 
-    /** The current keyboard view. */
+    /** The keyboard view to provide an accessibility node info. */
     private final KeyboardView mKeyboardView;
 
     /** The current keyboard. */
diff --git a/java/src/com/android/inputmethod/accessibility/MoreSuggestionsAccessibilityDelegate.java b/java/src/com/android/inputmethod/accessibility/MoreSuggestionsAccessibilityDelegate.java
deleted file mode 100644
index dfc8661..0000000
--- a/java/src/com/android/inputmethod/accessibility/MoreSuggestionsAccessibilityDelegate.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.accessibility;
-
-import android.view.MotionEvent;
-
-import com.android.inputmethod.keyboard.KeyDetector;
-import com.android.inputmethod.keyboard.MoreKeysKeyboardView;
-
-public final class MoreSuggestionsAccessibilityDelegate
-        extends MoreKeysKeyboardAccessibilityDelegate {
-    public MoreSuggestionsAccessibilityDelegate(final MoreKeysKeyboardView moreKeysKeyboardView,
-            final KeyDetector keyDetector) {
-        super(moreKeysKeyboardView, keyDetector);
-    }
-
-    @Override
-    protected void simulateTouchEvent(final int touchAction, final MotionEvent hoverEvent) {
-        final MotionEvent touchEvent = synthesizeTouchEvent(touchAction, hoverEvent);
-        mKeyboardView.onTouchEvent(touchEvent);
-        touchEvent.recycle();
-    }
-}
diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java
index 4a9163c..d257441 100644
--- a/java/src/com/android/inputmethod/event/Event.java
+++ b/java/src/com/android/inputmethod/event/Event.java
@@ -225,6 +225,13 @@
                 null /* suggestedWordInfo */, FLAG_NONE, null);
     }
 
+    // Returns whether this is a function key like backspace, ctrl, settings... as opposed to keys
+    // that result in input like letters or space.
+    public boolean isFunctionalKeyEvent() {
+        // This logic may need to be refined in the future
+        return NOT_A_CODE_POINT == mCodePoint;
+    }
+
     // Returns whether this event is for a dead character. @see {@link #FLAG_DEAD}
     public boolean isDead() {
         return 0 != (FLAG_DEAD & mFlags);
diff --git a/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java b/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java
index 05ba999..c61f45e 100644
--- a/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java
+++ b/java/src/com/android/inputmethod/event/HardwareKeyboardEventDecoder.java
@@ -74,7 +74,7 @@
             }
             // If not Enter, then this is just a regular keypress event for a normal character
             // that can be committed right away, taking into account the current state.
-            return Event.createHardwareKeypressEvent(keyCode, codePointAndFlags, null /* next */,
+            return Event.createHardwareKeypressEvent(codePointAndFlags, keyCode, null /* next */,
                     isKeyRepeat);
         }
         return Event.createNotHandledEvent();
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
index 3994487..5140c4f 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboardView.java
@@ -126,7 +126,7 @@
     @Override
     public void onDownEvent(final int x, final int y, final int pointerId, final long eventTime) {
         mActivePointerId = pointerId;
-        mCurrentKey = detectKey(x, y, pointerId);
+        mCurrentKey = detectKey(x, y);
     }
 
     @Override
@@ -135,7 +135,7 @@
             return;
         }
         final boolean hasOldKey = (mCurrentKey != null);
-        mCurrentKey = detectKey(x, y, pointerId);
+        mCurrentKey = detectKey(x, y);
         if (hasOldKey && mCurrentKey == null) {
             // A more keys keyboard is canceled when detecting no key.
             mController.onCancelMoreKeysPanel();
@@ -149,7 +149,7 @@
         }
         // Calling {@link #detectKey(int,int,int)} here is harmless because the last move event and
         // the following up event share the same coordinates.
-        mCurrentKey = detectKey(x, y, pointerId);
+        mCurrentKey = detectKey(x, y);
         if (mCurrentKey != null) {
             updateReleaseKeyGraphics(mCurrentKey);
             onKeyInput(mCurrentKey, x, y);
@@ -174,7 +174,7 @@
         }
     }
 
-    private Key detectKey(int x, int y, int pointerId) {
+    private Key detectKey(int x, int y) {
         final Key oldKey = mCurrentKey;
         final Key newKey = mKeyDetector.detectHitKey(x, y);
         if (newKey == oldKey) {
diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java
index 8010a3e..17dfc9c 100644
--- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPageKeyboardView.java
@@ -56,22 +56,7 @@
     private OnKeyEventListener mListener = EMPTY_LISTENER;
     private final KeyDetector mKeyDetector = new KeyDetector();
     private final GestureDetector mGestureDetector;
-    private EmojiPageKeyboardAccessibilityDelegate mAccessibilityDelegate;
-
-    private static final class EmojiPageKeyboardAccessibilityDelegate
-            extends KeyboardAccessibilityDelegate<EmojiPageKeyboardView> {
-        public EmojiPageKeyboardAccessibilityDelegate(final EmojiPageKeyboardView keyboardView,
-                final KeyDetector keyDetector) {
-            super(keyboardView, keyDetector);
-        }
-
-        @Override
-        protected void simulateTouchEvent(int touchAction, MotionEvent hoverEvent) {
-            final MotionEvent touchEvent = synthesizeTouchEvent(touchAction, hoverEvent);
-            mKeyboardView.onTouchEvent(touchEvent);
-            touchEvent.recycle();
-        }
-    }
+    private KeyboardAccessibilityDelegate<EmojiPageKeyboardView> mAccessibilityDelegate;
 
     public EmojiPageKeyboardView(final Context context, final AttributeSet attrs) {
         this(context, attrs, R.attr.keyboardViewStyle);
@@ -98,8 +83,7 @@
         mKeyDetector.setKeyboard(keyboard, 0 /* correctionX */, 0 /* correctionY */);
         if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
             if (mAccessibilityDelegate == null) {
-                mAccessibilityDelegate = new EmojiPageKeyboardAccessibilityDelegate(
-                        this, mKeyDetector);
+                mAccessibilityDelegate = new KeyboardAccessibilityDelegate<>(this, mKeyDetector);
             }
             mAccessibilityDelegate.setKeyboard(keyboard);
         } else {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
index ab25558..13b174e 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java
@@ -89,9 +89,9 @@
         /*   3:29 */ "morekeys_e",
         /*   4:28 */ "morekeys_i",
         /*   5:23 */ "morekeys_c",
-        /*   6:23 */ "double_quotes",
-        /*   7:22 */ "morekeys_n",
-        /*   8:22 */ "keylabel_to_alpha",
+        /*   6:23 */ "keylabel_to_alpha",
+        /*   7:23 */ "double_quotes",
+        /*   8:22 */ "morekeys_n",
         /*   9:22 */ "single_quotes",
         /*  10:20 */ "morekeys_s",
         /*  11:14 */ "morekeys_y",
@@ -260,10 +260,10 @@
         /* morekeys_a ~ */
         EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
         /* ~ morekeys_c */
-        /* double_quotes */ "!text/double_lqm_rqm",
-        /* morekeys_n */ EMPTY,
         // Label for "switch to alphabetic" key.
         /* keylabel_to_alpha */ "ABC",
+        /* double_quotes */ "!text/double_lqm_rqm",
+        /* morekeys_n */ EMPTY,
         /* single_quotes */ "!text/single_lqm_rqm",
         /* morekeys_s ~ */
         EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
@@ -507,14 +507,14 @@
         // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
         // U+0133: "ij" LATIN SMALL LIGATURE IJ
         /* morekeys_i */ "\u00ED,\u00EC,\u00EF,\u00EE,\u012F,\u012B,\u0133",
-        /* morekeys_c */ null,
-        /* double_quotes */ null,
+        /* morekeys_c ~ */
+        null, null, null,
+        /* ~ double_quotes */
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         /* morekeys_n */ "\u00F1,\u0144",
-        /* keylabel_to_alpha ~ */
-        null, null, null,
-        /* ~ morekeys_s */
+        /* single_quotes */ null,
+        /* morekeys_s */ null,
         // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
         // U+0133: "ij" LATIN SMALL LIGATURE IJ
         /* morekeys_y */ "\u00FD,\u0133",
@@ -523,17 +523,17 @@
     /* Locale ar: Arabic */
     private static final String[] TEXTS_ar = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE
         // U+200C: ZERO WIDTH NON-JOINER
         // U+0628: "ب" ARABIC LETTER BEH
         // U+062C: "ج" ARABIC LETTER JEEM
         /* keylabel_to_alpha */ "\u0623\u200C\u0628\u200C\u062C",
-        /* single_quotes ~ */
+        /* double_quotes ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null, null,
+        null, null, null, null, null, null, null, null, null, null,
         /* ~ morekeys_cyrillic_soft_sign */
         // U+0661: "١" ARABIC-INDIC DIGIT ONE
         /* keyspec_symbols_1 */ "\u0661",
@@ -685,7 +685,7 @@
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         // U+010D: "č" LATIN SMALL LETTER C WITH CARON
         /* morekeys_c */ "\u00E7,\u0107,\u010D",
-        /* double_quotes ~ */
+        /* keylabel_to_alpha ~ */
         null, null, null, null,
         /* ~ single_quotes */
         // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
@@ -705,13 +705,13 @@
         /* morekeys_a ~ */
         null, null, null, null, null, null,
         /* ~ morekeys_c */
-        /* double_quotes */ "!text/double_9qm_lqm",
-        /* morekeys_n */ null,
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
         /* keylabel_to_alpha */ "\u0410\u0411\u0412",
+        /* double_quotes */ "!text/double_9qm_lqm",
+        /* morekeys_n */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         /* morekeys_s ~ */
         null, null, null, null, null, null, null, null, null, null, null, null,
@@ -738,14 +738,13 @@
         /* morekeys_a ~ */
         null, null, null, null, null, null,
         /* ~ morekeys_c */
-        // single_quotes of Bulgarian is default single_quotes_right_left.
-        /* double_quotes */ "!text/double_9qm_lqm",
-        /* morekeys_n */ null,
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
         /* keylabel_to_alpha */ "\u0410\u0411\u0412",
+        // single_quotes of Bulgarian is default single_quotes_right_left.
+        /* double_quotes */ "!text/double_9qm_lqm",
     };
 
     /* Locale ca: Catalan */
@@ -796,12 +795,13 @@
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         // U+010D: "č" LATIN SMALL LETTER C WITH CARON
         /* morekeys_c */ "\u00E7,\u0107,\u010D",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ null,
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         /* morekeys_n */ "\u00F1,\u0144",
-        /* keylabel_to_alpha ~ */
-        null, null, null, null, null, null, null,
+        /* single_quotes ~ */
+        null, null, null, null, null, null,
         /* ~ morekeys_t */
         // U+00B7: "·" MIDDLE DOT
         // U+0142: "ł" LATIN SMALL LETTER L WITH STROKE
@@ -870,12 +870,12 @@
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         /* morekeys_c */ "\u010D,\u00E7,\u0107",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_lqm",
         // U+0148: "ň" LATIN SMALL LETTER N WITH CARON
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         /* morekeys_n */ "\u0148,\u00F1,\u0144",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         // U+0161: "š" LATIN SMALL LETTER S WITH CARON
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
@@ -930,11 +930,11 @@
         // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
         /* morekeys_i */ "\u00ED,\u00EF",
         /* morekeys_c */ null,
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_lqm",
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         /* morekeys_n */ "\u00F1,\u0144",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
         // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
@@ -1004,13 +1004,13 @@
         // U+00EB: "ë" LATIN SMALL LETTER E WITH DIAERESIS
         // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
         /* morekeys_e */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0117",
-        /* morekeys_i */ null,
-        /* morekeys_c */ null,
+        /* morekeys_i ~ */
+        null, null, null,
+        /* ~ keylabel_to_alpha */
         /* double_quotes */ "!text/double_9qm_lqm",
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         /* morekeys_n */ "\u00F1,\u0144",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
         // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
@@ -1043,8 +1043,8 @@
     /* Locale el: Greek */
     private static final String[] TEXTS_el = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+0391: "Α" GREEK CAPITAL LETTER ALPHA
         // U+0392: "Β" GREEK CAPITAL LETTER BETA
@@ -1092,10 +1092,10 @@
         /* morekeys_i */ "\u00ED,\u00EE,\u00EF,\u012B,\u00EC",
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
         /* morekeys_c */ "\u00E7",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ null,
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         /* morekeys_n */ "\u00F1",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ null,
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
         /* morekeys_s */ "\u00DF",
@@ -1161,6 +1161,7 @@
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
         // U+010B: "ċ" LATIN SMALL LETTER C WITH DOT ABOVE
         /* morekeys_c */ "\u0107,\u010D,\u00E7,\u010B",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ null,
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
@@ -1169,7 +1170,6 @@
         // U+0149: "ʼn" LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
         // U+014B: "ŋ" LATIN SMALL LETTER ENG
         /* morekeys_n */ "\u00F1,\u0144,\u0146,\u0148,\u0149,\u014B",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ null,
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
         // U+0161: "š" LATIN SMALL LETTER S WITH CARON
@@ -1297,15 +1297,15 @@
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         // U+010D: "č" LATIN SMALL LETTER C WITH CARON
         /* morekeys_c */ "\u00E7,\u0107,\u010D",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ null,
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         /* morekeys_n */ "\u00F1,\u0144",
-        /* keylabel_to_alpha ~ */
+        /* single_quotes ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null,
         /* ~ morekeys_nordic_row2_11 */
         // U+00A1: "¡" INVERTED EXCLAMATION MARK
         // U+00BF: "¿" INVERTED QUESTION MARK
@@ -1363,12 +1363,12 @@
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         /* morekeys_c */ "\u010D,\u00E7,\u0107",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_lqm",
         // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         /* morekeys_n */ "\u0146,\u00F1,\u0144",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         // U+0161: "š" LATIN SMALL LETTER S WITH CARON
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
@@ -1463,6 +1463,7 @@
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         // U+010D: "č" LATIN SMALL LETTER C WITH CARON
         /* morekeys_c */ "\u00E7,\u0107,\u010D",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ null,
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
@@ -1472,16 +1473,16 @@
     /* Locale fa: Persian */
     private static final String[] TEXTS_fa = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+0627: "ا" ARABIC LETTER ALEF
         // U+200C: ZERO WIDTH NON-JOINER
         // U+0628: "ب" ARABIC LETTER BEH
         // U+067E: "پ" ARABIC LETTER PEH
         /* keylabel_to_alpha */ "\u0627\u200C\u0628\u200C\u067E",
-        /* single_quotes ~ */
-        null, null, null, null, null, null, null,
+        /* double_quotes ~ */
+        null, null, null, null, null, null, null, null, null,
         /* ~ morekeys_l */
         // U+FDFC: "﷼" RIAL SIGN
         /* keyspec_currency */ "\uFDFC",
@@ -1710,7 +1711,7 @@
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         // U+010D: "č" LATIN SMALL LETTER C WITH CARON
         /* morekeys_c */ "\u00E7,%,\u0107,\u010D",
-        /* double_quotes ~ */
+        /* keylabel_to_alpha ~ */
         null, null, null, null, null,
         /* ~ morekeys_s */
         // U+00FF: "ÿ" LATIN SMALL LETTER Y WITH DIAERESIS
@@ -1782,6 +1783,7 @@
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         // U+010D: "č" LATIN SMALL LETTER C WITH CARON
         /* morekeys_c */ "\u00E7,\u0107,\u010D",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ null,
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
@@ -1791,15 +1793,15 @@
     /* Locale hi: Hindi */
     private static final String[] TEXTS_hi = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+0915: "क" DEVANAGARI LETTER KA
         // U+0916: "ख" DEVANAGARI LETTER KHA
         // U+0917: "ग" DEVANAGARI LETTER GA
         /* keylabel_to_alpha */ "\u0915\u0916\u0917",
-        /* single_quotes ~ */
-        null, null, null, null, null, null, null,
+        /* double_quotes ~ */
+        null, null, null, null, null, null, null, null, null,
         /* ~ morekeys_l */
         // U+20B9: "₹" INDIAN RUPEE SIGN
         /* keyspec_currency */ "\u20B9",
@@ -1849,11 +1851,11 @@
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
         /* morekeys_c */ "\u010D,\u0107,\u00E7",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_rqm",
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         /* morekeys_n */ "\u00F1,\u0144",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_rqm",
         // U+0161: "š" LATIN SMALL LETTER S WITH CARON
         // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
@@ -1917,9 +1919,9 @@
         // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
         /* morekeys_i */ "\u00ED,\u00EE,\u00EF,\u00EC,\u012F,\u012B",
         /* morekeys_c */ null,
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_rqm",
         /* morekeys_n */ null,
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_rqm",
         /* morekeys_s ~ */
         null, null, null, null, null, null, null, null,
@@ -1931,17 +1933,18 @@
     /* Locale hy_AM: Armenian (Armenia) */
     private static final String[] TEXTS_hy_AM = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+0531: "Ա" ARMENIAN CAPITAL LETTER AYB
         // U+0532: "Բ" ARMENIAN CAPITAL LETTER BEN
         // U+0533: "Գ" ARMENIAN CAPITAL LETTER GIM
         /* keylabel_to_alpha */ "\u0531\u0532\u0533",
-        /* single_quotes ~ */
+        /* double_quotes ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        null, null,
         /* ~ morekeys_nordic_row2_11 */
         // U+055E: "՞" ARMENIAN QUESTION MARK
         // U+055C: "՜" ARMENIAN EXCLAMATION MARK
@@ -2027,9 +2030,9 @@
         // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
         /* morekeys_i */ "\u00ED,\u00EF,\u00EE,\u00EC,\u012F,\u012B",
         /* morekeys_c */ null,
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_lqm",
         /* morekeys_n */ null,
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         /* morekeys_s */ null,
         // U+00FD: "ý" LATIN SMALL LETTER Y WITH ACUTE
@@ -2110,13 +2113,13 @@
         /* morekeys_a ~ */
         null, null, null, null, null, null,
         /* ~ morekeys_c */
-        /* double_quotes */ "!text/double_rqm_9qm",
-        /* morekeys_n */ null,
         // Label for "switch to alphabetic" key.
         // U+05D0: "א" HEBREW LETTER ALEF
         // U+05D1: "ב" HEBREW LETTER BET
         // U+05D2: "ג" HEBREW LETTER GIMEL
         /* keylabel_to_alpha */ "\u05D0\u05D1\u05D2",
+        /* double_quotes */ "!text/double_rqm_9qm",
+        /* morekeys_n */ null,
         /* single_quotes */ "!text/single_rqm_9qm",
         /* morekeys_s ~ */
         null, null, null, null, null, null,
@@ -2167,28 +2170,28 @@
         /* morekeys_a ~ */
         null, null, null, null, null, null,
         /* ~ morekeys_c */
-        /* double_quotes */ "!text/double_9qm_lqm",
-        /* morekeys_n */ null,
         // Label for "switch to alphabetic" key.
         // U+10D0: "ა" GEORGIAN LETTER AN
         // U+10D1: "ბ" GEORGIAN LETTER BAN
         // U+10D2: "გ" GEORGIAN LETTER GAN
         /* keylabel_to_alpha */ "\u10D0\u10D1\u10D2",
+        /* double_quotes */ "!text/double_9qm_lqm",
+        /* morekeys_n */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
     };
 
     /* Locale kk: Kazakh */
     private static final String[] TEXTS_kk = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
         /* keylabel_to_alpha */ "\u0410\u0411\u0412",
-        /* single_quotes ~ */
-        null, null, null, null, null, null, null, null, null, null, null, null, null,
+        /* double_quotes ~ */
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         /* ~ morekeys_k */
         // U+0451: "ё" CYRILLIC SMALL LETTER IO
         /* morekeys_cyrillic_ie */ "\u0451",
@@ -2237,14 +2240,14 @@
     /* Locale km_KH: Khmer (Cambodia) */
     private static final String[] TEXTS_km_KH = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+1780: "ក" KHMER LETTER KA
         // U+1781: "ខ" KHMER LETTER KHA
         // U+1782: "គ" KHMER LETTER KO
         /* keylabel_to_alpha */ "\u1780\u1781\u1782",
-        /* single_quotes ~ */
+        /* double_quotes ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
@@ -2252,7 +2255,7 @@
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
-        null, null, null, null, null, null, null,
+        null, null, null, null, null, null, null, null, null,
         /* ~ morekeys_cyrillic_a */
         // U+17DB: "៛" KHMER CURRENCY SYMBOL RIEL
         /* morekeys_currency_dollar */ "\u17DB,\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
@@ -2261,15 +2264,15 @@
     /* Locale ky: Kirghiz */
     private static final String[] TEXTS_ky = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
         /* keylabel_to_alpha */ "\u0410\u0411\u0412",
-        /* single_quotes ~ */
-        null, null, null, null, null, null, null, null, null, null, null, null, null,
+        /* double_quotes ~ */
+        null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         /* ~ morekeys_k */
         // U+0451: "ё" CYRILLIC SMALL LETTER IO
         /* morekeys_cyrillic_ie */ "\u0451",
@@ -2304,15 +2307,15 @@
     /* Locale lo_LA: Lao (Laos) */
     private static final String[] TEXTS_lo_LA = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+0E81: "ກ" LAO LETTER KO
         // U+0E82: "ຂ" LAO LETTER KHO SUNG
         // U+0E84: "ຄ" LAO LETTER KHO TAM
         /* keylabel_to_alpha */ "\u0E81\u0E82\u0E84",
-        /* single_quotes ~ */
-        null, null, null, null, null, null, null,
+        /* double_quotes ~ */
+        null, null, null, null, null, null, null, null, null,
         /* ~ morekeys_l */
         // U+20AD: "₭" KIP SIGN
         /* keyspec_currency */ "\u20AD",
@@ -2370,12 +2373,12 @@
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         /* morekeys_c */ "\u010D,\u00E7,\u0107",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_lqm",
         // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         /* morekeys_n */ "\u0146,\u00F1,\u0144",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         // U+0161: "š" LATIN SMALL LETTER S WITH CARON
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
@@ -2464,12 +2467,12 @@
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         /* morekeys_c */ "\u010D,\u00E7,\u0107",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_lqm",
         // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         /* morekeys_n */ "\u0146,\u00F1,\u0144",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         // U+0161: "š" LATIN SMALL LETTER S WITH CARON
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
@@ -2512,13 +2515,13 @@
         /* morekeys_a ~ */
         null, null, null, null, null, null,
         /* ~ morekeys_c */
-        /* double_quotes */ "!text/double_9qm_lqm",
-        /* morekeys_n */ null,
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
         /* keylabel_to_alpha */ "\u0410\u0411\u0412",
+        /* double_quotes */ "!text/double_9qm_lqm",
+        /* morekeys_n */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         /* morekeys_s ~ */
         null, null, null, null, null, null, null, null, null, null, null, null,
@@ -2547,15 +2550,15 @@
     /* Locale mn_MN: Mongolian (Mongolia) */
     private static final String[] TEXTS_mn_MN = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
         /* keylabel_to_alpha */ "\u0410\u0411\u0412",
-        /* single_quotes ~ */
-        null, null, null, null, null, null, null,
+        /* double_quotes ~ */
+        null, null, null, null, null, null, null, null, null,
         /* ~ morekeys_l */
         // U+20AE: "₮" TUGRIK SIGN
         /* keyspec_currency */ "\u20AE",
@@ -2564,15 +2567,15 @@
     /* Locale mr_IN: Marathi (India) */
     private static final String[] TEXTS_mr_IN = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+0915: "क" DEVANAGARI LETTER KA
         // U+0916: "ख" DEVANAGARI LETTER KHA
         // U+0917: "ग" DEVANAGARI LETTER GA
         /* keylabel_to_alpha */ "\u0915\u0916\u0917",
-        /* single_quotes ~ */
-        null, null, null, null, null, null, null,
+        /* double_quotes ~ */
+        null, null, null, null, null, null, null, null, null,
         /* ~ morekeys_l */
         // U+20B9: "₹" INDIAN RUPEE SIGN
         /* keyspec_currency */ "\u20B9",
@@ -2616,17 +2619,18 @@
     /* Locale my_MM: Burmese (Myanmar) */
     private static final String[] TEXTS_my_MM = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+1000: "က" MYANMAR LETTER KA
         // U+1001: "ခ" MYANMAR LETTER KHA
         // U+1002: "ဂ" MYANMAR LETTER GA
         /* keylabel_to_alpha */ "\u1000\u1001\u1002",
-        /* single_quotes ~ */
+        /* double_quotes ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
         null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+        null, null,
         /* ~ morekeys_nordic_row2_11 */
         /* morekeys_punctuation */ "!autoColumnOrder!9,\u104A,.,?,!,#,),(,/,;,...,',@,:,-,\",+,\\%,&",
         // U+104A: "၊" MYANMAR SIGN LITTLE SECTION
@@ -2681,11 +2685,11 @@
         // U+0117: "ė" LATIN SMALL LETTER E WITH DOT ABOVE
         // U+0113: "ē" LATIN SMALL LETTER E WITH MACRON
         /* morekeys_e */ "\u00E9,\u00E8,\u00EA,\u00EB,\u0119,\u0117,\u0113",
-        /* morekeys_i */ null,
-        /* morekeys_c */ null,
+        /* morekeys_i ~ */
+        null, null, null,
+        /* ~ keylabel_to_alpha */
         /* double_quotes */ "!text/double_9qm_rqm",
         /* morekeys_n */ null,
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_rqm",
         /* morekeys_s ~ */
         null, null, null, null, null, null, null, null, null, null, null, null, null,
@@ -2709,15 +2713,15 @@
     /* Locale ne_NP: Nepali (Nepal) */
     private static final String[] TEXTS_ne_NP = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+0915: "क" DEVANAGARI LETTER KA
         // U+0916: "ख" DEVANAGARI LETTER KHA
         // U+0917: "ग" DEVANAGARI LETTER GA
         /* keylabel_to_alpha */ "\u0915\u0916\u0917",
-        /* single_quotes ~ */
-        null, null, null, null, null, null, null,
+        /* double_quotes ~ */
+        null, null, null, null, null, null, null, null, null,
         /* ~ morekeys_l */
         // U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN
         /* keyspec_currency */ "\u0930\u0941.",
@@ -2801,11 +2805,11 @@
         // U+0133: "ij" LATIN SMALL LIGATURE IJ
         /* morekeys_i */ "\u00ED,\u00EF,\u00EC,\u00EE,\u012F,\u012B,\u0133",
         /* morekeys_c */ null,
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_rqm",
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         /* morekeys_n */ "\u00F1,\u0144",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_rqm",
         /* morekeys_s */ null,
         // U+0133: "ij" LATIN SMALL LIGATURE IJ
@@ -2847,11 +2851,11 @@
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
         // U+010D: "č" LATIN SMALL LETTER C WITH CARON
         /* morekeys_c */ "\u0107,\u00E7,\u010D",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_rqm",
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         /* morekeys_n */ "\u0144,\u00F1",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_rqm",
         // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
@@ -2952,9 +2956,9 @@
         // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
         /* morekeys_i */ "\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
         /* morekeys_c */ null,
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_rqm",
         /* morekeys_n */ null,
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_rqm",
         // U+0219: "ș" LATIN SMALL LETTER S WITH COMMA BELOW
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
@@ -2973,13 +2977,13 @@
         /* morekeys_a ~ */
         null, null, null, null, null, null,
         /* ~ morekeys_c */
-        /* double_quotes */ "!text/double_9qm_lqm",
-        /* morekeys_n */ null,
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
         /* keylabel_to_alpha */ "\u0410\u0411\u0412",
+        /* double_quotes */ "!text/double_9qm_lqm",
+        /* morekeys_n */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         /* morekeys_s ~ */
         null, null, null, null, null, null, null, null, null, null, null, null,
@@ -3001,6 +3005,17 @@
         /* morekeys_cyrillic_soft_sign */ "\u044A",
     };
 
+    /* Locale si_LK: Sinhalese (Sri Lanka) */
+    private static final String[] TEXTS_si_LK = {
+        /* morekeys_a ~ */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
+        // Label for "switch to alphabetic" key.
+        // U+0D85: "අ" SINHALA LETTER AYANNA
+        // U+0D86: "ආ" SINHALA LETTER AAYANNA
+        /* keylabel_to_alpha */ "\u0D85,\u0D86",
+    };
+
     /* Locale sk: Slovak */
     private static final String[] TEXTS_sk = {
         // U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
@@ -3052,13 +3067,13 @@
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         /* morekeys_c */ "\u010D,\u00E7,\u0107",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_lqm",
         // U+0148: "ň" LATIN SMALL LETTER N WITH CARON
         // U+0146: "ņ" LATIN SMALL LETTER N WITH CEDILLA
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         /* morekeys_n */ "\u0148,\u0146,\u00F1,\u0144",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         // U+0161: "š" LATIN SMALL LETTER S WITH CARON
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
@@ -3104,9 +3119,9 @@
         // U+010D: "č" LATIN SMALL LETTER C WITH CARON
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         /* morekeys_c */ "\u010D,\u0107",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ "!text/double_9qm_lqm",
         /* morekeys_n */ null,
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         // U+0161: "š" LATIN SMALL LETTER S WITH CARON
         /* morekeys_s */ "\u0161",
@@ -3127,14 +3142,14 @@
         /* morekeys_a ~ */
         null, null, null, null, null, null,
         /* ~ morekeys_c */
-        /* double_quotes */ "!text/double_9qm_lqm",
-        /* morekeys_n */ null,
         // END: More keys definitions for Serbian (Cyrillic)
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
         /* keylabel_to_alpha */ "\u0410\u0411\u0412",
+        /* double_quotes */ "!text/double_9qm_lqm",
+        /* morekeys_n */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         /* morekeys_s ~ */
         null, null, null, null, null, null, null, null,
@@ -3217,12 +3232,12 @@
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         // U+010D: "č" LATIN SMALL LETTER C WITH CARON
         /* morekeys_c */ "\u00E7,\u0107,\u010D",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ null,
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0148: "ň" LATIN SMALL LETTER N WITH CARON
         /* morekeys_n */ "\u0144,\u00F1,\u0148",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ null,
         // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
         // U+0161: "š" LATIN SMALL LETTER S WITH CARON
@@ -3310,10 +3325,10 @@
         /* morekeys_i */ "\u00EE,\u00EF,\u00ED,\u012B,\u00EC",
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
         /* morekeys_c */ "\u00E7",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ null,
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         /* morekeys_n */ "\u00F1",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ null,
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
         /* morekeys_s */ "\u00DF",
@@ -3326,15 +3341,15 @@
     /* Locale th: Thai */
     private static final String[] TEXTS_th = {
         /* morekeys_a ~ */
-        null, null, null, null, null, null, null, null,
-        /* ~ morekeys_n */
+        null, null, null, null, null, null,
+        /* ~ morekeys_c */
         // Label for "switch to alphabetic" key.
         // U+0E01: "ก" THAI CHARACTER KO KAI
         // U+0E02: "ข" THAI CHARACTER KHO KHAI
         // U+0E04: "ค" THAI CHARACTER KHO KHWAI
         /* keylabel_to_alpha */ "\u0E01\u0E02\u0E04",
-        /* single_quotes ~ */
-        null, null, null, null, null, null, null,
+        /* double_quotes ~ */
+        null, null, null, null, null, null, null, null, null,
         /* ~ morekeys_l */
         // U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT
         /* keyspec_currency */ "\u0E3F",
@@ -3388,6 +3403,7 @@
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         // U+010D: "č" LATIN SMALL LETTER C WITH CARON
         /* morekeys_c */ "\u00E7,\u0107,\u010D",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ null,
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
@@ -3426,7 +3442,7 @@
         // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
         // U+010D: "č" LATIN SMALL LETTER C WITH CARON
         /* morekeys_c */ "\u00E7,\u0107,\u010D",
-        /* double_quotes ~ */
+        /* keylabel_to_alpha ~ */
         null, null, null, null,
         /* ~ single_quotes */
         // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
@@ -3446,13 +3462,13 @@
         /* morekeys_a ~ */
         null, null, null, null, null, null,
         /* ~ morekeys_c */
-        /* double_quotes */ "!text/double_9qm_lqm",
-        /* morekeys_n */ null,
         // Label for "switch to alphabetic" key.
         // U+0410: "А" CYRILLIC CAPITAL LETTER A
         // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
         // U+0412: "В" CYRILLIC CAPITAL LETTER VE
         /* keylabel_to_alpha */ "\u0410\u0411\u0412",
+        /* double_quotes */ "!text/double_9qm_lqm",
+        /* morekeys_n */ null,
         /* single_quotes */ "!text/single_9qm_lqm",
         /* morekeys_s ~ */
         null, null, null, null, null, null,
@@ -3613,10 +3629,10 @@
         /* morekeys_i */ "\u00ED,\u00EE,\u00EF,\u012B,\u00EC",
         // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
         /* morekeys_c */ "\u00E7",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ null,
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         /* morekeys_n */ "\u00F1",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ null,
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
         /* morekeys_s */ "\u00DF",
@@ -3686,6 +3702,7 @@
         // U+010B: "ċ" LATIN SMALL LETTER C WITH DOT ABOVE
         // U+010D: "č" LATIN SMALL LETTER C WITH CARON
         /* morekeys_c */ "\u00E7,\u0107,\u0109,\u010B,\u010D",
+        /* keylabel_to_alpha */ null,
         /* double_quotes */ null,
         // U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
         // U+0144: "ń" LATIN SMALL LETTER N WITH ACUTE
@@ -3694,7 +3711,6 @@
         // U+0149: "ʼn" LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
         // U+014B: "ŋ" LATIN SMALL LETTER ENG
         /* morekeys_n */ "\u00F1,\u0144,\u0146,\u0148,\u0149,\u014B",
-        /* keylabel_to_alpha */ null,
         /* single_quotes */ null,
         // U+00DF: "ß" LATIN SMALL LETTER SHARP S
         // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
@@ -3767,21 +3783,21 @@
         "ar"     , TEXTS_ar,    /*  55/110 Arabic */
         "az_AZ"  , TEXTS_az_AZ, /*   8/ 18 Azerbaijani (Azerbaijan) */
         "be_BY"  , TEXTS_be_BY, /*   9/ 32 Belarusian (Belarus) */
-        "bg"     , TEXTS_bg,    /*   2/  9 Bulgarian */
+        "bg"     , TEXTS_bg,    /*   2/  8 Bulgarian */
         "ca"     , TEXTS_ca,    /*  11/ 95 Catalan */
         "cs"     , TEXTS_cs,    /*  17/ 21 Czech */
         "da"     , TEXTS_da,    /*  19/ 54 Danish */
         "de"     , TEXTS_de,    /*  16/ 62 German */
-        "el"     , TEXTS_el,    /*   1/  9 Greek */
+        "el"     , TEXTS_el,    /*   1/  7 Greek */
         "en"     , TEXTS_en,    /*   8/ 11 English */
         "eo"     , TEXTS_eo,    /*  26/118 Esperanto */
         "es"     , TEXTS_es,    /*   8/ 55 Spanish */
         "et_EE"  , TEXTS_et_EE, /*  22/ 27 Estonian (Estonia) */
-        "eu_ES"  , TEXTS_eu_ES, /*   7/  8 Basque (Spain) */
+        "eu_ES"  , TEXTS_eu_ES, /*   7/  9 Basque (Spain) */
         "fa"     , TEXTS_fa,    /*  58/125 Persian */
         "fi"     , TEXTS_fi,    /*  10/ 54 Finnish */
         "fr"     , TEXTS_fr,    /*  13/ 62 French */
-        "gl_ES"  , TEXTS_gl_ES, /*   7/  8 Gallegan (Spain) */
+        "gl_ES"  , TEXTS_gl_ES, /*   7/  9 Gallegan (Spain) */
         "hi"     , TEXTS_hi,    /*  23/ 53 Hindi */
         "hr"     , TEXTS_hr,    /*   9/ 20 Croatian */
         "hu"     , TEXTS_hu,    /*   9/ 20 Hungarian */
@@ -3808,13 +3824,14 @@
         "rm"     , TEXTS_rm,    /*   1/  2 Raeto-Romance */
         "ro"     , TEXTS_ro,    /*   6/ 15 Romanian */
         "ru"     , TEXTS_ru,    /*   9/ 32 Russian */
+        "si_LK"  , TEXTS_si_LK, /*   1/  7 Sinhalese (Sri Lanka) */
         "sk"     , TEXTS_sk,    /*  20/ 22 Slovak */
         "sl"     , TEXTS_sl,    /*   8/ 20 Slovenian */
         "sr"     , TEXTS_sr,    /*  11/ 93 Serbian */
         "sv"     , TEXTS_sv,    /*  21/ 54 Swedish */
         "sw"     , TEXTS_sw,    /*   9/ 18 Swahili */
         "th"     , TEXTS_th,    /*   2/ 17 Thai */
-        "tl"     , TEXTS_tl,    /*   7/  8 Tagalog */
+        "tl"     , TEXTS_tl,    /*   7/  9 Tagalog */
         "tr"     , TEXTS_tr,    /*   7/ 18 Turkish */
         "uk"     , TEXTS_uk,    /*  11/ 87 Ukrainian */
         "vi"     , TEXTS_vi,    /*   8/ 17 Vietnamese */
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index b4e115c..43af66e 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -220,6 +220,7 @@
 
     public static final String REGEXP_PERIOD = "\\.";
     public static final String STRING_SPACE = " ";
+    public static final String STRING_PERIOD_AND_SPACE = ". ";
 
     /**
      * Special keys code. Must be negative.
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index a8f9efb..6e5e0de 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1001,6 +1001,9 @@
         if (!mSettings.getCurrent().isApplicationSpecifiedCompletionsOn()) {
             return;
         }
+        // If we have an update request in flight, we need to cancel it so it does not override
+        // these completions.
+        mHandler.cancelUpdateSuggestionStrip();
         if (applicationSpecifiedCompletions == null) {
             setNeutralSuggestionStrip();
             return;
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index bcaaa16..0afaaef 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -679,13 +679,12 @@
         // Here we test whether we indeed have a period and a space before us. This should not
         // be needed, but it's there just in case something went wrong.
         final CharSequence textBeforeCursor = getTextBeforeCursor(2, 0);
-        final String periodSpace = ". ";
-        if (!TextUtils.equals(periodSpace, textBeforeCursor)) {
+        if (!TextUtils.equals(Constants.STRING_PERIOD_AND_SPACE, textBeforeCursor)) {
             // Theoretically we should not be coming here if there isn't ". " before the
             // cursor, but the application may be changing the text while we are typing, so
             // anything goes. We should not crash.
             Log.d(TAG, "Tried to revert double-space combo but we didn't find "
-                    + "\"" + periodSpace + "\" just before the cursor.");
+                    + "\"" + Constants.STRING_PERIOD_AND_SPACE + "\" just before the cursor.");
             return false;
         }
         // Double-space results in ". ". A backspace to cancel this should result in a single
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 9d03e8a..e43db35 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -123,39 +123,27 @@
                 suggestionsContainer.set(i, transformedWordInfo);
             }
         }
-        SuggestedWordInfo.removeDups(typedWord, suggestionsContainer);
+        final boolean didRemoveTypedWord =
+                SuggestedWordInfo.removeDups(typedWord, suggestionsContainer);
 
-        // If resumed, then we don't want to upcase everything: resuming on a fully-capitalized
-        // words is rarely done to switch to another fully-capitalized word, but usually to a
-        // normal, non-capitalized suggestion.
-        final String firstSuggestion;
+        final SuggestedWordInfo firstSuggestedWordInfo;
         final String whitelistedWord;
-        if (suggestionResults.isEmpty()) {
-            whitelistedWord = firstSuggestion = null;
+        if (suggestionsContainer.isEmpty()) {
+            firstSuggestedWordInfo = null;
+            whitelistedWord = null;
         } else {
-            final SuggestedWordInfo firstSuggestedWordInfo = getTransformedSuggestedWordInfo(
-                    suggestionResults.first(), suggestionResults.mLocale,
-                    shouldMakeSuggestionsAllUpperCase, isOnlyFirstCharCapitalized,
-                    trailingSingleQuotesCount);
-            firstSuggestion = firstSuggestedWordInfo.mWord;
+            firstSuggestedWordInfo = suggestionsContainer.get(0);
             if (!firstSuggestedWordInfo.isKindOf(SuggestedWordInfo.KIND_WHITELIST)) {
                 whitelistedWord = null;
             } else {
-                whitelistedWord = firstSuggestion;
+                whitelistedWord = firstSuggestedWordInfo.mWord;
             }
         }
 
-        // We allow auto-correction if we have a whitelisted word, or if the word is not a valid
-        // word of more than 1 char, except if the first suggestion is the same as the typed string
-        // because in this case if it's strong enough to auto-correct that will mistakenly designate
-        // the second candidate for auto-correction.
-        // TODO: stop relying on indices to find where is the auto-correction in the suggested
-        // words, and correct this test.
-        final boolean allowsToBeAutoCorrected = (null != whitelistedWord
-                && !whitelistedWord.equals(typedWord))
-                || (consideredWord.length() > 1 && !mDictionaryFacilitator.isValidWord(
-                        consideredWord, isOnlyFirstCharCapitalized)
-                        && !typedWord.equals(firstSuggestion));
+        // We allow auto-correction if we have a whitelisted word, or if the word had more than
+        // one char and was not suggested.
+        final boolean allowsToBeAutoCorrected = (null != whitelistedWord)
+                || (consideredWord.length() > 1 && !didRemoveTypedWord);
 
         final boolean hasAutoCorrection;
         // TODO: using isCorrectionEnabled here is not very good. It's probably useless, because
@@ -164,10 +152,10 @@
         // the current settings. It may also be useful to know, when the setting is off, whether
         // the word *would* have been auto-corrected.
         if (!isCorrectionEnabled || !allowsToBeAutoCorrected || isPrediction
-                || suggestionResults.isEmpty() || wordComposer.hasDigits()
+                || null == firstSuggestedWordInfo || wordComposer.hasDigits()
                 || wordComposer.isMostlyCaps() || wordComposer.isResumed()
                 || !mDictionaryFacilitator.hasInitializedMainDictionary()
-                || suggestionResults.first().isKindOf(SuggestedWordInfo.KIND_SHORTCUT)) {
+                || firstSuggestedWordInfo.isKindOf(SuggestedWordInfo.KIND_SHORTCUT)) {
             // If we don't have a main dictionary, we never want to auto-correct. The reason for
             // this is, the user may have a contact whose name happens to match a valid word in
             // their language, and it will unexpectedly auto-correct. For example, if the user
@@ -179,7 +167,7 @@
             hasAutoCorrection = false;
         } else {
             hasAutoCorrection = AutoCorrectionUtils.suggestionExceedsAutoCorrectionThreshold(
-                    suggestionResults.first(), consideredWord, mAutoCorrectionThreshold);
+                    firstSuggestedWordInfo, consideredWord, mAutoCorrectionThreshold);
         }
 
         if (!TextUtils.isEmpty(typedWord)) {
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index f22af79..e587b18 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -330,29 +330,37 @@
         }
 
         // This will always remove the higher index if a duplicate is found.
-        public static void removeDups(final String typedWord,
+        public static boolean removeDups(final String typedWord,
                 ArrayList<SuggestedWordInfo> candidates) {
             if (candidates.isEmpty()) {
-                return;
+                return false;
             }
+            final boolean didRemoveTypedWord;
             if (!TextUtils.isEmpty(typedWord)) {
-                removeSuggestedWordInfoFrom(typedWord, candidates, -1 /* startIndexExclusive */);
+                didRemoveTypedWord = removeSuggestedWordInfoFrom(typedWord, candidates,
+                        -1 /* startIndexExclusive */);
+            } else {
+                didRemoveTypedWord = false;
             }
             for (int i = 0; i < candidates.size(); ++i) {
                 removeSuggestedWordInfoFrom(candidates.get(i).mWord, candidates,
                         i /* startIndexExclusive */);
             }
+            return didRemoveTypedWord;
         }
 
-        private static void removeSuggestedWordInfoFrom(final String word,
+        private static boolean removeSuggestedWordInfoFrom(final String word,
                 final ArrayList<SuggestedWordInfo> candidates, final int startIndexExclusive) {
+            boolean didRemove = false;
             for (int i = startIndexExclusive + 1; i < candidates.size(); ++i) {
                 final SuggestedWordInfo previous = candidates.get(i);
                 if (word.equals(previous.mWord)) {
+                    didRemove = true;
                     candidates.remove(i);
                     --i;
                 }
             }
+            return didRemove;
         }
     }
 
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 4ebdcbd..15ddcf9 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -399,7 +399,7 @@
         }
 
         boolean didAutoCorrect = false;
-        if (Event.NOT_A_KEY_CODE != event.mKeyCode) {
+        if (event.isFunctionalKeyEvent()) {
             // A special key, like delete, shift, emoji, or the settings key.
             switch (event.mKeyCode) {
             case Constants.CODE_DELETE:
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 8d49564..d031624 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -37,6 +37,7 @@
 import com.android.inputmethod.latin.utils.BinaryDictionaryUtils;
 import com.android.inputmethod.latin.utils.CollectionUtils;
 import com.android.inputmethod.latin.utils.LocaleUtils;
+import com.android.inputmethod.latin.utils.ScriptUtils;
 import com.android.inputmethod.latin.utils.StringUtils;
 
 import java.lang.ref.WeakReference;
@@ -78,40 +79,8 @@
     private final HashSet<WeakReference<DictionaryCollection>> mDictionaryCollectionsList =
             new HashSet<>();
 
-    public static final int SCRIPT_LATIN = 0;
-    public static final int SCRIPT_CYRILLIC = 1;
-    public static final int SCRIPT_GREEK = 2;
     public static final String SINGLE_QUOTE = "\u0027";
     public static final String APOSTROPHE = "\u2019";
-    private static final TreeMap<String, Integer> mLanguageToScript;
-    static {
-        // List of the supported languages and their associated script. We won't check
-        // words written in another script than the selected script, because we know we
-        // don't have those in our dictionary so we will underline everything and we
-        // will never have any suggestions, so it makes no sense checking them, and this
-        // is done in {@link #shouldFilterOut}. Also, the script is used to choose which
-        // proximity to pass to the dictionary descent algorithm.
-        // IMPORTANT: this only contains languages - do not write countries in there.
-        // Only the language is searched from the map.
-        mLanguageToScript = new TreeMap<>();
-        mLanguageToScript.put("cs", SCRIPT_LATIN);
-        mLanguageToScript.put("da", SCRIPT_LATIN);
-        mLanguageToScript.put("de", SCRIPT_LATIN);
-        mLanguageToScript.put("el", SCRIPT_GREEK);
-        mLanguageToScript.put("en", SCRIPT_LATIN);
-        mLanguageToScript.put("es", SCRIPT_LATIN);
-        mLanguageToScript.put("fi", SCRIPT_LATIN);
-        mLanguageToScript.put("fr", SCRIPT_LATIN);
-        mLanguageToScript.put("hr", SCRIPT_LATIN);
-        mLanguageToScript.put("it", SCRIPT_LATIN);
-        mLanguageToScript.put("lt", SCRIPT_LATIN);
-        mLanguageToScript.put("lv", SCRIPT_LATIN);
-        mLanguageToScript.put("nb", SCRIPT_LATIN);
-        mLanguageToScript.put("nl", SCRIPT_LATIN);
-        mLanguageToScript.put("pt", SCRIPT_LATIN);
-        mLanguageToScript.put("sl", SCRIPT_LATIN);
-        mLanguageToScript.put("ru", SCRIPT_CYRILLIC);
-    }
 
     @Override public void onCreate() {
         super.onCreate();
@@ -122,22 +91,13 @@
         onSharedPreferenceChanged(prefs, PREF_USE_CONTACTS_KEY);
     }
 
-    public static int getScriptFromLocale(final Locale locale) {
-        final Integer script = mLanguageToScript.get(locale.getLanguage());
-        if (null == script) {
-            throw new RuntimeException("We have been called with an unsupported language: \""
-                    + locale.getLanguage() + "\". Framework bug?");
-        }
-        return script;
-    }
-
     private static String getKeyboardLayoutNameForScript(final int script) {
         switch (script) {
-        case AndroidSpellCheckerService.SCRIPT_LATIN:
+        case ScriptUtils.SCRIPT_LATIN:
             return "qwerty";
-        case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
+        case ScriptUtils.SCRIPT_CYRILLIC:
             return "east_slavic";
-        case AndroidSpellCheckerService.SCRIPT_GREEK:
+        case ScriptUtils.SCRIPT_GREEK:
             return "greek";
         default:
             throw new RuntimeException("Wrong script supplied: " + script);
@@ -413,7 +373,7 @@
     }
 
     public DictAndKeyboard createDictAndKeyboard(final Locale locale) {
-        final int script = getScriptFromLocale(locale);
+        final int script = ScriptUtils.getScriptFromLocale(locale);
         final String keyboardLayoutName = getKeyboardLayoutNameForScript(script);
         final InputMethodSubtype subtype = AdditionalSubtypeUtils.createAdditionalSubtype(
                 locale.toString(), keyboardLayoutName, null);
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
index e9d5a7a..be33f33 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java
@@ -36,6 +36,7 @@
 import com.android.inputmethod.latin.spellcheck.AndroidSpellCheckerService.SuggestionsGatherer;
 import com.android.inputmethod.latin.utils.CoordinateUtils;
 import com.android.inputmethod.latin.utils.LocaleUtils;
+import com.android.inputmethod.latin.utils.ScriptUtils;
 import com.android.inputmethod.latin.utils.StringUtils;
 
 import java.util.ArrayList;
@@ -116,7 +117,7 @@
         final String localeString = getLocale();
         mDictionaryPool = mService.getDictionaryPool(localeString);
         mLocale = LocaleUtils.constructLocaleFromString(localeString);
-        mScript = AndroidSpellCheckerService.getScriptFromLocale(mLocale);
+        mScript = ScriptUtils.getScriptFromLocale(mLocale);
     }
 
     @Override
@@ -125,44 +126,6 @@
         cres.unregisterContentObserver(mObserver);
     }
 
-    /*
-     * Returns whether the code point is a letter that makes sense for the specified
-     * locale for this spell checker.
-     * The dictionaries supported by Latin IME are described in res/xml/spellchecker.xml
-     * and is limited to EFIGS languages and Russian.
-     * Hence at the moment this explicitly tests for Cyrillic characters or Latin characters
-     * as appropriate, and explicitly excludes CJK, Arabic and Hebrew characters.
-     */
-    private static boolean isLetterCheckableByLanguage(final int codePoint,
-            final int script) {
-        switch (script) {
-        case AndroidSpellCheckerService.SCRIPT_LATIN:
-            // Our supported latin script dictionaries (EFIGS) at the moment only include
-            // characters in the C0, C1, Latin Extended A and B, IPA extensions unicode
-            // blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF,
-            // so the below is a very efficient way to test for it. As for the 0-0x3F, it's
-            // excluded from isLetter anyway.
-            return codePoint <= 0x2AF && Character.isLetter(codePoint);
-        case AndroidSpellCheckerService.SCRIPT_CYRILLIC:
-            // All Cyrillic characters are in the 400~52F block. There are some in the upper
-            // Unicode range, but they are archaic characters that are not used in modern
-            // Russian and are not used by our dictionary.
-            return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint);
-        case AndroidSpellCheckerService.SCRIPT_GREEK:
-            // Greek letters are either in the 370~3FF range (Greek & Coptic), or in the
-            // 1F00~1FFF range (Greek extended). Our dictionary contains both sort of characters.
-            // Our dictionary also contains a few words with 0xF2; it would be best to check
-            // if that's correct, but a web search does return results for these words so
-            // they are probably okay.
-            return (codePoint >= 0x370 && codePoint <= 0x3FF)
-                    || (codePoint >= 0x1F00 && codePoint <= 0x1FFF)
-                    || codePoint == 0xF2;
-        default:
-            // Should never come here
-            throw new RuntimeException("Impossible value of script: " + script);
-        }
-    }
-
     private static final int CHECKABILITY_CHECKABLE = 0;
     private static final int CHECKABILITY_TOO_MANY_NON_LETTERS = 1;
     private static final int CHECKABILITY_CONTAINS_PERIOD = 2;
@@ -189,7 +152,7 @@
         // Filter by first letter
         final int firstCodePoint = text.codePointAt(0);
         // Filter out words that don't start with a letter or an apostrophe
-        if (!isLetterCheckableByLanguage(firstCodePoint, script)
+        if (!ScriptUtils.isLetterCheckableByScript(firstCodePoint, script)
                 && '\'' != firstCodePoint) return CHECKABILITY_FIRST_LETTER_UNCHECKABLE;
 
         // Filter contents
@@ -210,7 +173,7 @@
             if (Constants.CODE_PERIOD == codePoint) {
                 return CHECKABILITY_CONTAINS_PERIOD;
             }
-            if (isLetterCheckableByLanguage(codePoint, script)) ++letterCount;
+            if (ScriptUtils.isLetterCheckableByScript(codePoint, script)) ++letterCount;
         }
         // Guestimate heuristic: perform spell checking if at least 3/4 of the characters
         // in this word are letters
@@ -295,7 +258,9 @@
                             return new SuggestionsInfo(SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO
                                     | SuggestionsInfo.RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS,
                                     new String[] {
-                                            TextUtils.join(Constants.STRING_SPACE, splitText) });
+                                            TextUtils.join(Constants.STRING_SPACE, splitText),
+                                            TextUtils.join(Constants.STRING_PERIOD_AND_SPACE,
+                                                    splitText) });
                         }
                     }
                     return dictInfo.mDictionary.isValidWord(inText)
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
index 528d500..47921ca 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestionsView.java
@@ -20,8 +20,6 @@
 import android.util.AttributeSet;
 import android.util.Log;
 
-import com.android.inputmethod.accessibility.AccessibilityUtils;
-import com.android.inputmethod.accessibility.MoreSuggestionsAccessibilityDelegate;
 import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardActionListener;
@@ -51,6 +49,7 @@
         super(context, attrs, defStyle);
     }
 
+    // TODO: Remove redundant override method.
     @Override
     public void setKeyboard(final Keyboard keyboard) {
         super.setKeyboard(keyboard);
@@ -58,16 +57,10 @@
         // above {@link MoreKeysKeyboardView#setKeyboard(Keyboard)} call.
         // With accessibility mode on, {@link #mAccessibilityDelegate} is set to a
         // {@link MoreKeysKeyboardAccessibilityDelegate} object at the above
-        // {@link MoreKeysKeyboardView#setKeyboard(Keyboard)} call. And the object has to be
-        // overwritten by a {@link MoreSuggestionsAccessibilityDelegate} object here.
-        if (AccessibilityUtils.getInstance().isAccessibilityEnabled()) {
-            if (!(mAccessibilityDelegate instanceof MoreSuggestionsAccessibilityDelegate)) {
-                mAccessibilityDelegate = new MoreSuggestionsAccessibilityDelegate(
-                        this, mKeyDetector);
-                mAccessibilityDelegate.setOpenAnnounce(R.string.spoken_open_more_suggestions);
-                mAccessibilityDelegate.setCloseAnnounce(R.string.spoken_close_more_suggestions);
-            }
-            mAccessibilityDelegate.setKeyboard(keyboard);
+        // {@link MoreKeysKeyboardView#setKeyboard(Keyboard)} call.
+        if (mAccessibilityDelegate != null) {
+            mAccessibilityDelegate.setOpenAnnounce(R.string.spoken_open_more_suggestions);
+            mAccessibilityDelegate.setCloseAnnounce(R.string.spoken_close_more_suggestions);
         }
     }
 
diff --git a/java/src/com/android/inputmethod/latin/utils/ScriptUtils.java b/java/src/com/android/inputmethod/latin/utils/ScriptUtils.java
new file mode 100644
index 0000000..4dfb38d
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/ScriptUtils.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.utils;
+
+import java.util.Locale;
+import java.util.TreeMap;
+
+/**
+ * A class to help with handling different writing scripts.
+ */
+public class ScriptUtils {
+    public static final int SCRIPT_LATIN = 0;
+    public static final int SCRIPT_CYRILLIC = 1;
+    public static final int SCRIPT_GREEK = 2;
+    public static final TreeMap<String, Integer> mLanguageToScript;
+    static {
+        // List of the supported languages and their associated script. We won't check
+        // words written in another script than the selected script, because we know we
+        // don't have those in our dictionary so we will underline everything and we
+        // will never have any suggestions, so it makes no sense checking them, and this
+        // is done in {@link #shouldFilterOut}. Also, the script is used to choose which
+        // proximity to pass to the dictionary descent algorithm.
+        // IMPORTANT: this only contains languages - do not write countries in there.
+        // Only the language is searched from the map.
+        mLanguageToScript = new TreeMap<>();
+        mLanguageToScript.put("cs", SCRIPT_LATIN);
+        mLanguageToScript.put("da", SCRIPT_LATIN);
+        mLanguageToScript.put("de", SCRIPT_LATIN);
+        mLanguageToScript.put("el", SCRIPT_GREEK);
+        mLanguageToScript.put("en", SCRIPT_LATIN);
+        mLanguageToScript.put("es", SCRIPT_LATIN);
+        mLanguageToScript.put("fi", SCRIPT_LATIN);
+        mLanguageToScript.put("fr", SCRIPT_LATIN);
+        mLanguageToScript.put("hr", SCRIPT_LATIN);
+        mLanguageToScript.put("it", SCRIPT_LATIN);
+        mLanguageToScript.put("lt", SCRIPT_LATIN);
+        mLanguageToScript.put("lv", SCRIPT_LATIN);
+        mLanguageToScript.put("nb", SCRIPT_LATIN);
+        mLanguageToScript.put("nl", SCRIPT_LATIN);
+        mLanguageToScript.put("pt", SCRIPT_LATIN);
+        mLanguageToScript.put("sl", SCRIPT_LATIN);
+        mLanguageToScript.put("ru", SCRIPT_CYRILLIC);
+    }
+    /*
+     * Returns whether the code point is a letter that makes sense for the specified
+     * locale for this spell checker.
+     * The dictionaries supported by Latin IME are described in res/xml/spellchecker.xml
+     * and is limited to EFIGS languages and Russian.
+     * Hence at the moment this explicitly tests for Cyrillic characters or Latin characters
+     * as appropriate, and explicitly excludes CJK, Arabic and Hebrew characters.
+     */
+    public static boolean isLetterCheckableByScript(final int codePoint, final int script) {
+        switch (script) {
+        case SCRIPT_LATIN:
+            // Our supported latin script dictionaries (EFIGS) at the moment only include
+            // characters in the C0, C1, Latin Extended A and B, IPA extensions unicode
+            // blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF,
+            // so the below is a very efficient way to test for it. As for the 0-0x3F, it's
+            // excluded from isLetter anyway.
+            return codePoint <= 0x2AF && Character.isLetter(codePoint);
+        case SCRIPT_CYRILLIC:
+            // All Cyrillic characters are in the 400~52F block. There are some in the upper
+            // Unicode range, but they are archaic characters that are not used in modern
+            // Russian and are not used by our dictionary.
+            return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint);
+        case SCRIPT_GREEK:
+            // Greek letters are either in the 370~3FF range (Greek & Coptic), or in the
+            // 1F00~1FFF range (Greek extended). Our dictionary contains both sort of characters.
+            // Our dictionary also contains a few words with 0xF2; it would be best to check
+            // if that's correct, but a web search does return results for these words so
+            // they are probably okay.
+            return (codePoint >= 0x370 && codePoint <= 0x3FF)
+                    || (codePoint >= 0x1F00 && codePoint <= 0x1FFF)
+                    || codePoint == 0xF2;
+        default:
+            // Should never come here
+            throw new RuntimeException("Impossible value of script: " + script);
+        }
+    }
+
+    public static int getScriptFromLocale(final Locale locale) {
+        final Integer script = mLanguageToScript.get(locale.getLanguage());
+        if (null == script) {
+            throw new RuntimeException("We have been called with an unsupported language: \""
+                    + locale.getLanguage() + "\". Framework bug?");
+        }
+        return script;
+    }
+}
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 3add84a..22ad2d0 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -275,17 +275,16 @@
 }
 
 static jint latinime_BinaryDictionary_getNgramProbability(JNIEnv *env, jclass clazz,
-        jlong dict, jintArray word0, jboolean isBeginningOfSentence, jintArray word1) {
+        jlong dict, jobjectArray prevWordCodePointArrays, jbooleanArray isBeginningOfSentenceArray,
+        jintArray word) {
     Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
     if (!dictionary) return JNI_FALSE;
-    const jsize word0Length = env->GetArrayLength(word0);
-    const jsize word1Length = env->GetArrayLength(word1);
-    int word0CodePoints[word0Length];
-    int word1CodePoints[word1Length];
-    env->GetIntArrayRegion(word0, 0, word0Length, word0CodePoints);
-    env->GetIntArrayRegion(word1, 0, word1Length, word1CodePoints);
-    const PrevWordsInfo prevWordsInfo(word0CodePoints, word0Length, isBeginningOfSentence);
-    return dictionary->getNgramProbability(&prevWordsInfo, word1CodePoints, word1Length);
+    const jsize wordLength = env->GetArrayLength(word);
+    int wordCodePoints[wordLength];
+    env->GetIntArrayRegion(word, 0, wordLength, wordCodePoints);
+    const PrevWordsInfo prevWordsInfo = JniDataUtils::constructPrevWordsInfo(env,
+            prevWordCodePointArrays, isBeginningOfSentenceArray);
+    return dictionary->getNgramProbability(&prevWordsInfo, wordCodePoints, wordLength);
 }
 
 // Method to iterate all words in the dictionary for makedict.
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
index 4da339b..1d202c3 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.cpp
@@ -77,30 +77,6 @@
     return dictBuffers->flush(dirPath);
 }
 
-/* static */ bool DictFileWritingUtils::flushAllHeaderAndBodyToFile(const char *const filePath,
-        BufferWithExtendableBuffer *const dictHeader, BufferWithExtendableBuffer *const dictBody) {
-    const int tmpFileNameBufSize = FileUtils::getFilePathWithSuffixBufSize(filePath,
-            TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE);
-    // Name of a temporary file used for writing that is a connected string of original name and
-    // TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE.
-    char tmpFileName[tmpFileNameBufSize];
-    FileUtils::getFilePathWithSuffix(filePath, TEMP_FILE_SUFFIX_FOR_WRITING_DICT_FILE,
-            tmpFileNameBufSize, tmpFileName);
-    if (!DictFileWritingUtils::flushBufferToFile(tmpFileName, dictHeader)) {
-        AKLOGE("Dictionary header cannot be written to %s.", tmpFileName);
-        return false;
-    }
-    if (!DictFileWritingUtils::flushBufferToFile(tmpFileName, dictBody)) {
-        AKLOGE("Dictionary structure cannot be written to %s.", tmpFileName);
-        return false;
-    }
-    if (rename(tmpFileName, filePath) != 0) {
-        AKLOGE("Dictionary file %s cannot be renamed to %s", tmpFileName, filePath);;
-        return false;
-    }
-    return true;
-}
-
 /* static */ bool DictFileWritingUtils::flushBufferToFileWithSuffix(const char *const basePath,
         const char *const suffix, const BufferWithExtendableBuffer *const buffer) {
     const int filePathBufSize = FileUtils::getFilePathWithSuffixBufSize(basePath, suffix);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h
index 5df5856..0dd1256 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/utils/dict_file_writing_utils.h
@@ -35,10 +35,6 @@
             const std::vector<int> localeAsCodePointVector,
             const DictionaryHeaderStructurePolicy::AttributeMap *const attributeMap);
 
-    static bool flushAllHeaderAndBodyToFile(const char *const filePath,
-            BufferWithExtendableBuffer *const dictHeader,
-            BufferWithExtendableBuffer *const dictBody);
-
     static bool flushBufferToFileWithSuffix(const char *const basePath, const char *const suffix,
             const BufferWithExtendableBuffer *const buffer);
 
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java
index bf19a8b..59fe611 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetSubtypesCountTests.java
@@ -25,7 +25,7 @@
 
 @SmallTest
 public class KeyboardLayoutSetSubtypesCountTests extends KeyboardLayoutSetTestsBase {
-    private static final int NUMBER_OF_SUBTYPES = 68;
+    private static final int NUMBER_OF_SUBTYPES = 72;
     private static final int NUMBER_OF_ASCII_CAPABLE_SUBTYPES = 45;
     private static final int NUMBER_OF_PREDEFINED_ADDITIONAL_SUBTYPES = 2;
 
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Sinhala.java b/tests/src/com/android/inputmethod/keyboard/layout/Sinhala.java
new file mode 100644
index 0000000..bfd94d5
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Sinhala.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout;
+
+import com.android.inputmethod.keyboard.KeyboardId;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKey;
+import com.android.inputmethod.keyboard.layout.expected.ExpectedKeyboardBuilder;
+import com.android.inputmethod.latin.Constants;
+
+import java.util.Locale;
+
+/**
+ * The Sinhala keyboard.
+ */
+public final class Sinhala extends LayoutBase {
+    private static final String LAYOUT_NAME = "sinhala";
+
+    public Sinhala(final LayoutCustomizer customizer) {
+        super(customizer, Symbols.class, SymbolsShifted.class);
+    }
+
+    @Override
+    public String getName() { return LAYOUT_NAME; }
+
+    public static class SinhalaCustomizer extends LayoutCustomizer {
+        public SinhalaCustomizer(final Locale locale) { super(locale); }
+
+        @Override
+        public ExpectedKey getAlphabetKey() { return SINHALA_ALPHABET_KEY; }
+
+        @Override
+        public ExpectedKey[] getRightShiftKeys(final boolean isPhone) {
+            return isPhone ? EMPTY_KEYS : EXCLAMATION_AND_QUESTION_MARKS;
+        }
+
+        // U+0D85: "අ" SINHALA LETTER AYANNA
+        // U+0D86: "ආ" SINHALA LETTER AAYANNA
+        private static final ExpectedKey SINHALA_ALPHABET_KEY = key(
+                "\u0D85,\u0D86", Constants.CODE_SWITCH_ALPHA_SYMBOL);
+    }
+
+    @Override
+    ExpectedKey[][] getCommonAlphabetLayout(boolean isPhone) { return ALPHABET_COMMON; }
+
+    @Override
+    ExpectedKey[][] getCommonAlphabetShiftLayout(boolean isPhone, final int elementId) {
+        if (elementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED) {
+            return ALPHABET_COMMON;
+        }
+        return ALPHABET_SHIFTED_COMMON;
+    }
+
+    private static final ExpectedKey[][] ALPHABET_COMMON = new ExpectedKeyboardBuilder()
+            .setKeysOfRow(1,
+                    // U+0DD4: "ු" SINHALA VOWEL SIGN KETTI PAA-PILLA
+                    key("\u0DD4", moreKey("1")),
+                    // U+0D85: "අ" SINHALA LETTER AYANNA
+                    key("\u0D85", moreKey("2")),
+                    // U+0DD0: "ැ" SINHALA VOWEL SIGN KETTI AEDA-PILLA
+                    key("\u0DD0", moreKey("3")),
+                    // U+0DBB: "ර" SINHALA LETTER RAYANNA
+                    key("\u0DBB", moreKey("4")),
+                    // U+0D91: "එ" SINHALA LETTER EYANNA
+                    key("\u0D91", moreKey("5")),
+                    // U+0DC4: "හ" SINHALA LETTER HAYANNA
+                    key("\u0DC4", moreKey("6")),
+                    // U+0DB8: "ම" SINHALA LETTER MAYANNA
+                    key("\u0DB8", moreKey("7")),
+                    // U+0DC3: "ස" SINHALA LETTER DANTAJA SAYANNA
+                    key("\u0DC3", moreKey("8")),
+                    // U+0DAF: "ද" SINHALA LETTER ALPAPRAANA DAYANNA
+                    // U+0DB3: "ඳ" SINHALA LETTER SANYAKA DAYANNA
+                    key("\u0DAF", joinMoreKeys("9", "\u0DB3")),
+                    // U+0DA0: "ච" SINHALA LETTER ALPAPRAANA CAYANNA
+                    key("\u0DA0", moreKey("0")),
+                    // U+0DA4: "ඤ" SINHALA LETTER TAALUJA NAASIKYAYA
+                    // U+0DF4: "෴" SINHALA PUNCTUATION KUNDDALIYA
+                    key("\u0DA4", moreKey("\u0DF4")))
+            .setKeysOfRow(2,
+                    // U+0DCA: "්" SINHALA SIGN AL-LAKUNA
+                    // U+0DD2: "ි" SINHALA VOWEL SIGN KETTI IS-PILLA
+                    // U+0DCF: "ා" SINHALA VOWEL SIGN AELA-PILLA
+                    // U+0DD9: "ෙ" SINHALA VOWEL SIGN KOMBUVA
+                    // U+0DA7: "ට" SINHALA LETTER ALPAPRAANA TTAYANNA
+                    // U+0DBA: "ය" SINHALA LETTER YAYANNA
+                    // U+0DC0: "ව" SINHALA LETTER VAYANNA
+                    // U+0DB1: "න" SINHALA LETTER DANTAJA NAYANNA
+                    // U+0D9A: "ක" SINHALA LETTER ALPAPRAANA KAYANNA
+                    // U+0DAD: "ත" SINHALA LETTER ALPAPRAANA TAYANNA
+                    // U+0D8F: "ඏ" SINHALA LETTER ILUYANNA
+                    "\u0DCA", "\u0DD2", "\u0DCF", "\u0DD9", "\u0DA7", "\u0DBA", "\u0DC0", "\u0DB1",
+                    "\u0D9A", "\u0DAD", "\u0D8F")
+            .setKeysOfRow(3,
+                    // U+0D82: "ං" SINHALA SIGN ANUSVARAYA
+                    // U+0D83: "ඃ" SINHALA SIGN VISARGAYA
+                    key("\u0D82", moreKey("\u0D83")),
+                    // U+0DA2: "ජ" SINHALA LETTER ALPAPRAANA JAYANNA
+                    // U+0DA6: "ඦ" SINHALA LETTER SANYAKA JAYANNA
+                    key("\u0DA2", moreKey("\u0DA6")),
+                    // U+0DA9: "ඩ" SINHALA LETTER ALPAPRAANA DDAYANNA
+                    // U+0DAC: "ඬ" SINHALA LETTER SANYAKA DDAYANNA
+                    key("\u0DA9", moreKey("\u0DAC")),
+                    // U+0D89: "ඉ" SINHALA LETTER IYANNA
+                    // U+0DB6: "බ" SINHALA LETTER ALPAPRAANA BAYANNA
+                    // U+0DB4: "ප" SINHALA LETTER ALPAPRAANA PAYANNA
+                    // U+0DBD: "ල" SINHALA LETTER DANTAJA LAYANNA
+                    "\u0D89", "\u0DB6", "\u0DB4", "\u0DBD",
+                    // U+0D9C: "ග" SINHALA LETTER ALPAPRAANA GAYANNA
+                    // U+0D9F: "ඟ" SINHALA LETTER SANYAKA GAYANNA
+                    key("\u0D9C", moreKey("\u0D9F")),
+                    // U+0DF3: "ෳ" SINHALA VOWEL SIGN DIGA GAYANUKITTA
+                    "\u0DF3")
+            .build();
+
+    private static final ExpectedKey[][] ALPHABET_SHIFTED_COMMON = new ExpectedKeyboardBuilder()
+            .setKeysOfRow(1,
+                    // U+0DD6: "ූ" SINHALA VOWEL SIGN DIGA PAA-PILLA
+                    key("\u0DD6", moreKey("1")),
+                    // U+0D8B: "උ" SINHALA LETTER UYANNA
+                    key("\u0D8B", moreKey("2")),
+                    // U+0DD1: "ෑ" SINHALA VOWEL SIGN DIGA AEDA-PILLA
+                    key("\u0DD1", moreKey("3")),
+                    // U+0D8D: "ඍ" SINHALA LETTER IRUYANNA
+                    key("\u0D8D", moreKey("4")),
+                    // U+0D94: "ඔ" SINHALA LETTER OYANNA
+                    key("\u0D94", moreKey("5")),
+                    // U+0DC1: "ශ" SINHALA LETTER TAALUJA SAYANNA
+                    key("\u0DC1", moreKey("6")),
+                    // U+0DB9: "ඹ" SINHALA LETTER AMBA BAYANNA
+                    key("\u0DB9", moreKey("7")),
+                    // U+0DC2: "ෂ" SINHALA LETTER MUURDHAJA SAYANNA
+                    key("\u0DC2", moreKey("8")),
+                    // U+0DB0: "ධ" SINHALA LETTER MAHAAPRAANA DAYANNA
+                    key("\u0DB0", moreKey("9")),
+                    // U+0DA1: "ඡ" SINHALA LETTER MAHAAPRAANA CAYANNA
+                    key("\u0DA1", moreKey("0")),
+                    // U+0DA5: "ඥ" SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA
+                    // U+0DF4: "෴" SINHALA PUNCTUATION KUNDDALIYA
+                    key("\u0DA5", moreKey("\u0DF4")))
+            .setKeysOfRow(2,
+                    // U+0DDF: "ෟ" SINHALA VOWEL SIGN GAYANUKITTA
+                    // U+0DD3: "ී" SINHALA VOWEL SIGN DIGA IS-PILLA
+                    // U+0DD8: "ෘ" SINHALA VOWEL SIGN GAETTA-PILLA
+                    // U+0DC6: "ෆ" SINHALA LETTER FAYANNA
+                    // U+0DA8: "ඨ" SINHALA LETTER MAHAAPRAANA TTAYANNA
+                    // U+0DCA/U+200D/U+0DBA:
+                    //     "්‍ය" SINHALA SIGN AL-LAKUNA/ZERO WIDTH JOINER/SINHALA LETTER YAYANNA
+                    // U+0DC5/U+0DD4:
+                    //     "ළු" SINHALA LETTER MUURDHAJA LAYANNA/SINHALA VOWEL SIGN KETTI PAA-PILLA
+                    // U+0DAB: "ණ" SINHALA LETTER MUURDHAJA NAYANNA
+                    // U+0D9B: "ඛ" SINHALA LETTER MAHAAPRAANA KAYANNA
+                    // U+0DAE: "ථ" SINHALA LETTER MAHAAPRAANA TAYANNA
+                    // U+0DCA/U+200D/U+0DBB:
+                    //     "්‍ර" SINHALA SIGN AL-LAKUNA/ZERO WIDTH JOINER/SINHALA LETTER RAYANNA
+                    "\u0DDF", "\u0DD3", "\u0DD8", "\u0DC6", "\u0DA8", "\u0DCA\u200D\u0DBA",
+                    "\u0DC5\u0DD4", "\u0DAB", "\u0D9B", "\u0DAE", "\u0DCA\u200D\u0DBB")
+            .setKeysOfRow(3,
+                    // U+0D9E: "ඞ" SINHALA LETTER KANTAJA NAASIKYAYA
+                    // U+0DA3: "ඣ" SINHALA LETTER MAHAAPRAANA JAYANNA
+                    // U+0DAA: "ඪ" SINHALA LETTER MAHAAPRAANA DDAYANNA
+                    // U+0D8A: "ඊ" SINHALA LETTER IIYANNA
+                    // U+0DB7: "භ" SINHALA LETTER MAHAAPRAANA BAYANNA
+                    // U+0DB5: "ඵ" SINHALA LETTER MAHAAPRAANA PAYANNA
+                    // U+0DC5: "ළ" SINHALA LETTER MUURDHAJA LAYANNA
+                    // U+0D9D: "ඝ" SINHALA LETTER MAHAAPRAANA GAYANNA
+                    // U+0DBB/U+0DCA/U+200D:
+                    //     "ර්‍" SINHALA LETTER RAYANNA/SINHALA SIGN AL-LAKUNA/ZERO WIDTH JOINER
+                    "\u0d9E", "\u0DA3", "\u0DAA", "\u0D8A", "\u0DB7", "\u0DB5", "\u0DC5", "\u0D9D",
+                    "\u0DBB\u0DCA\u200D")
+            .build();
+}
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHindiCompact.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHindiCompact.java
index 6380da5..2e676df 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHindiCompact.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsHindiCompact.java
@@ -16,7 +16,7 @@
 
 package com.android.inputmethod.keyboard.layout.tests;
 
-import android.test.suitebuilder.annotation.Suppress;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.inputmethod.keyboard.layout.HindiCompact;
 import com.android.inputmethod.keyboard.layout.HindiCompact.HindiCompactCustomizer;
@@ -27,7 +27,7 @@
 /**
  * hi: Hindi/hindi_compact
  */
-@Suppress
+@SmallTest
 public final class TestsHindiCompact extends LayoutTestsBase {
     private static final Locale LOCALE = new Locale("hi");
     private static final LayoutBase LAYOUT = new HindiCompact(new HindiCompactCustomizer(LOCALE));
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMarathiIN.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMarathiIN.java
index d45d99d..b937629 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMarathiIN.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMarathiIN.java
@@ -16,7 +16,7 @@
 
 package com.android.inputmethod.keyboard.layout.tests;
 
-import android.test.suitebuilder.annotation.Suppress;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.inputmethod.keyboard.layout.LayoutBase;
 import com.android.inputmethod.keyboard.layout.Marathi;
@@ -27,7 +27,7 @@
 /**
  * mr_IN: Marathi (India)/marathi
  */
-@Suppress
+@SmallTest
 public final class TestsMarathiIN extends LayoutTestsBase {
     private static final Locale LOCALE = new Locale("mr", "IN");
     private static final LayoutBase LAYOUT = new Marathi(new MarathiCustomizer(LOCALE));
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java
index a0bd50c..e6d3b3b 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsMyanmarMM.java
@@ -16,7 +16,7 @@
 
 package com.android.inputmethod.keyboard.layout.tests;
 
-import android.test.suitebuilder.annotation.Suppress;
+import android.test.suitebuilder.annotation.SmallTest;
 
 import com.android.inputmethod.keyboard.layout.LayoutBase;
 import com.android.inputmethod.keyboard.layout.Myanmar;
@@ -27,7 +27,7 @@
 /**
  * my_MM: Myanmar (Myanmar)/myanmar
  */
-@Suppress
+@SmallTest
 public final class TestsMyanmarMM extends LayoutTestsBase {
     private static final Locale LOCALE = new Locale("my", "MM");
     private static final LayoutBase LAYOUT = new Myanmar(new MyanmarCustomizer(LOCALE));
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSinhalaLK.java b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSinhalaLK.java
new file mode 100644
index 0000000..1cea497
--- /dev/null
+++ b/tests/src/com/android/inputmethod/keyboard/layout/tests/TestsSinhalaLK.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.layout.tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.inputmethod.keyboard.layout.LayoutBase;
+import com.android.inputmethod.keyboard.layout.Sinhala;
+import com.android.inputmethod.keyboard.layout.Sinhala.SinhalaCustomizer;
+
+import java.util.Locale;
+
+/**
+ * si_LK: Sinhala (Sri Lanka)/sinhala
+ */
+@SmallTest
+public final class TestsSinhalaLK extends LayoutTestsBase {
+    private static final Locale LOCALE = new Locale("si", "LK");
+    private static final LayoutBase LAYOUT = new Sinhala(new SinhalaCustomizer(LOCALE));
+
+    @Override
+    LayoutBase getLayout() { return LAYOUT; }
+}
diff --git a/tools/make-keyboard-text/res/values-si-rLK/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-si-rLK/donottranslate-more-keys.xml
new file mode 100644
index 0000000..89c9195
--- /dev/null
+++ b/tools/make-keyboard-text/res/values-si-rLK/donottranslate-more-keys.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Label for "switch to alphabetic" key.
+         U+0D85: "අ" SINHALA LETTER AYANNA
+         U+0D86: "ආ" SINHALA LETTER AAYANNA -->
+    <string name="keylabel_to_alpha">&#x0D85;,&#x0D86;</string>
+</resources>