aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/res/values-hi/strings.xml2
-rw-r--r--java/res/values-land/dimens.xml6
-rw-r--r--java/res/values-lo/donottranslate.xml23
-rw-r--r--java/res/values-pt-rPT/strings.xml2
-rw-r--r--java/res/values-th/donottranslate.xml2
-rw-r--r--java/res/values/dimens.xml4
-rw-r--r--java/res/values/donottranslate.xml2
-rw-r--r--java/res/xml-sw600dp/rows_lao.xml63
-rw-r--r--java/res/xml/kbd_emoji_recents.xml3
-rw-r--r--java/res/xml/kbd_lao.xml31
-rw-r--r--java/res/xml/key_space_5kw.xml4
-rw-r--r--java/res/xml/key_styles_currency.xml4
-rw-r--r--java/res/xml/keyboard_layout_set_lao.xml58
-rw-r--r--java/res/xml/keyboard_layout_set_nepali_romanized.xml3
-rw-r--r--java/res/xml/keyboard_layout_set_nepali_traditional.xml3
-rw-r--r--java/res/xml/method.xml8
-rw-r--r--java/res/xml/rowkeys_lao1.xml164
-rw-r--r--java/res/xml/rowkeys_lao2.xml127
-rw-r--r--java/res/xml/rowkeys_lao3.xml110
-rw-r--r--java/res/xml/rowkeys_lao4.xml103
-rw-r--r--java/res/xml/rowkeys_nepali_romanized3.xml2
-rw-r--r--java/res/xml/rows_lao.xml56
-rw-r--r--java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java319
-rw-r--r--java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java10
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java106
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java80
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java4
-rw-r--r--java/src/com/android/inputmethod/latin/settings/Settings.java24
-rw-r--r--native/jni/src/defines.h1
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node.h6
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node_utils.cpp2
-rw-r--r--native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h4
-rw-r--r--native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp6
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary.cpp2
-rw-r--r--native/jni/src/suggest/core/dictionary/multi_bigram_map.h2
-rw-r--r--native/jni/src/suggest/core/session/dic_traverse_session.cpp4
-rw-r--r--native/jni/src/suggest/core/session/dic_traverse_session.h2
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp18
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h18
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp12
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp26
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h8
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp20
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h3
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.cpp11
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h11
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp20
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.cpp57
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.h58
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.cpp20
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h20
-rw-r--r--tools/make-keyboard-text/res/values-lo/donottranslate-more-keys.xml28
-rw-r--r--tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.xml63
-rw-r--r--tools/make-keyboard-text/res/values/donottranslate-more-keys.xml2
54 files changed, 1484 insertions, 263 deletions
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index 01bba5c6e..dcbbcd97c 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -31,7 +31,7 @@
<string name="correction_category" msgid="2236750915056607613">"पाठ सुधार"</string>
<string name="gesture_typing_category" msgid="497263612130532630">"जेस्चर लिखना"</string>
<string name="misc_category" msgid="6894192814868233453">"अन्य विकल्प"</string>
- <string name="advanced_settings" msgid="362895144495591463">"उन्नत सेटिंग"</string>
+ <string name="advanced_settings" msgid="362895144495591463">"अतिरिक्त सेटिंग"</string>
<string name="advanced_settings_summary" msgid="4487980456152830271">"विशेषज्ञों के लिए विकल्‍प"</string>
<string name="include_other_imes_in_language_switch_list" msgid="4533689960308565519">"अन्‍य इनपुट पद्धतियों पर जाएं"</string>
<string name="include_other_imes_in_language_switch_list_summary" msgid="840637129103317635">"भाषा स्‍विच कुंजी में अन्‍य इनपुट पद्धतियां भी शामिल हैं"</string>
diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml
index c954e60da..42a746b60 100644
--- a/java/res/values-land/dimens.xml
+++ b/java/res/values-land/dimens.xml
@@ -75,5 +75,9 @@
<dimen name="gesture_floating_preview_vertical_padding">15dp</dimen>
<!-- Emoji keyboard -->
- <fraction name="emoji_keyboard_key_width">8.3333%p</fraction>
+ <fraction name="emoji_keyboard_key_width">10%p</fraction>
+ <fraction name="emoji_keyboard_row_height">50%p</fraction>
+ <fraction name="emoji_keyboard_key_letter_size">60%p</fraction>
+ <integer name="emoji_keyboard_max_key_count">20</integer>
+
</resources>
diff --git a/java/res/values-lo/donottranslate.xml b/java/res/values-lo/donottranslate.xml
new file mode 100644
index 000000000..a9893feec
--- /dev/null
+++ b/java/res/values-lo/donottranslate.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Whether this language uses spaces between words -->
+ <bool name="current_language_has_spaces">false</bool>
+</resources>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index bad0bd669..cd89a7765 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -134,7 +134,7 @@
<string name="select_language" msgid="3693815588777926848">"Idiomas de introdução"</string>
<string name="hint_add_to_dictionary" msgid="573678656946085380">"Toque novamente para guardar"</string>
<string name="has_dictionary" msgid="6071847973466625007">"Dicionário disponível"</string>
- <string name="prefs_enable_log" msgid="6620424505072963557">"Activar comentários do utilizador"</string>
+ <string name="prefs_enable_log" msgid="6620424505072963557">"Ativar comentários do utilizador"</string>
<string name="prefs_description_log" msgid="7525225584555429211">"Envie automaticamente estatísticas de utilização e relatórios de falhas e ajude-nos a melhorar este editor do método de introdução."</string>
<string name="keyboard_layout" msgid="8451164783510487501">"Tema do teclado"</string>
<string name="subtype_en_GB" msgid="88170601942311355">"Inglês (RU)"</string>
diff --git a/java/res/values-th/donottranslate.xml b/java/res/values-th/donottranslate.xml
index aeeebed15..a9893feec 100644
--- a/java/res/values-th/donottranslate.xml
+++ b/java/res/values-th/donottranslate.xml
@@ -18,6 +18,6 @@
*/
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- Whether this language uses spaces -->
+ <!-- Whether this language uses spaces between words -->
<bool name="current_language_has_spaces">false</bool>
</resources>
diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml
index 7de93e6e3..88e327f26 100644
--- a/java/res/values/dimens.xml
+++ b/java/res/values/dimens.xml
@@ -117,6 +117,9 @@
<!-- Emoji keyboard -->
<fraction name="emoji_keyboard_key_width">14.2857%p</fraction>
+ <fraction name="emoji_keyboard_row_height">33%p</fraction>
+ <fraction name="emoji_keyboard_key_letter_size">90%p</fraction>
+ <integer name="emoji_keyboard_max_key_count">21</integer>
<!-- Inset used in Accessibility mode to avoid accidental key presses when a finger slides off the screen. -->
<dimen name="accessibility_edge_slop">8dp</dimen>
@@ -124,4 +127,5 @@
<integer name="user_dictionary_max_word_length" translatable="false">48</integer>
<dimen name="language_on_spacebar_horizontal_margin">1dp</dimen>
+
</resources>
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index 52ebe161c..82c5ce456 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -31,7 +31,7 @@
<string name="symbols_word_separators">"&#x0009;&#x0020;\n"()[]{}*&amp;&lt;&gt;+=|.,;:!?/_\"</string>
<!-- Word connectors -->
<string name="symbols_word_connectors">\'-</string>
- <!-- Whether this language uses spaces -->
+ <!-- Whether this language uses spaces between words -->
<bool name="current_language_has_spaces">true</bool>
<!-- Always show the suggestion strip -->
diff --git a/java/res/xml-sw600dp/rows_lao.xml b/java/res/xml-sw600dp/rows_lao.xml
new file mode 100644
index 000000000..cfe8db98e
--- /dev/null
+++ b/java/res/xml-sw600dp/rows_lao.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <include
+ latin:keyboardLayout="@xml/key_styles_common" />
+ <Row
+ latin:keyWidth="7.5%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao1" />
+ <Key
+ latin:keyStyle="deleteKeyStyle"
+ latin:keyWidth="fillRight" />
+ </Row>
+ <Row
+ latin:keyWidth="7.5%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao2" />
+ </Row>
+ <Row
+ latin:keyWidth="7.5%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao3" />
+ <Key
+ latin:keyStyle="enterKeyStyle"
+ latin:keyWidth="fillRight" />
+ </Row>
+ <Row
+ latin:keyWidth="7.5%p"
+ >
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.0%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao4" />
+ <include
+ latin:keyboardLayout="@xml/keys_exclamation_question" />
+ </Row>
+ <include
+ latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/res/xml/kbd_emoji_recents.xml b/java/res/xml/kbd_emoji_recents.xml
index f56b79ab7..73926ecc0 100644
--- a/java/res/xml/kbd_emoji_recents.xml
+++ b/java/res/xml/kbd_emoji_recents.xml
@@ -21,8 +21,9 @@
<Keyboard
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
latin:keyWidth="@fraction/emoji_keyboard_key_width"
- latin:keyLetterSize="90%p"
+ latin:keyLetterSize="@fraction/emoji_keyboard_key_letter_size"
latin:keyLabelSize="60%p"
+ latin:rowHeight="@fraction/emoji_keyboard_row_height"
>
<GridRows
latin:codesArray="@array/emoji_recents"
diff --git a/java/res/xml/kbd_lao.xml b/java/res/xml/kbd_lao.xml
new file mode 100644
index 000000000..2bba330de
--- /dev/null
+++ b/java/res/xml/kbd_lao.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<Keyboard
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+ latin:rowHeight="20%p"
+ latin:verticalGap="@fraction/key_bottom_gap_5row"
+ latin:keyLetterSize="@fraction/key_letter_ratio_5row"
+ latin:keyShiftedLetterHintRatio="@fraction/key_uppercase_letter_ratio_5row"
+ latin:touchPositionCorrectionData="@array/touch_position_correction_data_default"
+>
+ <include
+ latin:keyboardLayout="@xml/rows_lao" />
+</Keyboard>
diff --git a/java/res/xml/key_space_5kw.xml b/java/res/xml/key_space_5kw.xml
index 02ee42fd2..b6d38fb33 100644
--- a/java/res/xml/key_space_5kw.xml
+++ b/java/res/xml/key_space_5kw.xml
@@ -23,7 +23,7 @@
>
<switch>
<case
- latin:languageCode="fa"
+ latin:languageCode="fa|ne"
latin:languageSwitchKeyEnabled="true"
>
<Key
@@ -35,7 +35,7 @@
latin:keyStyle="zwnjKeyStyle" />
</case>
<case
- latin:languageCode="fa"
+ latin:languageCode="fa|ne"
latin:languageSwitchKeyEnabled="false"
>
<Key
diff --git a/java/res/xml/key_styles_currency.xml b/java/res/xml/key_styles_currency.xml
index 60333eeb4..b7677a20d 100644
--- a/java/res/xml/key_styles_currency.xml
+++ b/java/res/xml/key_styles_currency.xml
@@ -95,14 +95,16 @@
<!-- fa: Persian (Rial and Afgahni)
hi: Hindi (Indian Rupee)
iw: Hebrew (New Sheqel)
+ lo: Lao (Kip)
mn: Mongolian (Tugrik)
+ ne: Nepali (Nepalese Rupee)
th: Thai (Baht)
uk: Ukrainian (Hryvnia)
vi: Vietnamese (Dong) -->
<!-- TODO: The currency sign of Turkish Lira was created in 2012 and assigned U+20BA for
its unicode, although there is no font glyph for it as of November 2012. -->
<case
- latin:languageCode="fa|hi|iw|mn|th|uk|vi"
+ latin:languageCode="fa|hi|iw|lo|mn|ne|th|uk|vi"
>
<!-- U+00A3: "£" POUND SIGN
U+20AC: "€" EURO SIGN
diff --git a/java/res/xml/keyboard_layout_set_lao.xml b/java/res/xml/keyboard_layout_set_lao.xml
new file mode 100644
index 000000000..2ffde45db
--- /dev/null
+++ b/java/res/xml/keyboard_layout_set_lao.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<KeyboardLayoutSet
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
+ <Element
+ latin:elementName="alphabet"
+ latin:elementKeyboard="@xml/kbd_lao"
+ latin:enableProximityCharsCorrection="true" />
+ <Element
+ latin:elementName="alphabetAutomaticShifted"
+ latin:elementKeyboard="@xml/kbd_lao"
+ 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_lao" />
+ <Element
+ latin:elementName="alphabetShiftLocked"
+ latin:elementKeyboard="@xml/kbd_lao" />
+ <Element
+ latin:elementName="alphabetShiftLockShifted"
+ latin:elementKeyboard="@xml/kbd_lao" />
+ <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/keyboard_layout_set_nepali_romanized.xml b/java/res/xml/keyboard_layout_set_nepali_romanized.xml
index 82f36cfbd..fbbc6a5a0 100644
--- a/java/res/xml/keyboard_layout_set_nepali_romanized.xml
+++ b/java/res/xml/keyboard_layout_set_nepali_romanized.xml
@@ -44,6 +44,9 @@
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
diff --git a/java/res/xml/keyboard_layout_set_nepali_traditional.xml b/java/res/xml/keyboard_layout_set_nepali_traditional.xml
index 2a6dc8e83..4a3b60153 100644
--- a/java/res/xml/keyboard_layout_set_nepali_traditional.xml
+++ b/java/res/xml/keyboard_layout_set_nepali_traditional.xml
@@ -44,6 +44,9 @@
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
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index c3d68c6e5..6014646bb 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -55,6 +55,7 @@
ka: Georgian/georgian
(kk: Kazakh/east_slavic) # disabled temporarily. waiting for strnig resources.
ky: Kyrgyz/east_slavic
+ lo: Lao/lao
lt: Lithuanian/qwerty
lv: Latvian/qwerty
mk: Macedonian/south_slavic
@@ -332,6 +333,13 @@
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
+ android:subtypeId="0x8315772c"
+ android:imeSubtypeLocale="lo"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=lao"
+ />
+ <subtype android:icon="@drawable/ic_subtype_keyboard"
+ android:label="@string/subtype_generic"
android:subtypeId="0x8321bb43"
android:imeSubtypeLocale="lt"
android:imeSubtypeMode="keyboard"
diff --git a/java/res/xml/rowkeys_lao1.xml b/java/res/xml/rowkeys_lao1.xml
new file mode 100644
index 000000000..fa1ad97d8
--- /dev/null
+++ b/java/res/xml/rowkeys_lao1.xml
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+0ED1: "໑" LAO DIGIT ONE -->
+ <Key
+ latin:keyLabel="&#x0ED1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED2: "໒" LAO DIGIT TWO -->
+ <Key
+ latin:keyLabel="&#x0ED2;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED3: "໓" LAO DIGIT THREE -->
+ <Key
+ latin:keyLabel="&#x0ED3;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED4: "໔" LAO DIGIT FOUR -->
+ <Key
+ latin:keyLabel="&#x0ED4;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ECC: "໌" LAO CANCELLATION MARK -->
+ <Key
+ latin:keyLabel="&#x0ECC;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EBC: "ຼ" LAO SEMIVOWEL SIGN LO -->
+ <Key
+ latin:keyLabel="&#x0EBC;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED5: "໕" LAO DIGIT FIVE -->
+ <Key
+ latin:keyLabel="&#x0ED5;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED6: "໖" LAO DIGIT SIX -->
+ <Key
+ latin:keyLabel="&#x0ED6;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED7: "໗" LAO DIGIT SEVEN -->
+ <Key
+ latin:keyLabel="&#x0ED7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED8: "໘" LAO DIGIT EIGHT -->
+ <Key
+ latin:keyLabel="&#x0ED8;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ED9: "໙" LAO DIGIT NINE -->
+ <Key
+ latin:keyLabel="&#x0ED9;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ECD/U+0EC8: "ໍ່" LAO NIGGAHITA/LAO TONE MAI EK -->
+ <Key
+ latin:keyLabel="&#x0ECD;&#x0EC8;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ </case>
+ <default>
+ <!-- U+0EA2: "ຢ" LAO LETTER YO
+ U+0ED1: "໑" LAO DIGIT ONE -->
+ <Key
+ latin:keyLabel="&#x0EA2;"
+ latin:keyHintLabel="1"
+ latin:additionalMoreKeys="1"
+ latin:moreKeys="&#x0ED1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E9F: "ຟ" LAO LETTER FO SUNG
+ U+0ED2: "໒" LAO DIGIT TWO -->
+ <Key
+ latin:keyLabel="&#x0E9F;"
+ latin:keyHintLabel="2"
+ latin:additionalMoreKeys="2"
+ latin:moreKeys="&#x0ED2;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC2: "ໂ" LAO VOWEL SIGN O
+ U+0ED3: "໓" LAO DIGIT THREE -->
+ <Key
+ latin:keyLabel="&#x0EC2;"
+ latin:keyHintLabel="3"
+ latin:additionalMoreKeys="3"
+ latin:moreKeys="&#x0ED3;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E96: "ຖ" LAO LETTER THO SUNG
+ U+0ED4: "໔" LAO DIGIT FOUR -->
+ <Key
+ latin:keyLabel="&#x0E96;"
+ latin:keyHintLabel="4"
+ latin:additionalMoreKeys="4"
+ latin:moreKeys="&#x0ED4;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB8: "ຸ" LAO VOWEL SIGN U -->
+ <Key
+ latin:keyLabel="&#x0EB8;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB9: "ູ" LAO VOWEL SIGN UU -->
+ <Key
+ latin:keyLabel="&#x0EB9;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E84: "ຄ" LAO LETTER KHO TAM
+ U+0ED5: "໕" LAO DIGIT FIVE -->
+ <Key
+ latin:keyLabel="&#x0E84;"
+ latin:keyHintLabel="5"
+ latin:additionalMoreKeys="5"
+ latin:moreKeys="&#x0ED5;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E95: "ຕ" LAO LETTER TO
+ U+0ED6: "໖" LAO DIGIT SIX -->
+ <Key
+ latin:keyLabel="&#x0E95;"
+ latin:keyHintLabel="6"
+ latin:additionalMoreKeys="6"
+ latin:moreKeys="&#x0ED6;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E88: "ຈ" LAO LETTER CO
+ U+0ED7: "໗" LAO DIGIT SEVEN -->
+ <Key
+ latin:keyLabel="&#x0E88;"
+ latin:keyHintLabel="7"
+ latin:additionalMoreKeys="7"
+ latin:moreKeys="&#x0ED7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E82: "ຂ" LAO LETTER KHO SUNG
+ U+0ED8: "໘" LAO DIGIT EIGHT -->
+ <Key
+ latin:keyLabel="&#x0E82;"
+ latin:keyHintLabel="8"
+ latin:additionalMoreKeys="8"
+ latin:moreKeys="&#x0ED8;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E8A: "ຊ" LAO LETTER SO TAM
+ U+0ED9: "໙" LAO DIGIT NINE -->
+ <Key
+ latin:keyLabel="&#x0E8A;"
+ latin:keyHintLabel="9"
+ latin:additionalMoreKeys="9"
+ latin:moreKeys="&#x0ED9;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ECD: "ໍ" LAO NIGGAHITA -->
+ <Key
+ latin:keyLabel="&#x0ECD;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_lao2.xml b/java/res/xml/rowkeys_lao2.xml
new file mode 100644
index 000000000..fca58ac0e
--- /dev/null
+++ b/java/res/xml/rowkeys_lao2.xml
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+0EBB/U+0EC9: "" LAO VOWEL SIGN MAI KON/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EBB;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+0ED0: "໐" LAO DIGIT ZERO -->
+ <Key
+ latin:keyLabel="&#x0ED0;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB3/U+0EC9: "ຳ້" LAO VOWEL SIGN AM/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EB3;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <Key
+ latin:keyLabel="_" />
+ <Key
+ latin:keyLabel="+" />
+ <!-- U+0EB4/U+0EC9: "ິ້" LAO VOWEL SIGN I/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EB4;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+0EB5/U+0EC9: "ີ້" LAO VOWEL SIGN II/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EB5;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+0EA3: "ຣ" LAO LETTER LO LING -->
+ <Key
+ latin:keyLabel="&#x0EA3;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EDC: "ໜ" LAO HO NO -->
+ <Key
+ latin:keyLabel="&#x0EDC;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EBD: "ຽ" LAO SEMIVOWEL SIGN NYO -->
+ <Key
+ latin:keyLabel="&#x0EBD;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EAB/U+0EBC: "" LAO LETTER HO SUNG/LAO SEMIVOWEL SIGN LO -->
+ <Key
+ latin:keyLabel="&#x0EAB;&#x0EBC;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+201D: "”" RIGHT DOUBLE QUOTATION MARK -->
+ <Key
+ latin:keyLabel="&#x201D;" />
+ </case>
+ <default>
+ <!-- U+0EBB: "ົ" LAO VOWEL SIGN MAI KON -->
+ <Key
+ latin:keyLabel="&#x0EBB;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC4: "ໄ" LAO VOWEL SIGN AI
+ U+0ED0: "໐" LAO DIGIT ZERO -->
+ <Key
+ latin:keyLabel="&#x0EC4;"
+ latin:keyHintLabel="0"
+ latin:additionalMoreKeys="0"
+ latin:moreKeys="&#x0ED0;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB3: "ຳ" LAO VOWEL SIGN AM -->
+ <Key
+ latin:keyLabel="&#x0EB3;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E9E: "ພ" LAO LETTER PHO TAM -->
+ <Key
+ latin:keyLabel="&#x0E9E;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB0: "ະ" LAO VOWEL SIGN A -->
+ <Key
+ latin:keyLabel="&#x0EB0;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB4: "ິ" LAO VOWEL SIGN I -->
+ <Key
+ latin:keyLabel="&#x0EB4;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB5: "ີ" LAO VOWEL SIGN II -->
+ <Key
+ latin:keyLabel="&#x0EB5;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EAE: "ຮ" LAO LETTER HO TAM -->
+ <Key
+ latin:keyLabel="&#x0EAE;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E99: "ນ" LAO LETTER NO -->
+ <Key
+ latin:keyLabel="&#x0E99;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E8D: "ຍ" LAO LETTER NYO -->
+ <Key
+ latin:keyLabel="&#x0E8D;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E9A: "ບ" LAO LETTER BO -->
+ <Key
+ latin:keyLabel="&#x0E9A;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EA5: "ລ" LAO LETTER LO LOOT -->
+ <Key
+ latin:keyLabel="&#x0EA5;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_lao3.xml b/java/res/xml/rowkeys_lao3.xml
new file mode 100644
index 000000000..2a6c2d1dd
--- /dev/null
+++ b/java/res/xml/rowkeys_lao3.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+0EB1/U+0EC9: "ັ້" LAO VOWEL SIGN MAI KAN/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EB1;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <Key
+ latin:keyLabel=";" />
+ <Key
+ latin:keyLabel="." />
+ <Key
+ latin:keyLabel="," />
+ <Key
+ latin:keyLabel=":" />
+ <!-- U+0ECA: "໊" LAO TONE MAI TI -->
+ <Key
+ latin:keyLabel="&#x0ECA;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0ECB: "໋" LAO TONE MAI CATAWA -->
+ <Key
+ latin:keyLabel="&#x0ECB;"
+ latin:keyLabelFlags="fontNormal" />
+ <Key
+ latin:keyLabel="!" />
+ <Key
+ latin:keyLabel="\?" />
+ <Key
+ latin:keyLabel="%" />
+ <Key
+ latin:keyLabel="=" />
+ <!-- U+201C: "“" LEFT DOUBLE QUOTATION MARK -->
+ <Key
+ latin:keyLabel="&#x201C;" />
+ </case>
+ <default>
+ <!-- U+0EB1: "ັ" LAO VOWEL SIGN MAI KAN -->
+ <Key
+ latin:keyLabel="&#x0EB1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EAB: "ຫ" LAO LETTER HO SUNG -->
+ <Key
+ latin:keyLabel="&#x0EAB;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E81: "ກ" LAO LETTER KO -->
+ <Key
+ latin:keyLabel="&#x0E81;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E94: "ດ" LAO LETTER DO -->
+ <Key
+ latin:keyLabel="&#x0E94;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC0: "ເ" LAO VOWEL SIGN E -->
+ <Key
+ latin:keyLabel="&#x0EC0;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC9: "້" LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EC9;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC8: "່" LAO TONE MAI EK -->
+ <Key
+ latin:keyLabel="&#x0EC8;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB2: "າ" LAO VOWEL SIGN AA -->
+ <Key
+ latin:keyLabel="&#x0EB2;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EAA: "ສ" LAO LETTER SO SUNG -->
+ <Key
+ latin:keyLabel="&#x0EAA;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EA7: "ວ" LAO LETTER WO -->
+ <Key
+ latin:keyLabel="&#x0EA7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E87: "ງ" LAO LETTER NGO -->
+ <Key
+ latin:keyLabel="&#x0E87;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+201C: "“" LEFT DOUBLE QUOTATION MARK -->
+ <Key
+ latin:keyLabel="&#x201C;" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_lao4.xml b/java/res/xml/rowkeys_lao4.xml
new file mode 100644
index 000000000..fae9cc923
--- /dev/null
+++ b/java/res/xml/rowkeys_lao4.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <case
+ latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetShiftLocked|alphabetShiftLockShifted"
+ >
+ <!-- U+20AD: "₭" KIP SIGN -->
+ <Key
+ latin:keyLabel="&#x20AD;" />
+ <Key
+ latin:keyLabel="(" />
+ <!-- U+0EAF: "ຯ" LAO ELLIPSIS -->
+ <Key
+ latin:keyLabel="&#x0EAF;"
+ latin:keyLabelFlags="fontNormal" />
+ <Key
+ latin:keyLabel="\@" />
+ <!-- U+0EB6/U+0EC9: "ຶ້" LAO VOWEL SIGN Y/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EB6;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+0EB7/U+0EC9: "ື້" LAO VOWEL SIGN YY/LAO TONE MAI THO -->
+ <Key
+ latin:keyLabel="&#x0EB7;&#x0EC9;"
+ latin:keyLabelFlags="fontNormal|followKeyLetterRatio" />
+ <!-- U+0EC6: "ໆ" LAO KO LA -->
+ <Key
+ latin:keyLabel="&#x0EC6;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EDD: "ໝ" LAO HO MO -->
+ <Key
+ latin:keyLabel="&#x0EDD;"
+ latin:keyLabelFlags="fontNormal" />
+ <Key
+ latin:keyLabel="$" />
+ <Key
+ latin:keyLabel=")" />
+ </case>
+ <default>
+ <!-- U+0E9C: "ຜ" LAO LETTER PHO SUNG -->
+ <Key
+ latin:keyLabel="&#x0E9C;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E9B: "ປ" LAO LETTER PO -->
+ <Key
+ latin:keyLabel="&#x0E9B;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC1: "ແ" LAO VOWEL SIGN EI -->
+ <Key
+ latin:keyLabel="&#x0EC1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EAD: "ອ" LAO LETTER O -->
+ <Key
+ latin:keyLabel="&#x0EAD;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB6: "ຶ" LAO VOWEL SIGN Y -->
+ <Key
+ latin:keyLabel="&#x0EB6;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EB7: "ື" LAO VOWEL SIGN YY -->
+ <Key
+ latin:keyLabel="&#x0EB7;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E97: "ທ" LAO LETTER THO TAM -->
+ <Key
+ latin:keyLabel="&#x0E97;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EA1: "ມ" LAO LETTER MO -->
+ <Key
+ latin:keyLabel="&#x0EA1;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0EC3: "ໃ" LAO VOWEL SIGN AY -->
+ <Key
+ latin:keyLabel="&#x0EC3;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0E9D: "ຝ" LAO LETTER FO TAM -->
+ <Key
+ latin:keyLabel="&#x0E9D;"
+ latin:keyLabelFlags="fontNormal" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml/rowkeys_nepali_romanized3.xml b/java/res/xml/rowkeys_nepali_romanized3.xml
index 5660596f0..166d028a3 100644
--- a/java/res/xml/rowkeys_nepali_romanized3.xml
+++ b/java/res/xml/rowkeys_nepali_romanized3.xml
@@ -48,7 +48,7 @@
latin:keyLabelFlags="fontNormal" />
<!-- U+0923: "ण" DEVANAGARI LETTER NNA -->
<Key
- latin:keyLabel="&#x0936;"
+ latin:keyLabel="&#x0923;"
latin:keyLabelFlags="fontNormal" />
<!-- Because the font rendering system prior to API version 16 can't automatically
render dotted circle for incomplete combining letter of some scripts, different
diff --git a/java/res/xml/rows_lao.xml b/java/res/xml/rows_lao.xml
new file mode 100644
index 000000000..321f4112a
--- /dev/null
+++ b/java/res/xml/rows_lao.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <include
+ latin:keyboardLayout="@xml/key_styles_common" />
+ <Row
+ latin:keyWidth="8.3333%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao1" />
+ </Row>
+ <Row
+ latin:keyWidth="8.3333%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao2" />
+ </Row>
+ <Row
+ latin:keyWidth="8.3333%p"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao3" />
+ </Row>
+ <Row
+ latin:keyWidth="8.3333%p"
+ >
+ <Key
+ latin:keyStyle="shiftKeyStyle" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_lao4" />
+ <Key
+ latin:keyStyle="deleteKeyStyle" />
+ </Row>
+ <include
+ latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java b/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
index 9996a6d6a..d28b5088c 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiKeyboardView.java
@@ -19,14 +19,18 @@ package com.android.inputmethod.keyboard;
import static com.android.inputmethod.latin.Constants.NOT_A_COORDINATE;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.Rect;
import android.os.Build;
+import android.preference.PreferenceManager;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
@@ -43,11 +47,15 @@ import com.android.inputmethod.keyboard.internal.ScrollViewWithNotifier;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SubtypeSwitcher;
+import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.ResourceUtils;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
/**
* View class to implement Emoji keyboards.
@@ -75,16 +83,25 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
+ private static final int CATEGORY_ID_UNSPECIFIED = -1;
+ public static final int CATEGORY_ID_RECENTS = 0;
+ public static final int CATEGORY_ID_PEOPLE = 1;
+ public static final int CATEGORY_ID_OBJECTS = 2;
+ public static final int CATEGORY_ID_NATURE = 3;
+ public static final int CATEGORY_ID_PLACES = 4;
+ public static final int CATEGORY_ID_SYMBOLS = 5;
+ public static final int CATEGORY_ID_EMOTICONS = 6;
+
+ private static class CategoryProperties {
+ public int mCategoryId;
+ public int mPageCount;
+ public CategoryProperties(final int categoryId, final int pageCount) {
+ mCategoryId = categoryId;
+ mPageCount = pageCount;
+ }
+ }
+
private static class EmojiCategory {
- private int mCurrentCategory = CATEGORY_UNSPECIFIED;
- private static final int CATEGORY_UNSPECIFIED = -1;
- private static final int CATEGORY_RECENTS = 0;
- private static final int CATEGORY_PEOPLE = 1;
- private static final int CATEGORY_OBJECTS = 2;
- private static final int CATEGORY_NATURE = 3;
- private static final int CATEGORY_PLACES = 4;
- private static final int CATEGORY_SYMBOLS = 5;
- private static final int CATEGORY_EMOTICONS = 6;
private static final String[] sCategoryName = {
"recents",
"people",
@@ -110,87 +127,231 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
KeyboardId.ELEMENT_EMOJI_CATEGORY3,
KeyboardId.ELEMENT_EMOJI_CATEGORY4,
KeyboardId.ELEMENT_EMOJI_CATEGORY5,
- KeyboardId.ELEMENT_EMOJI_CATEGORY6, };
+ KeyboardId.ELEMENT_EMOJI_CATEGORY6 };
+ private final SharedPreferences mPrefs;
+ private final int mMaxPageKeyCount;
+ private final KeyboardLayoutSet mLayoutSet;
private final HashMap<String, Integer> mCategoryNameToIdMap = CollectionUtils.newHashMap();
- private final ArrayList<Integer> mShownCategories = new ArrayList<Integer>();
-
- public EmojiCategory() {
+ private final ArrayList<CategoryProperties> mShownCategories =
+ CollectionUtils.newArrayList();
+ private final ConcurrentHashMap<Long, DynamicGridKeyboard>
+ mCategoryKeyboardMap = new ConcurrentHashMap<Long, DynamicGridKeyboard>();
+
+ private int mCurrentCategoryId = CATEGORY_ID_UNSPECIFIED;
+ private int mCurrentCategoryPageId = 0;
+
+ public EmojiCategory(final SharedPreferences prefs, final Resources res,
+ final KeyboardLayoutSet layoutSet) {
+ mPrefs = prefs;
+ mMaxPageKeyCount = res.getInteger(R.integer.emoji_keyboard_max_key_count);
+ mLayoutSet = layoutSet;
for (int i = 0; i < sCategoryName.length; ++i) {
mCategoryNameToIdMap.put(sCategoryName[i], i);
}
- mShownCategories.add(CATEGORY_RECENTS);
+ addShownCategoryId(CATEGORY_ID_RECENTS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- mShownCategories.add(CATEGORY_PEOPLE);
- mShownCategories.add(CATEGORY_OBJECTS);
- mShownCategories.add(CATEGORY_NATURE);
- mShownCategories.add(CATEGORY_PLACES);
- // TODO: Restore last saved category
- mCurrentCategory = CATEGORY_PEOPLE;
+ addShownCategoryId(CATEGORY_ID_PEOPLE);
+ addShownCategoryId(CATEGORY_ID_OBJECTS);
+ addShownCategoryId(CATEGORY_ID_NATURE);
+ addShownCategoryId(CATEGORY_ID_PLACES);
+ mCurrentCategoryId = CATEGORY_ID_PEOPLE;
} else {
- // TODO: Restore last saved category
- mCurrentCategory = CATEGORY_SYMBOLS;
+ mCurrentCategoryId = CATEGORY_ID_SYMBOLS;
}
- mShownCategories.add(CATEGORY_SYMBOLS);
- mShownCategories.add(CATEGORY_EMOTICONS);
+ addShownCategoryId(CATEGORY_ID_SYMBOLS);
+ addShownCategoryId(CATEGORY_ID_EMOTICONS);
+ getKeyboard(CATEGORY_ID_RECENTS, 0 /* cagetoryPageId */)
+ .loadRecentKeys(mCategoryKeyboardMap.values());
+ }
+
+ private void addShownCategoryId(int categoryId) {
+ // Load a keyboard of categoryId
+ getKeyboard(categoryId, 0 /* cagetoryPageId */);
+ final CategoryProperties properties =
+ new CategoryProperties(categoryId, getCategoryPageCount(categoryId));
+ mShownCategories.add(properties);
}
- public String getCategoryName(int category) {
- return sCategoryName[category];
+ public String getCategoryName(int categoryId, int categoryPageId) {
+ return sCategoryName[categoryId] + "-" + categoryPageId;
}
public int getCategoryId(String name) {
- return mCategoryNameToIdMap.get(name);
+ final String[] strings = name.split("-");
+ return mCategoryNameToIdMap.get(strings[0]);
}
- public int getCategoryIcon(int category) {
- return sCategoryIcon[category];
+ public int getCategoryIcon(int categoryId) {
+ return sCategoryIcon[categoryId];
}
- public String getCategoryLabel(int category) {
- return sCategoryLabel[category];
+ public String getCategoryLabel(int categoryId) {
+ return sCategoryLabel[categoryId];
}
- public ArrayList<Integer> getShownCategories() {
+ public ArrayList<CategoryProperties> getShownCategories() {
return mShownCategories;
}
- public int getCurrentCategory() {
- // TODO: Record current category.
- return mCurrentCategory;
+ public int getCurrentCategoryId() {
+ return mCurrentCategoryId;
+ }
+
+ public void setCurrentCategoryId(int categoryId) {
+ mCurrentCategoryId = categoryId;
}
- public void setCurrentCategory(int category) {
- mCurrentCategory = category;
+ public void setCurrentCategoryPageId(int id) {
+ mCurrentCategoryPageId = id;
+ }
+
+ public void saveLastTypedCategoryPage() {
+ Settings.writeEmojiCategoryLastTypedId(
+ mPrefs, mCurrentCategoryId, mCurrentCategoryPageId);
}
public boolean isInRecentTab() {
- return mCurrentCategory == CATEGORY_RECENTS;
+ return mCurrentCategoryId == CATEGORY_ID_RECENTS;
}
- public int getTabIdFromCategory(int category) {
+ public int getTabIdFromCategoryId(int categoryId) {
for (int i = 0; i < mShownCategories.size(); ++i) {
- if (mShownCategories.get(i) == category) {
+ if (mShownCategories.get(i).mCategoryId == categoryId) {
return i;
}
}
- Log.w(TAG, "category not found: " + category);
+ Log.w(TAG, "categoryId not found: " + categoryId);
+ return 0;
+ }
+
+ // Returns the view pager's page position for the categoryId
+ public int getPageIdFromCategoryId(int categoryId) {
+ final int lastSavedCategoryPageId =
+ Settings.readEmojiCategoryLastTypedId(mPrefs, categoryId);
+ int sum = 0;
+ for (int i = 0; i < mShownCategories.size(); ++i) {
+ final CategoryProperties props = mShownCategories.get(i);
+ if (props.mCategoryId == categoryId) {
+ return sum + lastSavedCategoryPageId;
+ }
+ sum += props.mPageCount;
+ }
+ Log.w(TAG, "categoryId not found: " + categoryId);
return 0;
}
public int getRecentTabId() {
- return getTabIdFromCategory(CATEGORY_RECENTS);
+ return getTabIdFromCategoryId(CATEGORY_ID_RECENTS);
}
- public int getCategoryFromTabId(int tabId) {
- return mShownCategories.get(tabId);
+ private int getCategoryPageCount(int categoryId) {
+ final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]);
+ return (keyboard.getKeys().length - 1) / mMaxPageKeyCount + 1;
}
- public int getElementIdFromTabId(int tabId) {
- return sCategoryElementId[getCategoryFromTabId(tabId)];
+ // Returns a pair of the category id and the category page id from the view pager's page
+ // position. The category page id is numbered in each category. And the view page position
+ // is the position of the current shown page in the view pager which contains all pages of
+ // all categories.
+ public Pair<Integer, Integer> getCategoryIdAndPageIdFromPagePosition(int position) {
+ int sum = 0;
+ for (CategoryProperties properties : mShownCategories) {
+ final int temp = sum;
+ sum += properties.mPageCount;
+ if (sum > position) {
+ return new Pair<Integer, Integer>(properties.mCategoryId, position - temp);
+ }
+ }
+ return null;
+ }
+
+ // Returns a keyboard from the view pager's page position.
+ public DynamicGridKeyboard getKeyboardFromPagePosition(int position) {
+ final Pair<Integer, Integer> categoryAndId =
+ getCategoryIdAndPageIdFromPagePosition(position);
+ if (categoryAndId != null) {
+ return getKeyboard(categoryAndId.first, categoryAndId.second);
+ }
+ return null;
+ }
+
+ public DynamicGridKeyboard getKeyboard(int categoryId, int id) {
+ synchronized(mCategoryKeyboardMap) {
+ final long key = (((long) categoryId) << Constants.MAX_INT_BIT_COUNT) | id;
+ final DynamicGridKeyboard kbd;
+ if (!mCategoryKeyboardMap.containsKey(key)) {
+ if (categoryId != CATEGORY_ID_RECENTS) {
+ final Keyboard keyboard =
+ mLayoutSet.getKeyboard(sCategoryElementId[categoryId]);
+ final Key[][] sortedKeys = sortKeys(keyboard.getKeys(), mMaxPageKeyCount);
+ for (int i = 0; i < sortedKeys.length; ++i) {
+ final DynamicGridKeyboard tempKbd = new DynamicGridKeyboard(mPrefs,
+ mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
+ mMaxPageKeyCount, categoryId, i /* categoryPageId */);
+ for (Key emojiKey : sortedKeys[i]) {
+ if (emojiKey == null) {
+ break;
+ }
+ tempKbd.addKeyLast(emojiKey);
+ }
+ mCategoryKeyboardMap.put((((long) categoryId)
+ << Constants.MAX_INT_BIT_COUNT) | i, tempKbd);
+ }
+ kbd = mCategoryKeyboardMap.get(key);
+ } else {
+ kbd = new DynamicGridKeyboard(mPrefs,
+ mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS),
+ mMaxPageKeyCount, categoryId, 0 /* categoryPageId */);
+ mCategoryKeyboardMap.put(key, kbd);
+ }
+ } else {
+ kbd = mCategoryKeyboardMap.get(key);
+ }
+ return kbd;
+ }
+ }
+
+ public int getTotalPageCountOfAllCategories() {
+ int sum = 0;
+ for (CategoryProperties properties : mShownCategories) {
+ sum += properties.mPageCount;
+ }
+ return sum;
+ }
+
+ private Key[][] sortKeys(Key[] inKeys, int maxPageCount) {
+ Key[] keys = Arrays.copyOf(inKeys, inKeys.length);
+ Arrays.sort(keys, 0, keys.length, new Comparator<Key>() {
+ @Override
+ public int compare(Key lhs, Key rhs) {
+ final Rect lHitBox = lhs.getHitBox();
+ final Rect rHitBox = rhs.getHitBox();
+ if (lHitBox.top < rHitBox.top) {
+ return -1;
+ } else if (lHitBox.top > rHitBox.top) {
+ return 1;
+ }
+ if (lHitBox.left < rHitBox.left) {
+ return -1;
+ } else if (lHitBox.left > rHitBox.left) {
+ return 1;
+ }
+ if (lhs.getCode() == rhs.getCode()) {
+ return 0;
+ }
+ return lhs.getCode() < rhs.getCode() ? -1 : 1;
+ }
+ });
+ final int pageCount = (keys.length - 1) / maxPageCount + 1;
+ final Key[][] retval = new Key[pageCount][maxPageCount];
+ for (int i = 0; i < keys.length; ++i) {
+ retval[i / maxPageCount][i % maxPageCount] = keys[i];
+ }
+ return retval;
}
}
- private final EmojiCategory mEmojiCategory = new EmojiCategory();
+ private final EmojiCategory mEmojiCategory;
public EmojiKeyboardView(final Context context, final AttributeSet attrs) {
this(context, attrs, R.attr.emojiKeyboardViewStyle);
@@ -213,13 +374,14 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(
context, null /* editorInfo */);
final Resources res = context.getResources();
+ final EmojiLayoutParams emojiLp = new EmojiLayoutParams(res);
builder.setSubtype(SubtypeSwitcher.getInstance().getEmojiSubtype());
builder.setKeyboardGeometry(ResourceUtils.getDefaultKeyboardWidth(res),
- (int)ResourceUtils.getDefaultKeyboardHeight(res)
- + res.getDimensionPixelSize(R.dimen.suggestions_strip_height));
+ emojiLp.mEmojiKeyboardHeight);
builder.setOptions(false, false, false /* lanuageSwitchKeyEnabled */);
mLayoutSet = builder.build();
- // TODO: Save/restore recent keys from/to preferences.
+ mEmojiCategory = new EmojiCategory(PreferenceManager.getDefaultSharedPreferences(context),
+ context.getResources(), builder.build());
}
@Override
@@ -235,20 +397,20 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
setMeasuredDimension(width, height);
}
- private void addTab(final TabHost host, final int category) {
- final String tabId = mEmojiCategory.getCategoryName(category);
+ private void addTab(final TabHost host, final int categoryId) {
+ final String tabId = mEmojiCategory.getCategoryName(categoryId, 0 /* categoryPageId */);
final TabHost.TabSpec tspec = host.newTabSpec(tabId);
tspec.setContent(R.id.emoji_keyboard_dummy);
- if (mEmojiCategory.getCategoryIcon(category) != 0) {
+ if (mEmojiCategory.getCategoryIcon(categoryId) != 0) {
final ImageView iconView = (ImageView)LayoutInflater.from(getContext()).inflate(
R.layout.emoji_keyboard_tab_icon, null);
- iconView.setImageResource(mEmojiCategory.getCategoryIcon(category));
+ iconView.setImageResource(mEmojiCategory.getCategoryIcon(categoryId));
tspec.setIndicator(iconView);
}
- if (mEmojiCategory.getCategoryLabel(category) != null) {
+ if (mEmojiCategory.getCategoryLabel(categoryId) != null) {
final TextView textView = (TextView)LayoutInflater.from(getContext()).inflate(
R.layout.emoji_keyboard_tab_label, null);
- textView.setText(mEmojiCategory.getCategoryLabel(category));
+ textView.setText(mEmojiCategory.getCategoryLabel(categoryId));
textView.setTextColor(mTabLabelColor);
tspec.setIndicator(textView);
}
@@ -259,8 +421,8 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
protected void onFinishInflate() {
mTabHost = (TabHost)findViewById(R.id.emoji_category_tabhost);
mTabHost.setup();
- for (final int i : mEmojiCategory.getShownCategories()) {
- addTab(mTabHost, i);
+ for (final CategoryProperties properties : mEmojiCategory.getShownCategories()) {
+ addTab(mTabHost, properties.mCategoryId);
}
mTabHost.setOnTabChangedListener(this);
mTabHost.getTabWidget().setStripEnabled(true);
@@ -275,7 +437,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
final EmojiLayoutParams emojiLp = new EmojiLayoutParams(res);
emojiLp.setPagerProps(mEmojiPager);
- setCurrentCategory(mEmojiCategory.getCurrentCategory(), true /* force */);
+ setCurrentCategoryId(mEmojiCategory.getCurrentCategoryId(), true /* force */);
final LinearLayout actionBar = (LinearLayout)findViewById(R.id.emoji_action_bar);
emojiLp.setActionBarProps(actionBar);
@@ -302,14 +464,17 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
@Override
public void onTabChanged(final String tabId) {
- final int category = mEmojiCategory.getCategoryId(tabId);
- setCurrentCategory(category, false /* force */);
+ final int categoryId = mEmojiCategory.getCategoryId(tabId);
+ setCurrentCategoryId(categoryId, false /* force */);
}
@Override
public void onPageSelected(final int position) {
- setCurrentCategory(mEmojiCategory.getCategoryFromTabId(position), false /* force */);
+ final Pair<Integer, Integer> newPos =
+ mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(position);
+ setCurrentCategoryId(newPos.first /* categoryId */, false /* force */);
+ mEmojiCategory.setCurrentCategoryPageId(newPos.second /* categoryPageId */);
}
@Override
@@ -341,6 +506,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
@Override
public void onKeyClick(final Key key) {
mEmojiKeyboardAdapter.addRecentKey(key);
+ mEmojiCategory.saveLastTypedCategoryPage();
final int code = key.getCode();
if (code == Constants.CODE_OUTPUT_TEXT) {
mKeyboardActionListener.onTextInput(key.getOutputText());
@@ -357,25 +523,25 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
mKeyboardActionListener = listener;
}
- private void setCurrentCategory(final int category, final boolean force) {
- if (mEmojiCategory.getCurrentCategory() == category && !force) {
+ private void setCurrentCategoryId(final int categoryId, final boolean force) {
+ if (mEmojiCategory.getCurrentCategoryId() == categoryId && !force) {
return;
}
- mEmojiCategory.setCurrentCategory(category);
- final int newTabId = mEmojiCategory.getTabIdFromCategory(category);
- if (force || mEmojiPager.getCurrentItem() != newTabId) {
- mEmojiPager.setCurrentItem(newTabId, true /* smoothScroll */);
+ mEmojiCategory.setCurrentCategoryId(categoryId);
+ final int newTabId = mEmojiCategory.getTabIdFromCategoryId(categoryId);
+ final int newCategoryPageId = mEmojiCategory.getPageIdFromCategoryId(categoryId);
+ if (force || mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(
+ mEmojiPager.getCurrentItem()).first != categoryId) {
+ mEmojiPager.setCurrentItem(newCategoryPageId, true /* smoothScroll */);
}
if (force || mTabHost.getCurrentTab() != newTabId) {
mTabHost.setCurrentTab(newTabId);
}
- // TODO: Record current category
}
private static class EmojiKeyboardAdapter extends PagerAdapter {
private final ScrollKeyboardView.OnKeyClickListener mListener;
- private final KeyboardLayoutSet mLayoutSet;
private final DynamicGridKeyboard mRecentsKeyboard;
private final SparseArray<ScrollKeyboardView> mActiveKeyboardView =
CollectionUtils.newSparseArray();
@@ -387,16 +553,14 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
final ScrollKeyboardView.OnKeyClickListener listener) {
mEmojiCategory = emojiCategory;
mListener = listener;
- mLayoutSet = layoutSet;
- mRecentsKeyboard = new DynamicGridKeyboard(
- layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS));
+ mRecentsKeyboard = mEmojiCategory.getKeyboard(CATEGORY_ID_RECENTS, 0);
}
public void addRecentKey(final Key key) {
if (mEmojiCategory.isInRecentTab()) {
return;
}
- mRecentsKeyboard.addRecentKey(key);
+ mRecentsKeyboard.addKeyFirst(key);
final KeyboardView recentKeyboardView =
mActiveKeyboardView.get(mEmojiCategory.getRecentTabId());
if (recentKeyboardView != null) {
@@ -406,7 +570,7 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
@Override
public int getCount() {
- return mEmojiCategory.getShownCategories().size();
+ return mEmojiCategory.getTotalPageCountOfAllCategories();
}
@Override
@@ -424,9 +588,8 @@ public final class EmojiKeyboardView extends LinearLayout implements OnTabChange
@Override
public Object instantiateItem(final ViewGroup container, final int position) {
- final int elementId = mEmojiCategory.getElementIdFromTabId(position);
- final Keyboard keyboard = (elementId == KeyboardId.ELEMENT_EMOJI_RECENTS)
- ? mRecentsKeyboard : mLayoutSet.getKeyboard(elementId);
+ final Keyboard keyboard =
+ mEmojiCategory.getKeyboardFromPagePosition(position);
final LayoutInflater inflater = LayoutInflater.from(container.getContext());
final View view = inflater.inflate(
R.layout.emoji_keyboard_page, container, false /* attachToRoot */);
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java b/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java
index 6486fc9db..5570d594d 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiLayoutParams.java
@@ -27,6 +27,8 @@ import android.widget.LinearLayout;
public class EmojiLayoutParams {
private static final int DEFAULT_KEYBOARD_ROWS = 4;
+ public final int mEmojiPagerHeight;
+ private final int mEmojiPagerBottomMargin;
public final int mEmojiKeyboardHeight;
public final int mEmojiActionBarHeight;
public final int mKeyVerticalGap;
@@ -49,13 +51,15 @@ public class EmojiLayoutParams {
+ mKeyVerticalGap;
mEmojiActionBarHeight = ((int) baseheight) / DEFAULT_KEYBOARD_ROWS
- (mKeyVerticalGap - mBottomPadding) / 2;
- mEmojiKeyboardHeight = defaultKeyboardHeight - mEmojiActionBarHeight;
+ mEmojiPagerHeight = defaultKeyboardHeight - mEmojiActionBarHeight;
+ mEmojiPagerBottomMargin = mKeyVerticalGap / 2;
+ mEmojiKeyboardHeight = mEmojiPagerHeight - mEmojiPagerBottomMargin - 1;
}
public void setPagerProps(ViewPager vp) {
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) vp.getLayoutParams();
- lp.height = mEmojiKeyboardHeight - mKeyVerticalGap / 2;
- lp.bottomMargin = mKeyVerticalGap / 2;
+ lp.height = mEmojiPagerHeight - mEmojiPagerBottomMargin;
+ lp.bottomMargin = mEmojiPagerBottomMargin;
vp.setLayoutParams(lp);
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
index a226891b4..f203eb7d7 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
@@ -16,33 +16,41 @@
package com.android.inputmethod.keyboard.internal;
+import android.content.SharedPreferences;
import android.text.TextUtils;
+import com.android.inputmethod.keyboard.EmojiKeyboardView;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.utils.CollectionUtils;
import java.util.ArrayDeque;
-import java.util.Random;
+import java.util.Collection;
/**
* This is a Keyboard class where you can add keys dynamically shown in a grid layout
*/
-// TODO: Save/restore recent keys from/to preferences.
public class DynamicGridKeyboard extends Keyboard {
private static final int TEMPLATE_KEY_CODE_0 = 0x30;
private static final int TEMPLATE_KEY_CODE_1 = 0x31;
+ // Recent codes are saved as an integer array, so we use comma as a separater.
+ private static final String RECENT_KEY_SEPARATOR = Constants.STRING_COMMA;
+ private final SharedPreferences mPrefs;
private final int mLeftPadding;
private final int mHorizontalStep;
private final int mVerticalStep;
private final int mColumnsNum;
- private final int mMaxRecentKeyCount;
- private final ArrayDeque<RecentKey> mRecentKeys = CollectionUtils.newArrayDeque();
+ private final int mMaxKeyCount;
+ private final boolean mIsRecents;
+ private final ArrayDeque<GridKey> mGridKeys = CollectionUtils.newArrayDeque();
- private Key[] mCachedRecentKeys;
+ private Key[] mCachedGridKeys;
- public DynamicGridKeyboard(final Keyboard templateKeyboard) {
+ public DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templateKeyboard,
+ final int maxKeyCount, final int categoryId, final int categoryPageId) {
super(templateKeyboard);
final Key key0 = getTemplateKey(TEMPLATE_KEY_CODE_0);
final Key key1 = getTemplateKey(TEMPLATE_KEY_CODE_1);
@@ -50,8 +58,9 @@ public class DynamicGridKeyboard extends Keyboard {
mHorizontalStep = Math.abs(key1.getX() - key0.getX());
mVerticalStep = key0.getHeight() + mVerticalGap;
mColumnsNum = mBaseWidth / mHorizontalStep;
- final int rowsNum = mBaseHeight / mVerticalStep;
- mMaxRecentKeyCount = mColumnsNum * rowsNum;
+ mMaxKeyCount = maxKeyCount;
+ mIsRecents = categoryId == EmojiKeyboardView.CATEGORY_ID_RECENTS;
+ mPrefs = prefs;
}
private Key getTemplateKey(final int code) {
@@ -63,32 +72,67 @@ public class DynamicGridKeyboard extends Keyboard {
throw new RuntimeException("Can't find template key: code=" + code);
}
- private final Random random = new Random();
+ public void addKeyFirst(final Key usedKey) {
+ addKey(usedKey, true);
+ if (mIsRecents) {
+ saveRecentKeys();
+ }
+ }
+
+ public void addKeyLast(final Key usedKey) {
+ addKey(usedKey, false);
+ }
- public void addRecentKey(final Key usedKey) {
- synchronized (mRecentKeys) {
- mCachedRecentKeys = null;
- final RecentKey key = (usedKey instanceof RecentKey)
- ? (RecentKey)usedKey : new RecentKey(usedKey);
- while (mRecentKeys.remove(key)) {
+ private void addKey(final Key usedKey, final boolean addFirst) {
+ synchronized (mGridKeys) {
+ mCachedGridKeys = null;
+ final GridKey key = new GridKey(usedKey);
+ while (mGridKeys.remove(key)) {
// Remove duplicate keys.
}
- mRecentKeys.addFirst(key);
- while (mRecentKeys.size() > mMaxRecentKeyCount) {
- mRecentKeys.removeLast();
+ if (addFirst) {
+ mGridKeys.addFirst(key);
+ } else {
+ mGridKeys.addLast(key);
+ }
+ while (mGridKeys.size() > mMaxKeyCount) {
+ mGridKeys.removeLast();
}
int index = 0;
- for (final RecentKey recentKey : mRecentKeys) {
+ for (final GridKey gridKey : mGridKeys) {
final int keyX = getKeyX(index);
final int keyY = getKeyY(index);
- final int x = keyX+random.nextInt(recentKey.getWidth());
- final int y = keyY+random.nextInt(recentKey.getHeight());
- recentKey.updateCorrdinates(keyX, keyY);
+ gridKey.updateCorrdinates(keyX, keyY);
index++;
}
}
}
+ private void saveRecentKeys() {
+ final StringBuilder sb = new StringBuilder();
+ for (final Key key : mGridKeys) {
+ sb.append(key.getCode()).append(RECENT_KEY_SEPARATOR);
+ }
+ Settings.writeEmojiRecentKeys(mPrefs, sb.toString());
+ }
+
+ public void loadRecentKeys(Collection<DynamicGridKeyboard> keyboards) {
+ final String str = Settings.readEmojiRecentKeys(mPrefs);
+ for (String s : str.split(RECENT_KEY_SEPARATOR)) {
+ if (TextUtils.isEmpty(s)) {
+ continue;
+ }
+ final int code = Integer.valueOf(s);
+ for (DynamicGridKeyboard kbd : keyboards) {
+ final Key key = kbd.getKey(code);
+ if (key != null) {
+ addKeyLast(key);
+ break;
+ }
+ }
+ }
+ }
+
private int getKeyX(final int index) {
final int column = index % mColumnsNum;
return column * mHorizontalStep + mLeftPadding;
@@ -101,26 +145,26 @@ public class DynamicGridKeyboard extends Keyboard {
@Override
public Key[] getKeys() {
- synchronized (mRecentKeys) {
- if (mCachedRecentKeys != null) {
- return mCachedRecentKeys;
+ synchronized (mGridKeys) {
+ if (mCachedGridKeys != null) {
+ return mCachedGridKeys;
}
- mCachedRecentKeys = mRecentKeys.toArray(new Key[mRecentKeys.size()]);
- return mCachedRecentKeys;
+ mCachedGridKeys = mGridKeys.toArray(new Key[mGridKeys.size()]);
+ return mCachedGridKeys;
}
}
@Override
public Key[] getNearestKeys(final int x, final int y) {
- // TODO: Calculate the nearest key index in mRecentKeys from x and y.
+ // TODO: Calculate the nearest key index in mGridKeys from x and y.
return getKeys();
}
- static final class RecentKey extends Key {
+ static final class GridKey extends Key {
private int mCurrentX;
private int mCurrentY;
- public RecentKey(final Key originalKey) {
+ public GridKey(final Key originalKey) {
super(originalKey);
}
@@ -151,7 +195,7 @@ public class DynamicGridKeyboard extends Keyboard {
@Override
public String toString() {
- return "RecentKey: " + super.toString();
+ return "GridKey: " + super.toString();
}
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index 7008b0619..a72595f7c 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -383,7 +383,7 @@ public final class KeyboardTextsSet {
// Label for "switch to more symbol" modifier key. Must be short to fit on key!
/* 124 */ "= \\ <",
// Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key!
- /* 125 */ "~ [ {",
+ /* 125 */ "~ [ <",
// Label for "Tab" key. Must be short to fit on key!
/* 126 */ "Tab",
// Label for "switch to phone numeric" key. Must be short to fit on key!
@@ -2056,6 +2056,25 @@ public final class KeyboardTextsSet {
/* 45 */ "\u0410\u0411\u0412",
};
+ /* Language lo: Lao */
+ private static final String[] LANGUAGE_lo = {
+ /* 0~ */
+ 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,
+ /* ~44 */
+ // Label for "switch to alphabetic" key.
+ // U+0E81: "ກ" LAO LETTER KO
+ // U+0E82: "ຂ" LAO LETTER KHO SUNG
+ // U+0E84: "ຄ" LAO LETTER KHO TAM
+ /* 45 */ "\u0E81\u0E82\u0E84",
+ /* 46~ */
+ null, null, null, null, null,
+ /* ~50 */
+ // U+20AD: "₭" KIP SIGN
+ /* 51 */ "\u20AD",
+ };
+
/* Language lt: Lithuanian */
private static final String[] LANGUAGE_lt = {
// U+0105: "ą" LATIN SMALL LETTER A WITH OGONEK
@@ -2347,6 +2366,63 @@ public final class KeyboardTextsSet {
/* 47 */ "!text/double_9qm_rqm",
};
+ /* Language ne: Nepali */
+ private static final String[] LANGUAGE_ne = {
+ /* 0~ */
+ 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,
+ /* ~44 */
+ // Label for "switch to alphabetic" key.
+ // U+0915: "क" DEVANAGARI LETTER KA
+ // U+0916: "ख" DEVANAGARI LETTER KHA
+ // U+0917: "ग" DEVANAGARI LETTER GA
+ /* 45 */ "\u0915\u0916\u0917",
+ /* 46~ */
+ null, null, null, null, null,
+ /* ~50 */
+ // U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN
+ /* 51 */ "\u0930\u0941.",
+ /* 52~ */
+ null, null, null, null, null, null, null, null, null, null, null,
+ /* ~62 */
+ // U+0967: "१" DEVANAGARI DIGIT ONE
+ /* 63 */ "\u0967",
+ // U+0968: "२" DEVANAGARI DIGIT TWO
+ /* 64 */ "\u0968",
+ // U+0969: "३" DEVANAGARI DIGIT THREE
+ /* 65 */ "\u0969",
+ // U+096A: "४" DEVANAGARI DIGIT FOUR
+ /* 66 */ "\u096A",
+ // U+096B: "५" DEVANAGARI DIGIT FIVE
+ /* 67 */ "\u096B",
+ // U+096C: "६" DEVANAGARI DIGIT SIX
+ /* 68 */ "\u096C",
+ // U+096D: "७" DEVANAGARI DIGIT SEVEN
+ /* 69 */ "\u096D",
+ // U+096E: "८" DEVANAGARI DIGIT EIGHT
+ /* 70 */ "\u096E",
+ // U+096F: "९" DEVANAGARI DIGIT NINE
+ /* 71 */ "\u096F",
+ // U+0966: "०" DEVANAGARI DIGIT ZERO
+ /* 72 */ "\u0966",
+ // Label for "switch to symbols" key.
+ /* 73 */ "?\u0967\u0968\u0969",
+ // Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
+ // part because it'll be appended by the code.
+ /* 74 */ "\u0967\u0968\u0969",
+ /* 75 */ "1",
+ /* 76 */ "2",
+ /* 77 */ "3",
+ /* 78 */ "4",
+ /* 79 */ "5",
+ /* 80 */ "6",
+ /* 81 */ "7",
+ /* 82 */ "8",
+ /* 83 */ "9",
+ /* 84 */ "0",
+ };
+
/* Language nl: Dutch */
private static final String[] LANGUAGE_nl = {
// U+00E1: "á" LATIN SMALL LETTER A WITH ACUTE
@@ -3332,11 +3408,13 @@ public final class KeyboardTextsSet {
"ka", LANGUAGE_ka, /* Georgian */
"kk", LANGUAGE_kk, /* Kazakh */
"ky", LANGUAGE_ky, /* Kirghiz */
+ "lo", LANGUAGE_lo, /* Lao */
"lt", LANGUAGE_lt, /* Lithuanian */
"lv", LANGUAGE_lv, /* Latvian */
"mk", LANGUAGE_mk, /* Macedonian */
"mn", LANGUAGE_mn, /* Mongolian */
"nb", LANGUAGE_nb, /* Norwegian Bokmål */
+ "ne", LANGUAGE_ne, /* Nepali */
"nl", LANGUAGE_nl, /* Dutch */
"pl", LANGUAGE_pl, /* Polish */
"pt", LANGUAGE_pt, /* Portuguese */
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 8aec03f71..029ba02ed 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -220,7 +220,11 @@ public final class Constants {
}
}
+ public static final int MAX_INT_BIT_COUNT = 32;
+ public static final String STRING_COMMA = ",";
+
private Constants() {
// This utility class is not publicly instantiable.
}
+
}
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index 686c8d5f5..1a0fecc62 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -98,6 +98,10 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_SEND_FEEDBACK = "send_feedback";
public static final String PREF_ABOUT_KEYBOARD = "about_keyboard";
+ // Emoji
+ public static final String PREF_EMOJI_RECENT_KEYS = "emoji_recent_keys";
+ public static final String PREF_EMOJI_CATEGORY_LAST_TYPED_ID = "emoji_category_last_typed_id";
+
private Resources mRes;
private SharedPreferences mPrefs;
private SettingsValues mSettingsValues;
@@ -370,4 +374,24 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
final String tokenStr = mPrefs.getString(PREF_LAST_USED_PERSONALIZATION_TOKEN, null);
return StringUtils.hexStringToByteArray(tokenStr);
}
+
+ public static void writeEmojiRecentKeys(final SharedPreferences prefs, String str) {
+ prefs.edit().putString(PREF_EMOJI_RECENT_KEYS, str).apply();
+ }
+
+ public static String readEmojiRecentKeys(final SharedPreferences prefs) {
+ return prefs.getString(PREF_EMOJI_RECENT_KEYS, "");
+ }
+
+ public static void writeEmojiCategoryLastTypedId(
+ final SharedPreferences prefs, final int category, final int id) {
+ final String key = PREF_EMOJI_CATEGORY_LAST_TYPED_ID + category;
+ prefs.edit().putInt(key, id).apply();
+ }
+
+ public static int readEmojiCategoryLastTypedId(
+ final SharedPreferences prefs, final int category) {
+ final String key = PREF_EMOJI_CATEGORY_LAST_TYPED_ID + category;
+ return prefs.getInt(key, 0);
+ }
}
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index 4605890c7..89dfa39b3 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -292,7 +292,6 @@ static inline void prof_out(void) {
// of the binary dictionary where a {key,value} string pair scheme is used.
#define LARGEST_INT_DIGIT_COUNT 11
-#define NOT_A_VALID_WORD_POS (-99)
#define NOT_A_CODE_POINT (-1)
#define NOT_A_DISTANCE (-1)
#define NOT_A_COORDINATE (-1)
diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h
index cdd9f59aa..377015371 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node.h
@@ -112,7 +112,7 @@ class DicNode {
mIsUsed = true;
mIsCachedForNextSuggestion = false;
mDicNodeProperties.init(
- NOT_A_VALID_WORD_POS /* pos */, rootGroupPos, NOT_A_CODE_POINT /* nodeCodePoint */,
+ NOT_A_DICT_POS /* pos */, rootGroupPos, NOT_A_CODE_POINT /* nodeCodePoint */,
NOT_A_PROBABILITY /* probability */, false /* isTerminal */,
true /* hasChildren */, false /* isBlacklistedOrNotAWord */, 0 /* depth */,
0 /* terminalDepth */);
@@ -125,7 +125,7 @@ class DicNode {
mIsUsed = true;
mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion;
mDicNodeProperties.init(
- NOT_A_VALID_WORD_POS /* pos */, rootGroupPos, NOT_A_CODE_POINT /* nodeCodePoint */,
+ NOT_A_DICT_POS /* pos */, rootGroupPos, NOT_A_CODE_POINT /* nodeCodePoint */,
NOT_A_PROBABILITY /* probability */, false /* isTerminal */,
true /* hasChildren */, false /* isBlacklistedOrNotAWord */, 0 /* depth */,
0 /* terminalDepth */);
@@ -234,7 +234,7 @@ class DicNode {
}
bool isFirstWord() const {
- return mDicNodeState.mDicNodeStatePrevWord.getPrevWordNodePos() == NOT_A_VALID_WORD_POS;
+ return mDicNodeState.mDicNodeStatePrevWord.getPrevWordNodePos() == NOT_A_DICT_POS;
}
bool isCompletion(const int inputSize) const {
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
index e81591992..ec65114c7 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
+++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
@@ -89,7 +89,7 @@ namespace latinime {
const int unigramProbability = node->getProbability();
const int wordPos = node->getPos();
const int prevWordPos = node->getPrevWordPos();
- if (NOT_A_VALID_WORD_POS == wordPos || NOT_A_VALID_WORD_POS == prevWordPos) {
+ if (NOT_A_DICT_POS == wordPos || NOT_A_DICT_POS == prevWordPos) {
// Note: Normally wordPos comes from the dictionary and should never equal
// NOT_A_VALID_WORD_POS.
return dictionaryStructurePolicy->getProbability(unigramProbability,
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h
index 9bc96877e..b7af97018 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_state_prevword.h
@@ -29,7 +29,7 @@ class DicNodeStatePrevWord {
public:
AK_FORCE_INLINE DicNodeStatePrevWord()
: mPrevWordCount(0), mPrevWordLength(0), mPrevWordStart(0), mPrevWordProbability(0),
- mPrevWordNodePos(NOT_A_VALID_WORD_POS) {
+ mPrevWordNodePos(NOT_A_DICT_POS) {
memset(mPrevWord, 0, sizeof(mPrevWord));
memset(mPrevSpacePositions, 0, sizeof(mPrevSpacePositions));
}
@@ -41,7 +41,7 @@ class DicNodeStatePrevWord {
mPrevWordCount = 0;
mPrevWordStart = 0;
mPrevWordProbability = -1;
- mPrevWordNodePos = NOT_A_VALID_WORD_POS;
+ mPrevWordNodePos = NOT_A_DICT_POS;
memset(mPrevSpacePositions, 0, sizeof(mPrevSpacePositions));
}
diff --git a/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp b/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp
index cf1cd8815..425b07624 100644
--- a/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/bigram_dictionary.cpp
@@ -116,7 +116,7 @@ int BigramDictionary::getPredictions(const int *prevWord, const int prevWordLeng
mDictionaryStructurePolicy->getBigramsStructurePolicy(), pos);
while (bigramsIt.hasNext()) {
bigramsIt.next();
- if (bigramsIt.getBigramPos() == NOT_A_VALID_WORD_POS) {
+ if (bigramsIt.getBigramPos() == NOT_A_DICT_POS) {
continue;
}
const int codePointCount = mDictionaryStructurePolicy->
@@ -146,7 +146,7 @@ int BigramDictionary::getBigramListPositionForWord(const int *prevWord, const in
if (0 >= prevWordLength) return NOT_A_DICT_POS;
int pos = mDictionaryStructurePolicy->getTerminalNodePositionOfWord(prevWord, prevWordLength,
forceLowerCaseSearch);
- if (NOT_A_VALID_WORD_POS == pos) return NOT_A_DICT_POS;
+ if (NOT_A_DICT_POS == pos) return NOT_A_DICT_POS;
return mDictionaryStructurePolicy->getBigramsPositionOfNode(pos);
}
@@ -157,7 +157,7 @@ bool BigramDictionary::isValidBigram(const int *word0, int length0, const int *w
if (NOT_A_DICT_POS == pos) return false;
int nextWordPos = mDictionaryStructurePolicy->getTerminalNodePositionOfWord(word1, length1,
false /* forceLowerCaseSearch */);
- if (NOT_A_VALID_WORD_POS == nextWordPos) return false;
+ if (NOT_A_DICT_POS == nextWordPos) return false;
BinaryDictionaryBigramsIterator bigramsIt(
mDictionaryStructurePolicy->getBigramsStructurePolicy(), pos);
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index 02ece639c..29fe7ab94 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -87,7 +87,7 @@ int Dictionary::getBigrams(const int *word, int length, int *outWords, int *freq
int Dictionary::getProbability(const int *word, int length) const {
int pos = getDictionaryStructurePolicy()->getTerminalNodePositionOfWord(word, length,
false /* forceLowerCaseSearch */);
- if (NOT_A_VALID_WORD_POS == pos) {
+ if (NOT_A_DICT_POS == pos) {
return NOT_A_PROBABILITY;
}
return getDictionaryStructurePolicy()->getUnigramProbabilityOfPtNode(pos);
diff --git a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h
index 9efe5f6f9..aecf41386 100644
--- a/native/jni/src/suggest/core/dictionary/multi_bigram_map.h
+++ b/native/jni/src/suggest/core/dictionary/multi_bigram_map.h
@@ -73,7 +73,7 @@ class MultiBigramMap {
bigramsListPos);
while (bigramsIt.hasNext()) {
bigramsIt.next();
- if (bigramsIt.getBigramPos() == NOT_A_VALID_WORD_POS) {
+ if (bigramsIt.getBigramPos() == NOT_A_DICT_POS) {
continue;
}
mBigramMap[bigramsIt.getBigramPos()] = bigramsIt.getProbability();
diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.cpp b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
index 2c2259214..50f2bbd8d 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.cpp
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
@@ -35,13 +35,13 @@ void DicTraverseSession::init(const Dictionary *const dictionary, const int *pre
->getMultiWordCostMultiplier();
mSuggestOptions = suggestOptions;
if (!prevWord) {
- mPrevWordPos = NOT_A_VALID_WORD_POS;
+ mPrevWordPos = NOT_A_DICT_POS;
return;
}
// TODO: merge following similar calls to getTerminalPosition into one case-insensitive call.
mPrevWordPos = getDictionaryStructurePolicy()->getTerminalNodePositionOfWord(
prevWord, prevWordLength, false /* forceLowerCaseSearch */);
- if (mPrevWordPos == NOT_A_VALID_WORD_POS) {
+ if (mPrevWordPos == NOT_A_DICT_POS) {
// Check bigrams for lower-cased previous word if original was not found. Useful for
// auto-capitalized words like "The [current_word]".
mPrevWordPos = getDictionaryStructurePolicy()->getTerminalNodePositionOfWord(
diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.h b/native/jni/src/suggest/core/session/dic_traverse_session.h
index fe8893590..e2ef5fc76 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.h
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.h
@@ -59,7 +59,7 @@ class DicTraverseSession {
}
AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr, bool usesLargeCache)
- : mPrevWordPos(NOT_A_VALID_WORD_POS), mProximityInfo(0),
+ : mPrevWordPos(NOT_A_DICT_POS), mProximityInfo(0),
mDictionary(0), mSuggestOptions(0), mDicNodesCache(usesLargeCache),
mMultiBigramMap(), mInputSize(0), mPartiallyCommited(false), mMaxPointerCount(1),
mMultiWordCostMultiplier(1.0f) {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp
index d57547445..09e832f07 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.cpp
@@ -38,6 +38,22 @@ const BigramListReadWriteUtils::BigramFlags
BigramListReadWriteUtils::MASK_ATTRIBUTE_PROBABILITY = 0x0F;
const int BigramListReadWriteUtils::ATTRIBUTE_ADDRESS_SHIFT = 4;
+/* static */ BigramListReadWriteUtils::BigramFlags
+ BigramListReadWriteUtils::getFlagsAndForwardPointer(const uint8_t *const bigramsBuf,
+ int *const pos) {
+ return ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf, pos);
+}
+
+/* static */ void BigramListReadWriteUtils::skipExistingBigrams(const uint8_t *const bigramsBuf,
+ int *const pos) {
+ BigramFlags flags = getFlagsAndForwardPointer(bigramsBuf, pos);
+ while (hasNext(flags)) {
+ *pos += attributeAddressSize(flags);
+ flags = getFlagsAndForwardPointer(bigramsBuf, pos);
+ }
+ *pos += attributeAddressSize(flags);
+}
+
/* static */ int BigramListReadWriteUtils::getBigramAddressAndForwardPointer(
const uint8_t *const bigramsBuf, const BigramFlags flags, int *const pos) {
int offset = 0;
@@ -54,7 +70,7 @@ const int BigramListReadWriteUtils::ATTRIBUTE_ADDRESS_SHIFT = 4;
break;
}
if (offset == 0) {
- return NOT_A_VALID_WORD_POS;
+ return NOT_A_DICT_POS;
}
if (isOffsetNegative(flags)) {
return origin - offset;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h
index ee2b722a4..9a930747c 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h
@@ -21,7 +21,6 @@
#include <stdint.h>
#include "defines.h"
-#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
namespace latinime {
@@ -29,10 +28,7 @@ class BigramListReadWriteUtils {
public:
typedef uint8_t BigramFlags;
- static AK_FORCE_INLINE BigramFlags getFlagsAndForwardPointer(
- const uint8_t *const bigramsBuf, int *const pos) {
- return ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf, pos);
- }
+ static BigramFlags getFlagsAndForwardPointer(const uint8_t *const bigramsBuf, int *const pos);
static AK_FORCE_INLINE int getProbabilityFromFlags(const BigramFlags flags) {
return flags & MASK_ATTRIBUTE_PROBABILITY;
@@ -43,15 +39,7 @@ public:
}
// Bigrams reading methods
- static AK_FORCE_INLINE void skipExistingBigrams(const uint8_t *const bigramsBuf,
- int *const pos) {
- BigramFlags flags = getFlagsAndForwardPointer(bigramsBuf, pos);
- while (hasNext(flags)) {
- *pos += attributeAddressSize(flags);
- flags = getFlagsAndForwardPointer(bigramsBuf, pos);
- }
- *pos += attributeAddressSize(flags);
- }
+ static void skipExistingBigrams(const uint8_t *const bigramsBuf, int *const pos);
static int getBigramAddressAndForwardPointer(const uint8_t *const bigramsBuf,
const BigramFlags flags, int *const pos);
@@ -79,7 +67,7 @@ public:
const int entryPos, const int targetPos, const int probability, const bool hasNext,
BigramFlags *const outBigramFlags, uint32_t *const outOffset,
int *const outOffsetFieldSize) {
- if (targetPos == NOT_A_VALID_WORD_POS) {
+ if (targetPos == NOT_A_DICT_POS) {
return false;
}
BigramFlags flags = probability & MASK_ATTRIBUTE_PROBABILITY;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp
index 4ee138125..ca3b64da1 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp
@@ -31,7 +31,7 @@ void DynamicBigramListPolicy::getNextBigram(int *const outBigramPos, int *const
BigramListReadWriteUtils::getFlagsAndForwardPointer(buffer, pos);
int originalBigramPos = BigramListReadWriteUtils::getBigramAddressAndForwardPointer(
buffer, flags, pos);
- if (usesAdditionalBuffer && originalBigramPos != NOT_A_VALID_WORD_POS) {
+ if (usesAdditionalBuffer && originalBigramPos != NOT_A_DICT_POS) {
originalBigramPos += mBuffer->getOriginalBufferSize();
}
*outBigramPos = followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos);
@@ -66,7 +66,7 @@ bool DynamicBigramListPolicy::copyAllBigrams(int *const fromPos, int *const toPo
flags = BigramListReadWriteUtils::getFlagsAndForwardPointer(buffer, fromPos);
int originalBigramPos = BigramListReadWriteUtils::getBigramAddressAndForwardPointer(
buffer, flags, fromPos);
- if (originalBigramPos == NOT_A_VALID_WORD_POS) {
+ if (originalBigramPos == NOT_A_DICT_POS) {
// skip invalid bigram entry.
continue;
}
@@ -172,7 +172,7 @@ bool DynamicBigramListPolicy::removeBigram(const int bigramListPos, const int ta
}
int originalBigramPos = BigramListReadWriteUtils::getBigramAddressAndForwardPointer(
buffer, flags, &pos);
- if (usesAdditionalBuffer && originalBigramPos != NOT_A_VALID_WORD_POS) {
+ if (usesAdditionalBuffer && originalBigramPos != NOT_A_DICT_POS) {
originalBigramPos += mBuffer->getOriginalBufferSize();
}
const int bigramPos = followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos);
@@ -192,8 +192,8 @@ bool DynamicBigramListPolicy::removeBigram(const int bigramListPos, const int ta
int DynamicBigramListPolicy::followBigramLinkAndGetCurrentBigramPtNodePos(
const int originalBigramPos) const {
- if (originalBigramPos == NOT_A_VALID_WORD_POS) {
- return NOT_A_VALID_WORD_POS;
+ if (originalBigramPos == NOT_A_DICT_POS) {
+ return NOT_A_DICT_POS;
}
int currentPos = originalBigramPos;
DynamicPatriciaTrieNodeReader nodeReader(mBuffer, this /* bigramsPolicy */, mShortcutPolicy);
@@ -206,7 +206,7 @@ int DynamicBigramListPolicy::followBigramLinkAndGetCurrentBigramPtNodePos(
if (bigramLinkCount > BIGRAM_LINK_COUNT_LIMIT) {
AKLOGI("Bigram link is invalid. start position: %d", bigramPos);
ASSERT(false);
- return NOT_A_VALID_WORD_POS;
+ return NOT_A_DICT_POS;
}
}
return currentPos;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp
index 56ef60ae4..e455080d7 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp
@@ -25,6 +25,13 @@ namespace latinime {
void DynamicPatriciaTrieNodeReader::fetchNodeInfoFromBufferAndProcessMovedNode(const int nodePos,
const int maxCodePointCount, int *const outCodePoints) {
+ if (nodePos < 0 || nodePos >= mBuffer->getTailPosition()) {
+ AKLOGE("Fetching PtNode info form invalid dictionary position: %d, dictionary size: %d",
+ nodePos, mBuffer->getTailPosition());
+ ASSERT(false);
+ invalidatePtNodeInfo();
+ return;
+ }
const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(nodePos);
const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer);
int pos = nodePos;
@@ -62,7 +69,7 @@ void DynamicPatriciaTrieNodeReader::fetchNodeInfoFromBufferAndProcessMovedNode(c
if (usesAdditionalBuffer && mChildrenPos != NOT_A_DICT_POS) {
mChildrenPos += mBuffer->getOriginalBufferSize();
}
- if (mSiblingPos == NOT_A_VALID_WORD_POS && DynamicPatriciaTrieReadingUtils::isMoved(mFlags)) {
+ if (mSiblingPos == NOT_A_DICT_POS && DynamicPatriciaTrieReadingUtils::isMoved(mFlags)) {
mBigramLinkedNodePos = mChildrenPos;
} else {
mBigramLinkedNodePos = NOT_A_DICT_POS;
@@ -83,7 +90,7 @@ void DynamicPatriciaTrieNodeReader::fetchNodeInfoFromBufferAndProcessMovedNode(c
mBigramPos = NOT_A_DICT_POS;
}
// Update siblingPos if needed.
- if (mSiblingPos == NOT_A_VALID_WORD_POS) {
+ if (mSiblingPos == NOT_A_DICT_POS) {
// Sibling position is the tail position of current node.
mSiblingPos = pos;
}
@@ -94,4 +101,19 @@ void DynamicPatriciaTrieNodeReader::fetchNodeInfoFromBufferAndProcessMovedNode(c
}
}
+void DynamicPatriciaTrieNodeReader::invalidatePtNodeInfo() {
+ mHeadPos = NOT_A_DICT_POS;
+ mFlags = 0;
+ mParentPos = NOT_A_DICT_POS;
+ mCodePointCount = 0;
+ mProbabilityFieldPos = NOT_A_DICT_POS;
+ mProbability = NOT_A_PROBABILITY;
+ mChildrenPosFieldPos = NOT_A_DICT_POS;
+ mChildrenPos = NOT_A_DICT_POS;
+ mBigramLinkedNodePos = NOT_A_DICT_POS;
+ mShortcutPos = NOT_A_DICT_POS;
+ mBigramPos = NOT_A_DICT_POS;
+ mSiblingPos = NOT_A_DICT_POS;
+}
+
}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h
index 89d38a590..6ef5f5813 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h
@@ -39,12 +39,12 @@ class DynamicPatriciaTrieNodeReader {
const DictionaryBigramsStructurePolicy *const bigramsPolicy,
const DictionaryShortcutsStructurePolicy *const shortcutsPolicy)
: mBuffer(buffer), mBigramsPolicy(bigramsPolicy),
- mShortcutsPolicy(shortcutsPolicy), mHeadPos(NOT_A_VALID_WORD_POS), mFlags(0),
+ mShortcutsPolicy(shortcutsPolicy), mHeadPos(NOT_A_DICT_POS), mFlags(0),
mParentPos(NOT_A_DICT_POS), mCodePointCount(0), mProbabilityFieldPos(NOT_A_DICT_POS),
mProbability(NOT_A_PROBABILITY), mChildrenPosFieldPos(NOT_A_DICT_POS),
mChildrenPos(NOT_A_DICT_POS), mBigramLinkedNodePos(NOT_A_DICT_POS),
mShortcutPos(NOT_A_DICT_POS), mBigramPos(NOT_A_DICT_POS),
- mSiblingPos(NOT_A_VALID_WORD_POS) {}
+ mSiblingPos(NOT_A_DICT_POS) {}
~DynamicPatriciaTrieNodeReader() {}
@@ -56,7 +56,7 @@ class DynamicPatriciaTrieNodeReader {
AK_FORCE_INLINE void fetchNodeInfoFromBufferAndGetNodeCodePoints(const int nodePos,
const int maxCodePointCount, int *const outCodePoints) {
- mSiblingPos = NOT_A_VALID_WORD_POS;
+ mSiblingPos = NOT_A_DICT_POS;
mBigramLinkedNodePos = NOT_A_DICT_POS;
fetchNodeInfoFromBufferAndProcessMovedNode(nodePos, maxCodePointCount, outCodePoints);
}
@@ -156,6 +156,8 @@ class DynamicPatriciaTrieNodeReader {
void fetchNodeInfoFromBufferAndProcessMovedNode(const int nodePos, const int maxCodePointCount,
int *const outCodePoints);
+
+ void invalidatePtNodeInfo();
};
} // namespace latinime
#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_NODE_READER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
index ece1781f1..cccc09041 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp
@@ -116,7 +116,7 @@ int DynamicPatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const in
if (!readingHelper.isMatchedCodePoint(
j, searchCodePoints[matchedCodePointCount + j])) {
// Different code point is found. The given word is not included in the dictionary.
- return NOT_A_VALID_WORD_POS;
+ return NOT_A_DICT_POS;
}
}
// All characters are matched.
@@ -125,14 +125,14 @@ int DynamicPatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const in
return nodeReader->getHeadPos();
}
if (!nodeReader->hasChildren()) {
- return NOT_A_VALID_WORD_POS;
+ return NOT_A_DICT_POS;
}
// Advance to the children nodes.
readingHelper.readChildNode();
}
// If we already traversed the tree further than the word is long, there means
// there was no match (or we would have found it).
- return NOT_A_VALID_WORD_POS;
+ return NOT_A_DICT_POS;
}
int DynamicPatriciaTriePolicy::getProbability(const int unigramProbability,
@@ -149,7 +149,7 @@ int DynamicPatriciaTriePolicy::getProbability(const int unigramProbability,
}
int DynamicPatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int nodePos) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
+ if (nodePos == NOT_A_DICT_POS) {
return NOT_A_PROBABILITY;
}
DynamicPatriciaTrieNodeReader nodeReader(&mBufferWithExtendableBuffer,
@@ -162,7 +162,7 @@ int DynamicPatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int nodePos)
}
int DynamicPatriciaTriePolicy::getShortcutPositionOfNode(const int nodePos) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
+ if (nodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
}
DynamicPatriciaTrieNodeReader nodeReader(&mBufferWithExtendableBuffer,
@@ -175,7 +175,7 @@ int DynamicPatriciaTriePolicy::getShortcutPositionOfNode(const int nodePos) cons
}
int DynamicPatriciaTriePolicy::getBigramsPositionOfNode(const int nodePos) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
+ if (nodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
}
DynamicPatriciaTrieNodeReader nodeReader(&mBufferWithExtendableBuffer,
@@ -209,12 +209,12 @@ bool DynamicPatriciaTriePolicy::addBigramWords(const int *const word0, const int
}
const int word0Pos = getTerminalNodePositionOfWord(word0, length0,
false /* forceLowerCaseSearch */);
- if (word0Pos == NOT_A_VALID_WORD_POS) {
+ if (word0Pos == NOT_A_DICT_POS) {
return false;
}
const int word1Pos = getTerminalNodePositionOfWord(word1, length1,
false /* forceLowerCaseSearch */);
- if (word1Pos == NOT_A_VALID_WORD_POS) {
+ if (word1Pos == NOT_A_DICT_POS) {
return false;
}
DynamicPatriciaTrieWritingHelper writingHelper(&mBufferWithExtendableBuffer,
@@ -230,12 +230,12 @@ bool DynamicPatriciaTriePolicy::removeBigramWords(const int *const word0, const
}
const int word0Pos = getTerminalNodePositionOfWord(word0, length0,
false /* forceLowerCaseSearch */);
- if (word0Pos == NOT_A_VALID_WORD_POS) {
+ if (word0Pos == NOT_A_DICT_POS) {
return false;
}
const int word1Pos = getTerminalNodePositionOfWord(word1, length1,
false /* forceLowerCaseSearch */);
- if (word1Pos == NOT_A_VALID_WORD_POS) {
+ if (word1Pos == NOT_A_DICT_POS) {
return false;
}
DynamicPatriciaTrieWritingHelper writingHelper(&mBufferWithExtendableBuffer,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h
index db1c392bb..120fd7699 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h
@@ -72,8 +72,7 @@ class DynamicPatriciaTrieReadingHelper {
// Initialize reading state with the head position of a node.
AK_FORCE_INLINE void initWithNodePos(const int nodePos) {
- // TODO: Consolidate NOT_A_VALID_WORD_POS and NOT_A_DICT_POS
- if (nodePos == NOT_A_VALID_WORD_POS || nodePos == NOT_A_DICT_POS) {
+ if (nodePos == NOT_A_DICT_POS) {
mPos = NOT_A_DICT_POS;
} else {
mIsError = false;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.cpp
index c7e89fff8..8428c0b15 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.cpp
@@ -28,6 +28,17 @@ const DptReadingUtils::NodeFlags DptReadingUtils::FLAG_IS_NOT_MOVED = 0xC0;
const DptReadingUtils::NodeFlags DptReadingUtils::FLAG_IS_MOVED = 0x40;
const DptReadingUtils::NodeFlags DptReadingUtils::FLAG_IS_DELETED = 0x80;
+/* static */ int DptReadingUtils::getForwardLinkPosition(const uint8_t *const buffer,
+ const int pos) {
+ int linkAddressPos = pos;
+ return ByteArrayUtils::readSint24AndAdvancePosition(buffer, &linkAddressPos);
+}
+
+/* static */ int DptReadingUtils::getParentPosAndAdvancePosition(const uint8_t *const buffer,
+ int *const pos) {
+ return ByteArrayUtils::readSint24AndAdvancePosition(buffer, pos);
+}
+
/* static */ int DptReadingUtils::readChildrenPositionAndAdvancePosition(
const uint8_t *const buffer, int *const pos) {
const int base = *pos;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h
index 5a2ad9cb9..db5f9b1bd 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_utils.h
@@ -20,7 +20,6 @@
#include <stdint.h>
#include "defines.h"
-#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
namespace latinime {
@@ -28,19 +27,13 @@ class DynamicPatriciaTrieReadingUtils {
public:
typedef uint8_t NodeFlags;
- static AK_FORCE_INLINE int getForwardLinkPosition(const uint8_t *const buffer, const int pos) {
- int linkAddressPos = pos;
- return ByteArrayUtils::readSint24AndAdvancePosition(buffer, &linkAddressPos);
- }
+ static int getForwardLinkPosition(const uint8_t *const buffer, const int pos);
static AK_FORCE_INLINE bool isValidForwardLinkPosition(const int forwardLinkAddress) {
return forwardLinkAddress != 0;
}
- static AK_FORCE_INLINE int getParentPosAndAdvancePosition(const uint8_t *const buffer,
- int *const pos) {
- return ByteArrayUtils::readSint24AndAdvancePosition(buffer, pos);
- }
+ static int getParentPosAndAdvancePosition(const uint8_t *const buffer, int *const pos);
static int readChildrenPositionAndAdvancePosition(const uint8_t *const buffer, int *const pos);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp
index d5a83a938..e6cff431b 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_policy.cpp
@@ -219,7 +219,7 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
}
// This function gets the position of the terminal node of the exact matching word in the
-// dictionary. If no match is found, it returns NOT_A_VALID_WORD_POS.
+// dictionary. If no match is found, it returns NOT_A_DICT_POS.
int PatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const inWord,
const int length, const bool forceLowerCaseSearch) const {
int pos = getRootPosition();
@@ -228,7 +228,7 @@ int PatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const inWord,
while (true) {
// If we already traversed the tree further than the word is long, there means
// there was no match (or we would have found it).
- if (wordPos >= length) return NOT_A_VALID_WORD_POS;
+ if (wordPos >= length) return NOT_A_DICT_POS;
int ptNodeCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(mDictRoot,
&pos);
const int wChar = forceLowerCaseSearch
@@ -236,7 +236,7 @@ int PatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const inWord,
while (true) {
// If there are no more PtNodes in this array, it means we could not
// find a matching character for this depth, therefore there is no match.
- if (0 >= ptNodeCount) return NOT_A_VALID_WORD_POS;
+ if (0 >= ptNodeCount) return NOT_A_DICT_POS;
const int ptNodePos = pos;
const PatriciaTrieReadingUtils::NodeFlags flags =
PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
@@ -245,7 +245,7 @@ int PatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const inWord,
if (character == wChar) {
// This is the correct PtNode. Only one PtNode may start with the same char within
// a PtNode array, so either we found our match in this array, or there is
- // no match and we can return NOT_A_VALID_WORD_POS. So we will check all the
+ // no match and we can return NOT_A_DICT_POS. So we will check all the
// characters in this PtNode indeed does match.
if (PatriciaTrieReadingUtils::hasMultipleChars(flags)) {
character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(mDictRoot,
@@ -256,8 +256,8 @@ int PatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const inWord,
// character that does not match, as explained above, it means the word is
// not in the dictionary (by virtue of this PtNode being the only one to
// match the word on the first character, but not matching the whole word).
- if (wordPos >= length) return NOT_A_VALID_WORD_POS;
- if (inWord[wordPos] != character) return NOT_A_VALID_WORD_POS;
+ if (wordPos >= length) return NOT_A_DICT_POS;
+ if (inWord[wordPos] != character) return NOT_A_DICT_POS;
character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
mDictRoot, &pos);
}
@@ -274,7 +274,7 @@ int PatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const inWord,
PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos);
}
if (!PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) {
- return NOT_A_VALID_WORD_POS;
+ return NOT_A_DICT_POS;
}
// We have children and we are still shorter than the word we are searching for, so
// we need to traverse children. Put the pointer on the children position, and
@@ -320,7 +320,7 @@ int PatriciaTriePolicy::getProbability(const int unigramProbability,
}
int PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int nodePos) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
+ if (nodePos == NOT_A_DICT_POS) {
return NOT_A_PROBABILITY;
}
int pos = nodePos;
@@ -342,7 +342,7 @@ int PatriciaTriePolicy::getUnigramProbabilityOfPtNode(const int nodePos) const {
}
int PatriciaTriePolicy::getShortcutPositionOfNode(const int nodePos) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
+ if (nodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
}
int pos = nodePos;
@@ -362,7 +362,7 @@ int PatriciaTriePolicy::getShortcutPositionOfNode(const int nodePos) const {
}
int PatriciaTriePolicy::getBigramsPositionOfNode(const int nodePos) const {
- if (nodePos == NOT_A_VALID_WORD_POS) {
+ if (nodePos == NOT_A_DICT_POS) {
return NOT_A_DICT_POS;
}
int pos = nodePos;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.cpp
index 576a158bc..1316b425f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.cpp
@@ -42,6 +42,63 @@ const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_IS_NOT_A_WORD = 0x02;
// Flag for blacklist
const PtReadingUtils::NodeFlags PtReadingUtils::FLAG_IS_BLACKLISTED = 0x01;
+/* static */ int PtReadingUtils::getPtNodeArraySizeAndAdvancePosition(
+ const uint8_t *const buffer, int *const pos) {
+ const uint8_t firstByte = ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
+ if (firstByte < 0x80) {
+ return firstByte;
+ } else {
+ return ((firstByte & 0x7F) << 8) ^ ByteArrayUtils::readUint8AndAdvancePosition(
+ buffer, pos);
+ }
+}
+
+/* static */ PtReadingUtils::NodeFlags PtReadingUtils::getFlagsAndAdvancePosition(
+ const uint8_t *const buffer, int *const pos) {
+ return ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
+}
+
+/* static */ int PtReadingUtils::getCodePointAndAdvancePosition(const uint8_t *const buffer,
+ int *const pos) {
+ return ByteArrayUtils::readCodePointAndAdvancePosition(buffer, pos);
+}
+
+// Returns the number of read characters.
+/* static */ int PtReadingUtils::getCharsAndAdvancePosition(const uint8_t *const buffer,
+ const NodeFlags flags, const int maxLength, int *const outBuffer, int *const pos) {
+ int length = 0;
+ if (hasMultipleChars(flags)) {
+ length = ByteArrayUtils::readStringAndAdvancePosition(buffer, maxLength, outBuffer,
+ pos);
+ } else {
+ if (maxLength > 0) {
+ outBuffer[0] = getCodePointAndAdvancePosition(buffer, pos);
+ length = 1;
+ }
+ }
+ return length;
+}
+
+// Returns the number of skipped characters.
+/* static */ int PtReadingUtils::skipCharacters(const uint8_t *const buffer, const NodeFlags flags,
+ const int maxLength, int *const pos) {
+ if (hasMultipleChars(flags)) {
+ return ByteArrayUtils::advancePositionToBehindString(buffer, maxLength, pos);
+ } else {
+ if (maxLength > 0) {
+ getCodePointAndAdvancePosition(buffer, pos);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+/* static */ int PtReadingUtils::readProbabilityAndAdvancePosition(const uint8_t *const buffer,
+ int *const pos) {
+ return ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
+}
+
/* static */ int PtReadingUtils::readChildrenPositionAndAdvancePosition(
const uint8_t *const buffer, const NodeFlags flags, int *const pos) {
const int base = *pos;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.h
index 2b0646db2..8420ee95a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/patricia_trie_reading_utils.h
@@ -20,7 +20,6 @@
#include <stdint.h>
#include "defines.h"
-#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
namespace latinime {
@@ -28,62 +27,21 @@ class PatriciaTrieReadingUtils {
public:
typedef uint8_t NodeFlags;
- static AK_FORCE_INLINE int getPtNodeArraySizeAndAdvancePosition(
- const uint8_t *const buffer, int *const pos) {
- const uint8_t firstByte = ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
- if (firstByte < 0x80) {
- return firstByte;
- } else {
- return ((firstByte & 0x7F) << 8) ^ ByteArrayUtils::readUint8AndAdvancePosition(
- buffer, pos);
- }
- }
+ static int getPtNodeArraySizeAndAdvancePosition(const uint8_t *const buffer, int *const pos);
- static AK_FORCE_INLINE NodeFlags getFlagsAndAdvancePosition(const uint8_t *const buffer,
- int *const pos) {
- return ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
- }
+ static NodeFlags getFlagsAndAdvancePosition(const uint8_t *const buffer, int *const pos);
- static AK_FORCE_INLINE int getCodePointAndAdvancePosition(const uint8_t *const buffer,
- int *const pos) {
- return ByteArrayUtils::readCodePointAndAdvancePosition(buffer, pos);
- }
+ static int getCodePointAndAdvancePosition(const uint8_t *const buffer, int *const pos);
// Returns the number of read characters.
- static AK_FORCE_INLINE int getCharsAndAdvancePosition(const uint8_t *const buffer,
- const NodeFlags flags, const int maxLength, int *const outBuffer, int *const pos) {
- int length = 0;
- if (hasMultipleChars(flags)) {
- length = ByteArrayUtils::readStringAndAdvancePosition(buffer, maxLength, outBuffer,
- pos);
- } else {
- if (maxLength > 0) {
- outBuffer[0] = getCodePointAndAdvancePosition(buffer, pos);
- length = 1;
- }
- }
- return length;
- }
+ static int getCharsAndAdvancePosition(const uint8_t *const buffer, const NodeFlags flags,
+ const int maxLength, int *const outBuffer, int *const pos);
// Returns the number of skipped characters.
- static AK_FORCE_INLINE int skipCharacters(const uint8_t *const buffer, const NodeFlags flags,
- const int maxLength, int *const pos) {
- if (hasMultipleChars(flags)) {
- return ByteArrayUtils::advancePositionToBehindString(buffer, maxLength, pos);
- } else {
- if (maxLength > 0) {
- getCodePointAndAdvancePosition(buffer, pos);
- return 1;
- } else {
- return 0;
- }
- }
- }
+ static int skipCharacters(const uint8_t *const buffer, const NodeFlags flags,
+ const int maxLength, int *const pos);
- static AK_FORCE_INLINE int readProbabilityAndAdvancePosition(const uint8_t *const buffer,
- int *const pos) {
- return ByteArrayUtils::readUint8AndAdvancePosition(buffer, pos);
- }
+ static int readProbabilityAndAdvancePosition(const uint8_t *const buffer, int *const pos);
static int readChildrenPositionAndAdvancePosition(const uint8_t *const buffer,
const NodeFlags flags, int *const pos);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.cpp
index e70bb5071..847dcdee5 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.cpp
@@ -16,6 +16,8 @@
#include "suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h"
+#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
+
namespace latinime {
// Flag for presence of more attributes
@@ -28,4 +30,22 @@ const int ShortcutListReadingUtils::SHORTCUT_LIST_SIZE_FIELD_SIZE = 2;
// The numeric value of the shortcut probability that means 'whitelist'.
const int ShortcutListReadingUtils::WHITELIST_SHORTCUT_PROBABILITY = 15;
+/* static */ ShortcutListReadingUtils::ShortcutFlags
+ ShortcutListReadingUtils::getFlagsAndForwardPointer(const uint8_t *const dictRoot,
+ int *const pos) {
+ return ByteArrayUtils::readUint8AndAdvancePosition(dictRoot, pos);
+}
+
+/* static */ int ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(
+ const uint8_t *const dictRoot, int *const pos) {
+ // readUint16andAdvancePosition() returns an offset *including* the uint16 field itself.
+ return ByteArrayUtils::readUint16AndAdvancePosition(dictRoot, pos)
+ - SHORTCUT_LIST_SIZE_FIELD_SIZE;
+}
+
+/* static */ int ShortcutListReadingUtils::readShortcutTarget(
+ const uint8_t *const dictRoot, const int maxLength, int *const outWord, int *const pos) {
+ return ByteArrayUtils::readStringAndAdvancePosition(dictRoot, maxLength, outWord, pos);
+}
+
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h
index 5f4f240f5..a83ed5a50 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/shortcut/shortcut_list_reading_utils.h
@@ -20,7 +20,6 @@
#include <stdint.h>
#include "defines.h"
-#include "suggest/policyimpl/dictionary/utils/byte_array_utils.h"
namespace latinime {
@@ -28,10 +27,7 @@ class ShortcutListReadingUtils {
public:
typedef uint8_t ShortcutFlags;
- static AK_FORCE_INLINE ShortcutFlags getFlagsAndForwardPointer(
- const uint8_t *const dictRoot, int *const pos) {
- return ByteArrayUtils::readUint8AndAdvancePosition(dictRoot, pos);
- }
+ static ShortcutFlags getFlagsAndForwardPointer(const uint8_t *const dictRoot, int *const pos);
static AK_FORCE_INLINE int getProbabilityFromFlags(const ShortcutFlags flags) {
return flags & MASK_ATTRIBUTE_PROBABILITY;
@@ -43,12 +39,7 @@ class ShortcutListReadingUtils {
// This method returns the size of the shortcut list region excluding the shortcut list size
// field at the beginning.
- static AK_FORCE_INLINE int getShortcutListSizeAndForwardPointer(
- const uint8_t *const dictRoot, int *const pos) {
- // readUint16andAdvancePosition() returns an offset *including* the uint16 field itself.
- return ByteArrayUtils::readUint16AndAdvancePosition(dictRoot, pos)
- - SHORTCUT_LIST_SIZE_FIELD_SIZE;
- }
+ static int getShortcutListSizeAndForwardPointer(const uint8_t *const dictRoot, int *const pos);
static AK_FORCE_INLINE int getShortcutListSizeFieldSize() {
return SHORTCUT_LIST_SIZE_FIELD_SIZE;
@@ -63,11 +54,8 @@ class ShortcutListReadingUtils {
return getProbabilityFromFlags(flags) == WHITELIST_SHORTCUT_PROBABILITY;
}
- static AK_FORCE_INLINE int readShortcutTarget(
- const uint8_t *const dictRoot, const int maxLength, int *const outWord,
- int *const pos) {
- return ByteArrayUtils::readStringAndAdvancePosition(dictRoot, maxLength, outWord, pos);
- }
+ static int readShortcutTarget(const uint8_t *const dictRoot, const int maxLength,
+ int *const outWord, int *const pos);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ShortcutListReadingUtils);
diff --git a/tools/make-keyboard-text/res/values-lo/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-lo/donottranslate-more-keys.xml
new file mode 100644
index 000000000..1d8ffa8cf
--- /dev/null
+++ b/tools/make-keyboard-text/res/values-lo/donottranslate-more-keys.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Label for "switch to alphabetic" key.
+ U+0E81: "ກ" LAO LETTER KO
+ U+0E82: "ຂ" LAO LETTER KHO SUNG
+ U+0E84: "ຄ" LAO LETTER KHO TAM -->
+ <string name="label_to_alpha_key">&#x0E81;&#x0E82;&#x0E84;</string>
+ <!-- U+20AD: "₭" KIP SIGN -->
+ <string name="keylabel_for_currency">&#x20AD;</string>
+</resources>
diff --git a/tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.xml
new file mode 100644
index 000000000..9205e5309
--- /dev/null
+++ b/tools/make-keyboard-text/res/values-ne/donottranslate-more-keys.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2013, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Label for "switch to alphabetic" key.
+ U+0915: "क" DEVANAGARI LETTER KA
+ U+0916: "ख" DEVANAGARI LETTER KHA
+ U+0917: "ग" DEVANAGARI LETTER GA -->
+ <string name="label_to_alpha_key">&#x0915;&#x0916;&#x0917;</string>
+ <!-- U+0967: "१" DEVANAGARI DIGIT ONE -->
+ <string name="keylabel_for_symbols_1">&#x0967;</string>
+ <!-- U+0968: "२" DEVANAGARI DIGIT TWO -->
+ <string name="keylabel_for_symbols_2">&#x0968;</string>
+ <!-- U+0969: "३" DEVANAGARI DIGIT THREE -->
+ <string name="keylabel_for_symbols_3">&#x0969;</string>
+ <!-- U+096A: "४" DEVANAGARI DIGIT FOUR -->
+ <string name="keylabel_for_symbols_4">&#x096A;</string>
+ <!-- U+096B: "५" DEVANAGARI DIGIT FIVE -->
+ <string name="keylabel_for_symbols_5">&#x096B;</string>
+ <!-- U+096C: "६" DEVANAGARI DIGIT SIX -->
+ <string name="keylabel_for_symbols_6">&#x096C;</string>
+ <!-- U+096D: "७" DEVANAGARI DIGIT SEVEN -->
+ <string name="keylabel_for_symbols_7">&#x096D;</string>
+ <!-- U+096E: "८" DEVANAGARI DIGIT EIGHT -->
+ <string name="keylabel_for_symbols_8">&#x096E;</string>
+ <!-- U+096F: "९" DEVANAGARI DIGIT NINE -->
+ <string name="keylabel_for_symbols_9">&#x096F;</string>
+ <!-- U+0966: "०" DEVANAGARI DIGIT ZERO -->
+ <string name="keylabel_for_symbols_0">&#x0966;</string>
+ <!-- Label for "switch to symbols" key. -->
+ <string name="label_to_symbol_key">\?&#x0967;&#x0968;&#x0969;</string>
+ <!-- Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
+ part because it'll be appended by the code. -->
+ <string name="label_to_symbol_with_microphone_key">&#x0967;&#x0968;&#x0969;</string>
+ <string name="additional_more_keys_for_symbols_1">1</string>
+ <string name="additional_more_keys_for_symbols_2">2</string>
+ <string name="additional_more_keys_for_symbols_3">3</string>
+ <string name="additional_more_keys_for_symbols_4">4</string>
+ <string name="additional_more_keys_for_symbols_5">5</string>
+ <string name="additional_more_keys_for_symbols_6">6</string>
+ <string name="additional_more_keys_for_symbols_7">7</string>
+ <string name="additional_more_keys_for_symbols_8">8</string>
+ <string name="additional_more_keys_for_symbols_9">9</string>
+ <string name="additional_more_keys_for_symbols_0">0</string>
+ <!-- U+0930/U+0941/U+002E "रु." NEPALESE RUPEE SIGN -->
+ <string name="keylabel_for_currency">&#x0930;&#x0941;&#x002E;</string>
+</resources>
diff --git a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml
index a4c2f126d..cc09f7fe5 100644
--- a/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml
+++ b/tools/make-keyboard-text/res/values/donottranslate-more-keys.xml
@@ -190,7 +190,7 @@
<!-- Label for "switch to more symbol" modifier key. Must be short to fit on key! -->
<string name="label_to_more_symbol_key">= \\ &lt;</string>
<!-- Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key! -->
- <string name="label_to_more_symbol_for_tablet_key">~ [ {</string>
+ <string name="label_to_more_symbol_for_tablet_key">~ [ &lt;</string>
<!-- Label for "Tab" key. Must be short to fit on key! -->
<string name="label_tab_key">Tab</string>
<!-- Label for "switch to phone numeric" key. Must be short to fit on key! -->