aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/res/xml-sw600dp/rows_lao.xml63
-rw-r--r--java/res/xml/kbd_lao.xml31
-rw-r--r--java/res/xml/key_styles_currency.xml3
-rw-r--r--java/res/xml/keyboard_layout_set_lao.xml58
-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/rows_lao.xml56
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java20
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java28
-rw-r--r--java/src/com/android/inputmethod/latin/Dictionary.java5
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java10
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableDictionary.java9
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java4
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java6
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java23
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java19
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/FormatSpec.java14
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java6
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java4
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java269
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsValues.java3
-rw-r--r--java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java33
-rw-r--r--native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp5
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.cpp72
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h45
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.cpp5
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_node_reader.h25
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.cpp4
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h6
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp41
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h2
-rw-r--r--tests/src/com/android/inputmethod/latin/InputTestsBase.java3
-rw-r--r--tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java6
-rw-r--r--tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java75
-rw-r--r--tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java21
-rw-r--r--tools/make-keyboard-text/res/values-lo/donottranslate-more-keys.xml28
39 files changed, 1369 insertions, 145 deletions
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_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_styles_currency.xml b/java/res/xml/key_styles_currency.xml
index 60333eeb4..094465167 100644
--- a/java/res/xml/key_styles_currency.xml
+++ b/java/res/xml/key_styles_currency.xml
@@ -95,6 +95,7 @@
<!-- fa: Persian (Rial and Afgahni)
hi: Hindi (Indian Rupee)
iw: Hebrew (New Sheqel)
+ lo: Lao (Kip)
mn: Mongolian (Tugrik)
th: Thai (Baht)
uk: Ukrainian (Hryvnia)
@@ -102,7 +103,7 @@
<!-- 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|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/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/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/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index 7008b0619..de7f2e25c 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -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
@@ -3332,6 +3351,7 @@ 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 */
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 834d3ed53..dacb8483c 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -40,6 +40,9 @@ public final class BinaryDictionary extends Dictionary {
private static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH;
// Must be equal to MAX_RESULTS in native/jni/src/defines.h
private static final int MAX_RESULTS = 18;
+ // Required space count for auto commit.
+ // TODO: Remove this heuristic.
+ private static final int SPACE_COUNT_FOR_AUTO_COMMIT = 3;
private long mNativeDict;
private final Locale mLocale;
@@ -49,6 +52,7 @@ public final class BinaryDictionary extends Dictionary {
private final int[] mSpaceIndices = new int[MAX_RESULTS];
private final int[] mOutputScores = new int[MAX_RESULTS];
private final int[] mOutputTypes = new int[MAX_RESULTS];
+ private final int[] mOutputAutoCommitFirstWordConfidence = new int[1]; // Only one result
private final NativeSuggestOptions mNativeSuggestOptions = new NativeSuggestOptions();
@@ -104,7 +108,8 @@ public final class BinaryDictionary extends Dictionary {
long traverseSession, int[] xCoordinates, int[] yCoordinates, int[] times,
int[] pointerIds, int[] inputCodePoints, int inputSize, int commitPoint,
int[] suggestOptions, int[] prevWordCodePointArray,
- int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes);
+ int[] outputCodePoints, int[] outputScores, int[] outputIndices, int[] outputTypes,
+ int[] outputAutoCommitFirstWordConfidence);
private static native float calcNormalizedScoreNative(int[] before, int[] after, int score);
private static native int editDistanceNative(int[] before, int[] after);
private static native void addUnigramWordNative(long dict, int[] word, int probability);
@@ -157,7 +162,7 @@ public final class BinaryDictionary extends Dictionary {
ips.getYCoordinates(), ips.getTimes(), ips.getPointerIds(), mInputCodePoints,
inputSize, 0 /* commitPoint */, mNativeSuggestOptions.getOptions(),
prevWordCodePointArray, mOutputCodePoints, mOutputScores, mSpaceIndices,
- mOutputTypes);
+ mOutputTypes, mOutputAutoCommitFirstWordConfidence);
final ArrayList<SuggestedWordInfo> suggestions = CollectionUtils.newArrayList();
for (int j = 0; j < count; ++j) {
final int start = j * MAX_WORD_LENGTH;
@@ -181,7 +186,8 @@ public final class BinaryDictionary extends Dictionary {
// flags too and pass mOutputTypes[j] instead of kind
suggestions.add(new SuggestedWordInfo(new String(mOutputCodePoints, start, len),
score, kind, this /* sourceDict */,
- mSpaceIndices[0] /* indexOfTouchPointOfSecondWord */));
+ mSpaceIndices[0] /* indexOfTouchPointOfSecondWord */,
+ mOutputAutoCommitFirstWordConfidence[0]));
}
}
return suggestions;
@@ -256,6 +262,22 @@ public final class BinaryDictionary extends Dictionary {
}
@Override
+ public boolean shouldAutoCommit(final SuggestedWordInfo candidate) {
+ // TODO: actually use the confidence rather than use this completely broken heuristic
+ final String word = candidate.mWord;
+ final int length = word.length();
+ int remainingSpaces = SPACE_COUNT_FOR_AUTO_COMMIT;
+ for (int i = 0; i < length; ++i) {
+ // This is okay because no low-surrogate and no high-surrogate can ever match the
+ // space character, so we don't need to take care of iterating on code points.
+ if (Constants.CODE_SPACE == word.charAt(i)) {
+ if (0 >= --remainingSpaces) return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
public void close() {
synchronized (mDicTraverseSessions) {
final int sessionsSize = mDicTraverseSessions.size();
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 8a3a88438..fa79f5af7 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -137,7 +137,10 @@ public abstract class Dictionary {
}
/**
- * Whether we think this suggestion should trigger an auto-commit.
+ * Whether we think this suggestion should trigger an auto-commit. prevWord is the word
+ * before the suggestion, so that we can use n-gram frequencies.
+ * @param candidate The candidate suggestion, in whole (not only the first part).
+ * @return whether we should auto-commit or not.
*/
public boolean shouldAutoCommit(final SuggestedWordInfo candidate) {
// If we don't have support for auto-commit, or if we don't know, we return false to
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index c884e7b1f..2a9076436 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -617,4 +617,14 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
});
return holder.get(false, TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS);
}
+
+ @UsedForTesting
+ public void shutdownExecutorForTests() {
+ getExecutor(mFilename).shutdown();
+ }
+
+ @UsedForTesting
+ public boolean isTerminatedForTests() {
+ return getExecutor(mFilename).isTerminated();
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index ba7d1a2b0..d491f988a 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -344,7 +344,8 @@ public class ExpandableDictionary extends Dictionary {
// in the future.
suggestions.add(new SuggestedWordInfo(new String(word, 0, depth + 1), finalFreq,
SuggestedWordInfo.KIND_CORRECTION, this /* sourceDict */,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
if (suggestions.size() >= Suggest.MAX_SUGGESTIONS) return false;
}
if (null != node.mShortcutTargets) {
@@ -353,7 +354,8 @@ public class ExpandableDictionary extends Dictionary {
final char[] shortcut = node.mShortcutTargets.get(shortcutIndex);
suggestions.add(new SuggestedWordInfo(new String(shortcut, 0, shortcut.length),
finalFreq, SuggestedWordInfo.KIND_SHORTCUT, this /* sourceDict */,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
if (suggestions.size() > Suggest.MAX_SUGGESTIONS) return false;
}
}
@@ -604,7 +606,8 @@ public class ExpandableDictionary extends Dictionary {
suggestions.add(new SuggestedWordInfo(new String(mLookedUpString, index,
Constants.DICTIONARY_MAX_WORD_LENGTH - index),
freq, SuggestedWordInfo.KIND_CORRECTION, this /* sourceDict */,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
}
}
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 5657ed779..d8a47a307 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -2702,7 +2702,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
suggestions.add(new SuggestedWordInfo(s,
SuggestionStripView.MAX_SUGGESTIONS - i,
SuggestedWordInfo.KIND_RESUMED, Dictionary.DICTIONARY_RESUMED,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE
+ /* autoCommitFirstWordConfidence */));
}
}
}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 9370757ec..7815f4d41 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -327,7 +327,8 @@ public final class Suggest {
suggestionsContainer.add(0, new SuggestedWordInfo(typedWord,
SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_TYPED,
Dictionary.DICTIONARY_USER_TYPED,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
}
SuggestedWordInfo.removeDups(suggestionsContainer);
@@ -474,7 +475,8 @@ public final class Suggest {
sb.appendCodePoint(Constants.CODE_SINGLE_QUOTE);
}
return new SuggestedWordInfo(sb.toString(), wordInfo.mScore, wordInfo.mKind,
- wordInfo.mSourceDict, wordInfo.mIndexOfTouchPointOfSecondWord);
+ wordInfo.mSourceDict, wordInfo.mIndexOfTouchPointOfSecondWord,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
}
public void close() {
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index b27fd81e9..17637054a 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -114,7 +114,8 @@ public final class SuggestedWords {
final SuggestedWordInfo suggestedWordInfo = new SuggestedWordInfo(text.toString(),
SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_APP_DEFINED,
Dictionary.DICTIONARY_APPLICATION_DEFINED,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */);
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
result.add(suggestedWordInfo);
}
return result;
@@ -128,7 +129,8 @@ public final class SuggestedWords {
final HashSet<String> alreadySeen = CollectionUtils.newHashSet();
suggestionsList.add(new SuggestedWordInfo(typedWord, SuggestedWordInfo.MAX_SCORE,
SuggestedWordInfo.KIND_TYPED, Dictionary.DICTIONARY_USER_TYPED,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
alreadySeen.add(typedWord.toString());
final int previousSize = previousSuggestions.size();
for (int index = 1; index < previousSize; index++) {
@@ -151,6 +153,7 @@ public final class SuggestedWords {
public static final class SuggestedWordInfo {
public static final int NOT_AN_INDEX = -1;
+ public static final int NOT_A_CONFIDENCE = -1;
public static final int MAX_SCORE = Integer.MAX_VALUE;
public static final int KIND_MASK_KIND = 0xFF; // Mask to get only the kind
public static final int KIND_TYPED = 0; // What user typed
@@ -180,16 +183,30 @@ public final class SuggestedWords {
// passed to native code to get suggestions for a gesture that corresponds to the first
// letter of the second word.
public final int mIndexOfTouchPointOfSecondWord;
+ // For auto-commit. This is a measure of how confident we are that we can commit the
+ // first word of this suggestion.
+ public final int mAutoCommitFirstWordConfidence;
private String mDebugString = "";
+ /**
+ * Create a new suggested word info.
+ * @param word The string to suggest.
+ * @param score A measure of how likely this suggestion is.
+ * @param kind The kind of suggestion, as one of the above KIND_* constants.
+ * @param sourceDict What instance of Dictionary produced this suggestion.
+ * @param indexOfTouchPointOfSecondWord See mIndexOfTouchPointOfSecondWord.
+ * @param autoCommitFirstWordConfidence See mAutoCommitFirstWordConfidence.
+ */
public SuggestedWordInfo(final String word, final int score, final int kind,
- final Dictionary sourceDict, final int indexOfTouchPointOfSecondWord) {
+ final Dictionary sourceDict, final int indexOfTouchPointOfSecondWord,
+ final int autoCommitFirstWordConfidence) {
mWord = word;
mScore = score;
mKind = kind;
mSourceDict = sourceDict;
mCodePointCount = StringUtils.codePointCount(mWord);
mIndexOfTouchPointOfSecondWord = indexOfTouchPointOfSecondWord;
+ mAutoCommitFirstWordConfidence = autoCommitFirstWordConfidence;
}
public boolean isEligibleForAutoCommit() {
diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
index 21e9811ef..f333b0d86 100644
--- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
+++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictEncoderUtils.java
@@ -126,8 +126,14 @@ public class BinaryDictEncoderUtils {
*/
private static int getPtNodeMaximumSize(final PtNode ptNode, final FormatOptions options) {
int size = getNodeHeaderSize(ptNode, options);
- // If terminal, one byte for the frequency
- if (ptNode.isTerminal()) size += FormatSpec.PTNODE_FREQUENCY_SIZE;
+ if (ptNode.isTerminal()) {
+ // If terminal, one byte for the frequency or four bytes for the terminal id.
+ if (options.mHasTerminalId) {
+ size += FormatSpec.PTNODE_TERMINAL_ID_SIZE;
+ } else {
+ size += FormatSpec.PTNODE_FREQUENCY_SIZE;
+ }
+ }
size += FormatSpec.PTNODE_MAX_ADDRESS_SIZE; // For children address
size += getShortcutListSize(ptNode.mShortcutTargets);
if (null != ptNode.mBigrams) {
@@ -345,7 +351,13 @@ public class BinaryDictEncoderUtils {
changed = true;
}
int nodeSize = getNodeHeaderSize(ptNode, formatOptions);
- if (ptNode.isTerminal()) nodeSize += FormatSpec.PTNODE_FREQUENCY_SIZE;
+ if (ptNode.isTerminal()) {
+ if (formatOptions.mHasTerminalId) {
+ nodeSize += FormatSpec.PTNODE_TERMINAL_ID_SIZE;
+ } else {
+ nodeSize += FormatSpec.PTNODE_FREQUENCY_SIZE;
+ }
+ }
if (formatOptions.mSupportsDynamicUpdate) {
nodeSize += FormatSpec.SIGNED_CHILDREN_ADDRESS_SIZE;
} else if (null != ptNode.mChildren) {
@@ -787,7 +799,6 @@ public class BinaryDictEncoderUtils {
+ FormatSpec.MAX_TERMINAL_FREQUENCY
+ " : " + ptNode.mFrequency);
}
-
dictEncoder.writePtNode(ptNode, parentPosition, formatOptions, dict);
}
if (formatOptions.mSupportsDynamicUpdate) {
diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
index 44ae33de1..96ccd8e49 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java
@@ -198,9 +198,12 @@ public final class FormatSpec {
public static final int MAGIC_NUMBER = 0x9BC13AFE;
static final int MINIMUM_SUPPORTED_VERSION = 2;
- static final int MAXIMUM_SUPPORTED_VERSION = 3;
+ static final int MAXIMUM_SUPPORTED_VERSION = 4;
static final int NOT_A_VERSION_NUMBER = -1;
static final int FIRST_VERSION_WITH_DYNAMIC_UPDATE = 3;
+ static final int FIRST_VERSION_WITH_TERMINAL_ID = 4;
+ static final int VERSION3 = 3;
+ static final int VERSION4 = 4;
// These options need to be the same numeric values as the one in the native reading code.
static final int GERMAN_UMLAUT_PROCESSING_FLAG = 0x1;
@@ -251,11 +254,17 @@ public final class FormatSpec {
static final int PTNODE_TERMINATOR_SIZE = 1;
static final int PTNODE_FLAGS_SIZE = 1;
static final int PTNODE_FREQUENCY_SIZE = 1;
+ static final int PTNODE_TERMINAL_ID_SIZE = 4;
static final int PTNODE_MAX_ADDRESS_SIZE = 3;
static final int PTNODE_ATTRIBUTE_FLAGS_SIZE = 1;
static final int PTNODE_ATTRIBUTE_MAX_ADDRESS_SIZE = 3;
static final int PTNODE_SHORTCUT_LIST_SIZE_SIZE = 2;
+ // These values are used only by version 4 or later.
+ static final String TRIE_FILE_EXTENSION = ".trie";
+ static final String FREQ_FILE_EXTENSION = ".freq";
+ static final int FREQUENCY_AND_FLAGS_SIZE = 2;
+
static final int NO_CHILDREN_ADDRESS = Integer.MIN_VALUE;
static final int NO_PARENT_ADDRESS = 0;
static final int NO_FORWARD_LINK_ADDRESS = 0;
@@ -264,6 +273,7 @@ public final class FormatSpec {
static final int MAX_PTNODES_FOR_ONE_BYTE_PTNODE_COUNT = 0x7F; // 127
static final int MAX_PTNODES_IN_A_PT_NODE_ARRAY = 0x7FFF; // 32767
static final int MAX_BIGRAMS_IN_A_PTNODE = 10000;
+ static final int MAX_SHORTCUT_LIST_SIZE_IN_A_PTNODE = 0xFFFF;
static final int MAX_TERMINAL_FREQUENCY = 255;
static final int MAX_BIGRAM_FREQUENCY = 15;
@@ -287,6 +297,7 @@ public final class FormatSpec {
public static final class FormatOptions {
public final int mVersion;
public final boolean mSupportsDynamicUpdate;
+ public final boolean mHasTerminalId;
@UsedForTesting
public FormatOptions(final int version) {
this(version, false);
@@ -300,6 +311,7 @@ public final class FormatSpec {
+ FIRST_VERSION_WITH_DYNAMIC_UPDATE + " and ulterior.");
}
mSupportsDynamicUpdate = supportsDynamicUpdate;
+ mHasTerminalId = (version >= FIRST_VERSION_WITH_TERMINAL_ID);
}
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
index 3e685a3d7..be653feec 100644
--- a/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
+++ b/java/src/com/android/inputmethod/latin/makedict/FusionDictionary.java
@@ -111,6 +111,7 @@ public final class FusionDictionary implements Iterable<Word> {
ArrayList<WeightedString> mShortcutTargets;
ArrayList<WeightedString> mBigrams;
int mFrequency; // NOT_A_TERMINAL == mFrequency indicates this is not a terminal.
+ int mTerminalId; // NOT_A_TERMINAL == mTerminalId indicates this is not a terminal.
PtNodeArray mChildren;
boolean mIsNotAWord; // Only a shortcut
boolean mIsBlacklistEntry;
@@ -129,6 +130,7 @@ public final class FusionDictionary implements Iterable<Word> {
final boolean isNotAWord, final boolean isBlacklistEntry) {
mChars = chars;
mFrequency = frequency;
+ mTerminalId = frequency;
mShortcutTargets = shortcutTargets;
mBigrams = bigrams;
mChildren = null;
@@ -156,6 +158,10 @@ public final class FusionDictionary implements Iterable<Word> {
mChildren.mData.add(n);
}
+ public int getTerminalId() {
+ return mTerminalId;
+ }
+
public boolean isTerminal() {
return NOT_A_TERMINAL != mFrequency;
}
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java
index 48a823d43..222a0f474 100644
--- a/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver3DictEncoder.java
@@ -68,7 +68,7 @@ public class Ver3DictEncoder implements DictEncoder {
@Override
public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions)
throws IOException, UnsupportedFormatException {
- if (formatOptions.mVersion > 3) {
+ if (formatOptions.mVersion > FormatSpec.VERSION3) {
throw new UnsupportedFormatException(
"The given format options has wrong version number : "
+ formatOptions.mVersion);
@@ -200,7 +200,7 @@ public class Ver3DictEncoder implements DictEncoder {
mPosition += shortcutShift;
}
final int shortcutByteSize = mPosition - indexOfShortcutByteSize;
- if (shortcutByteSize > 0xFFFF) {
+ if (shortcutByteSize > FormatSpec.MAX_SHORTCUT_LIST_SIZE_IN_A_PTNODE) {
throw new RuntimeException("Shortcut list too large");
}
BinaryDictEncoderUtils.writeUIntToBuffer(mBuffer, indexOfShortcutByteSize, shortcutByteSize,
diff --git a/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
new file mode 100644
index 000000000..75b75ae2e
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/makedict/Ver4DictEncoder.java
@@ -0,0 +1,269 @@
+/*
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.makedict;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding;
+import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
+import com.android.inputmethod.latin.makedict.FormatSpec.FormatOptions;
+import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
+import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
+import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * An implementation of DictEncoder for version 4 binary dictionary.
+ */
+@UsedForTesting
+public class Ver4DictEncoder implements DictEncoder {
+ private final File mDictPlacedDir;
+ private byte[] mTrieBuf;
+ private byte[] mFreqBuf;
+ private int mTriePos;
+ private OutputStream mTrieOutStream;
+ private OutputStream mFreqOutStream;
+
+ @UsedForTesting
+ public Ver4DictEncoder(final File dictPlacedDir) {
+ mDictPlacedDir = dictPlacedDir;
+ }
+
+ private void openStreams(final FormatOptions formatOptions, final DictionaryOptions dictOptions)
+ throws FileNotFoundException, IOException {
+ final FileHeader header = new FileHeader(0, dictOptions, formatOptions);
+ final String filename = header.getId() + "." + header.getVersion();
+ final File mDictDir = new File(mDictPlacedDir, filename);
+ final File trieFile = new File(mDictDir, filename + FormatSpec.TRIE_FILE_EXTENSION);
+ final File freqFile = new File(mDictDir, filename + FormatSpec.FREQ_FILE_EXTENSION);
+ if (!mDictDir.isDirectory()) {
+ if (mDictDir.exists()) mDictDir.delete();
+ mDictDir.mkdirs();
+ }
+ if (!trieFile.exists()) trieFile.createNewFile();
+ if (!freqFile.exists()) freqFile.createNewFile();
+ mTrieOutStream = new FileOutputStream(trieFile);
+ mFreqOutStream = new FileOutputStream(freqFile);
+ }
+
+ private void close() throws IOException {
+ try {
+ if (mTrieOutStream != null) {
+ mTrieOutStream.close();
+ }
+ if (mFreqOutStream != null) {
+ mFreqOutStream.close();
+ }
+ } finally {
+ mTrieOutStream = null;
+ mFreqOutStream = null;
+ }
+ }
+
+ @Override
+ public void writeDictionary(final FusionDictionary dict, final FormatOptions formatOptions)
+ throws IOException, UnsupportedFormatException {
+ if (formatOptions.mVersion != FormatSpec.VERSION4) {
+ throw new UnsupportedFormatException("File header has a wrong version number : "
+ + formatOptions.mVersion);
+ }
+ if (!mDictPlacedDir.isDirectory()) {
+ throw new UnsupportedFormatException("Given path is not a directory.");
+ }
+
+ if (mTrieOutStream == null) {
+ openStreams(formatOptions, dict.mOptions);
+ }
+
+ BinaryDictEncoderUtils.writeDictionaryHeader(mTrieOutStream, dict, formatOptions);
+
+ MakedictLog.i("Flattening the tree...");
+ ArrayList<PtNodeArray> flatNodes = BinaryDictEncoderUtils.flattenTree(dict.mRootNodeArray);
+ int terminalCount = 0;
+ for (final PtNodeArray array : flatNodes) {
+ for (final PtNode node : array.mData) {
+ if (node.isTerminal()) node.mTerminalId = terminalCount++;
+ }
+ }
+
+ MakedictLog.i("Computing addresses...");
+ BinaryDictEncoderUtils.computeAddresses(dict, flatNodes, formatOptions);
+ if (MakedictLog.DBG) BinaryDictEncoderUtils.checkFlatPtNodeArrayList(flatNodes);
+
+ final PtNodeArray lastNodeArray = flatNodes.get(flatNodes.size() - 1);
+ final int bufferSize = lastNodeArray.mCachedAddressAfterUpdate + lastNodeArray.mCachedSize;
+ mTrieBuf = new byte[bufferSize];
+ mFreqBuf = new byte[terminalCount * FormatSpec.FREQUENCY_AND_FLAGS_SIZE];
+
+ MakedictLog.i("Writing file...");
+ for (PtNodeArray nodeArray : flatNodes) {
+ BinaryDictEncoderUtils.writePlacedPtNodeArray(dict, this, nodeArray, formatOptions);
+ }
+ if (MakedictLog.DBG) {
+ BinaryDictEncoderUtils.showStatistics(flatNodes);
+ MakedictLog.i("has " + terminalCount + " terminals.");
+ }
+ mTrieOutStream.write(mTrieBuf);
+ mFreqOutStream.write(mFreqBuf);
+
+ MakedictLog.i("Done");
+ close();
+ }
+
+ @Override
+ public void setPosition(int position) {
+ if (mTrieBuf == null || position < 0 || position >- mTrieBuf.length) return;
+ mTriePos = position;
+ }
+
+ @Override
+ public int getPosition() {
+ return mTriePos;
+ }
+
+ @Override
+ public void writePtNodeCount(int ptNodeCount) {
+ final int countSize = BinaryDictIOUtils.getPtNodeCountSize(ptNodeCount);
+ // ptNodeCount must fit on one byte or two bytes.
+ // Please see comments in FormatSpec
+ if (countSize != 1 && countSize != 2) {
+ throw new RuntimeException("Strange size from getPtNodeCountSize : " + countSize);
+ }
+ mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos, ptNodeCount,
+ countSize);
+ }
+
+ private void writePtNodeFlags(final PtNode ptNode, final int parentAddress,
+ final FormatOptions formatOptions) {
+ final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions);
+ mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos,
+ BinaryDictEncoderUtils.makePtNodeFlags(ptNode, mTriePos, childrenPos,
+ formatOptions),
+ FormatSpec.PTNODE_FLAGS_SIZE);
+ }
+
+ private void writeParentPosition(int parentPos, final PtNode ptNode,
+ final FormatOptions formatOptions) {
+ if (parentPos != FormatSpec.NO_PARENT_ADDRESS) {
+ parentPos -= ptNode.mCachedAddressAfterUpdate;
+ }
+ mTriePos = BinaryDictEncoderUtils.writeParentAddress(mTrieBuf, mTriePos, parentPos,
+ formatOptions);
+ }
+
+ private void writeCharacters(final int[] characters, final boolean hasSeveralChars) {
+ mTriePos = CharEncoding.writeCharArray(characters, mTrieBuf, mTriePos);
+ if (hasSeveralChars) {
+ mTrieBuf[mTriePos++] = FormatSpec.PTNODE_CHARACTERS_TERMINATOR;
+ }
+ }
+
+ private void writeTerminalId(final int terminalId) {
+ mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos, terminalId,
+ FormatSpec.PTNODE_TERMINAL_ID_SIZE);
+ }
+
+ private void writeFrequency(final int frequency, final int terminalId) {
+ final int freqPos = terminalId * FormatSpec.FREQUENCY_AND_FLAGS_SIZE;
+ BinaryDictEncoderUtils.writeUIntToBuffer(mFreqBuf, freqPos, frequency,
+ FormatSpec.FREQUENCY_AND_FLAGS_SIZE);
+ }
+
+ private void writeChildrenPosition(PtNode ptNode, FormatOptions formatOptions) {
+ final int childrenPos = BinaryDictEncoderUtils.getChildrenPosition(ptNode, formatOptions);
+ if (formatOptions.mSupportsDynamicUpdate) {
+ mTriePos += BinaryDictEncoderUtils.writeSignedChildrenPosition(mTrieBuf,
+ mTriePos, childrenPos);
+ } else {
+ mTriePos += BinaryDictEncoderUtils.writeChildrenPosition(mTrieBuf,
+ mTriePos, childrenPos);
+ }
+ }
+
+ private void writeShortcuts(ArrayList<WeightedString> shortcuts) {
+ if (null == shortcuts || shortcuts.isEmpty()) return;
+
+ final int indexOfShortcutByteSize = mTriePos;
+ mTriePos += FormatSpec.PTNODE_SHORTCUT_LIST_SIZE_SIZE;
+ final Iterator<WeightedString> shortcutIterator = shortcuts.iterator();
+ while (shortcutIterator.hasNext()) {
+ final WeightedString target = shortcutIterator.next();
+ final int shortcutFlags = BinaryDictEncoderUtils.makeShortcutFlags(
+ shortcutIterator.hasNext(),
+ target.mFrequency);
+ mTrieBuf[mTriePos++] = (byte)shortcutFlags;
+ final int shortcutShift = CharEncoding.writeString(mTrieBuf, mTriePos,
+ target.mWord);
+ mTriePos += shortcutShift;
+ }
+ final int shortcutByteSize = mTriePos - indexOfShortcutByteSize;
+ if (shortcutByteSize > FormatSpec.MAX_SHORTCUT_LIST_SIZE_IN_A_PTNODE) {
+ throw new RuntimeException("Shortcut list too large : " + shortcutByteSize);
+ }
+ BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, indexOfShortcutByteSize,
+ shortcutByteSize, FormatSpec.PTNODE_SHORTCUT_LIST_SIZE_SIZE);
+ }
+
+ private void writeBigrams(ArrayList<WeightedString> bigrams, FusionDictionary dict) {
+ if (bigrams == null) return;
+
+ final Iterator<WeightedString> bigramIterator = bigrams.iterator();
+ while (bigramIterator.hasNext()) {
+ final WeightedString bigram = bigramIterator.next();
+ final PtNode target =
+ FusionDictionary.findWordInTree(dict.mRootNodeArray, bigram.mWord);
+ final int addressOfBigram = target.mCachedAddressAfterUpdate;
+ final int unigramFrequencyForThisWord = target.mFrequency;
+ final int offset = addressOfBigram
+ - (mTriePos + FormatSpec.PTNODE_ATTRIBUTE_FLAGS_SIZE);
+ int bigramFlags = BinaryDictEncoderUtils.makeBigramFlags(bigramIterator.hasNext(),
+ offset, bigram.mFrequency, unigramFrequencyForThisWord, bigram.mWord);
+ mTrieBuf[mTriePos++] = (byte) bigramFlags;
+ mTriePos += BinaryDictEncoderUtils.writeChildrenPosition(mTrieBuf,
+ mTriePos, Math.abs(offset));
+ }
+ }
+
+ @Override
+ public void writeForwardLinkAddress(int forwardLinkAddress) {
+ mTriePos = BinaryDictEncoderUtils.writeUIntToBuffer(mTrieBuf, mTriePos,
+ forwardLinkAddress, FormatSpec.FORWARD_LINK_ADDRESS_SIZE);
+ }
+
+ @Override
+ public void writePtNode(final PtNode ptNode, final int parentPosition,
+ final FormatOptions formatOptions, final FusionDictionary dict) {
+ writePtNodeFlags(ptNode, parentPosition, formatOptions);
+ writeParentPosition(parentPosition, ptNode, formatOptions);
+ writeCharacters(ptNode.mChars, ptNode.hasSeveralChars());
+ if (ptNode.isTerminal()) {
+ writeTerminalId(ptNode.mTerminalId);
+ writeFrequency(ptNode.mFrequency, ptNode.mTerminalId);
+ }
+ writeChildrenPosition(ptNode, formatOptions);
+ writeShortcuts(ptNode.mShortcutTargets);
+ writeBigrams(ptNode.mBigrams, dict);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index 072bb8731..fc2d19298 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -295,7 +295,8 @@ public final class SettingsValues {
puncList.add(new SuggestedWordInfo(KeySpecParser.getLabel(puncSpec),
SuggestedWordInfo.MAX_SCORE, SuggestedWordInfo.KIND_HARDCODED,
Dictionary.DICTIONARY_HARDCODED,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
}
}
return new SuggestedWords(puncList,
diff --git a/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java b/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java
index 3c1db6529..5dc0b5893 100644
--- a/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java
+++ b/java/src/com/android/inputmethod/latin/utils/PrioritizedSerialExecutor.java
@@ -31,6 +31,7 @@ public class PrioritizedSerialExecutor {
private static final int TASK_QUEUE_CAPACITY = 1000;
private final Queue<Runnable> mTasks;
private final Queue<Runnable> mPrioritizedTasks;
+ private boolean mIsShutdown;
// The task which is running now.
private Runnable mActive;
@@ -38,6 +39,7 @@ public class PrioritizedSerialExecutor {
public PrioritizedSerialExecutor() {
mTasks = new ArrayDeque<Runnable>(TASK_QUEUE_CAPACITY);
mPrioritizedTasks = new ArrayDeque<Runnable>(TASK_QUEUE_CAPACITY);
+ mIsShutdown = false;
}
/**
@@ -56,9 +58,11 @@ public class PrioritizedSerialExecutor {
*/
public void execute(final Runnable r) {
synchronized(mLock) {
- mTasks.offer(r);
- if (mActive == null) {
- scheduleNext();
+ if (!mIsShutdown) {
+ mTasks.offer(r);
+ if (mActive == null) {
+ scheduleNext();
+ }
}
}
}
@@ -69,9 +73,11 @@ public class PrioritizedSerialExecutor {
*/
public void executePrioritized(final Runnable r) {
synchronized(mLock) {
- mPrioritizedTasks.offer(r);
- if (mActive == null) {
- scheduleNext();
+ if (!mIsShutdown) {
+ mPrioritizedTasks.offer(r);
+ if (mActive == null) {
+ scheduleNext();
+ }
}
}
}
@@ -123,4 +129,19 @@ public class PrioritizedSerialExecutor {
execute(newTask);
}
}
+
+ public void shutdown() {
+ synchronized(mLock) {
+ mIsShutdown = true;
+ }
+ }
+
+ public boolean isTerminated() {
+ synchronized(mLock) {
+ if (!mIsShutdown) {
+ return false;
+ }
+ return mPrioritizedTasks.isEmpty() && mTasks.isEmpty() && mActive == null;
+ }
+ }
}
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 8da1859c4..6a366121d 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -70,7 +70,8 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, j
jintArray yCoordinatesArray, jintArray timesArray, jintArray pointerIdsArray,
jintArray inputCodePointsArray, jint inputSize, jint commitPoint, jintArray suggestOptions,
jintArray prevWordCodePointsForBigrams, jintArray outputCodePointsArray,
- jintArray scoresArray, jintArray spaceIndicesArray, jintArray outputTypesArray) {
+ jintArray scoresArray, jintArray spaceIndicesArray, jintArray outputTypesArray,
+ jintArray outputAutoCommitFirstWordConfidence) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
if (!dictionary) return 0;
ProximityInfo *pInfo = reinterpret_cast<ProximityInfo *>(proximityInfo);
@@ -253,7 +254,7 @@ static const JNINativeMethod sMethods[] = {
},
{
const_cast<char *>("getSuggestionsNative"),
- const_cast<char *>("(JJJ[I[I[I[I[III[I[I[I[I[I[I)I"),
+ const_cast<char *>("(JJJ[I[I[I[I[III[I[I[I[I[I[I[I)I"),
reinterpret_cast<void *>(latinime_BinaryDictionary_getSuggestions)
},
{
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 936dc9c5d..4ee138125 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
@@ -18,6 +18,42 @@
namespace latinime {
+const int DynamicBigramListPolicy::BIGRAM_LINK_COUNT_LIMIT = 10000;
+
+void DynamicBigramListPolicy::getNextBigram(int *const outBigramPos, int *const outProbability,
+ bool *const outHasNext, int *const pos) const {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*pos);
+ const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer);
+ if (usesAdditionalBuffer) {
+ *pos -= mBuffer->getOriginalBufferSize();
+ }
+ const BigramListReadWriteUtils::BigramFlags flags =
+ BigramListReadWriteUtils::getFlagsAndForwardPointer(buffer, pos);
+ int originalBigramPos = BigramListReadWriteUtils::getBigramAddressAndForwardPointer(
+ buffer, flags, pos);
+ if (usesAdditionalBuffer && originalBigramPos != NOT_A_VALID_WORD_POS) {
+ originalBigramPos += mBuffer->getOriginalBufferSize();
+ }
+ *outBigramPos = followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos);
+ *outProbability = BigramListReadWriteUtils::getProbabilityFromFlags(flags);
+ *outHasNext = BigramListReadWriteUtils::hasNext(flags);
+ if (usesAdditionalBuffer) {
+ *pos += mBuffer->getOriginalBufferSize();
+ }
+}
+
+void DynamicBigramListPolicy::skipAllBigrams(int *const pos) const {
+ const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*pos);
+ const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer);
+ if (usesAdditionalBuffer) {
+ *pos -= mBuffer->getOriginalBufferSize();
+ }
+ BigramListReadWriteUtils::skipExistingBigrams(buffer, pos);
+ if (usesAdditionalBuffer) {
+ *pos += mBuffer->getOriginalBufferSize();
+ }
+}
+
bool DynamicBigramListPolicy::copyAllBigrams(int *const fromPos, int *const toPos) {
const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*fromPos);
if (usesAdditionalBuffer) {
@@ -28,15 +64,16 @@ bool DynamicBigramListPolicy::copyAllBigrams(int *const fromPos, int *const toPo
// The buffer address can be changed after calling buffer writing methods.
const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer);
flags = BigramListReadWriteUtils::getFlagsAndForwardPointer(buffer, fromPos);
- int bigramPos = BigramListReadWriteUtils::getBigramAddressAndForwardPointer(
+ int originalBigramPos = BigramListReadWriteUtils::getBigramAddressAndForwardPointer(
buffer, flags, fromPos);
- if (bigramPos == NOT_A_VALID_WORD_POS) {
+ if (originalBigramPos == NOT_A_VALID_WORD_POS) {
// skip invalid bigram entry.
continue;
}
if (usesAdditionalBuffer) {
- bigramPos += mBuffer->getOriginalBufferSize();
+ originalBigramPos += mBuffer->getOriginalBufferSize();
}
+ const int bigramPos = followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos);
BigramListReadWriteUtils::BigramFlags newBigramFlags;
uint32_t newBigramOffset;
int newBigramOffsetFieldSize;
@@ -133,11 +170,12 @@ bool DynamicBigramListPolicy::removeBigram(const int bigramListPos, const int ta
if (usesAdditionalBuffer) {
bigramOffsetFieldPos += mBuffer->getOriginalBufferSize();
}
- int bigramPos = BigramListReadWriteUtils::getBigramAddressAndForwardPointer(
+ int originalBigramPos = BigramListReadWriteUtils::getBigramAddressAndForwardPointer(
buffer, flags, &pos);
- if (usesAdditionalBuffer && bigramPos != NOT_A_VALID_WORD_POS) {
- bigramPos += mBuffer->getOriginalBufferSize();
+ if (usesAdditionalBuffer && originalBigramPos != NOT_A_VALID_WORD_POS) {
+ originalBigramPos += mBuffer->getOriginalBufferSize();
}
+ const int bigramPos = followBigramLinkAndGetCurrentBigramPtNodePos(originalBigramPos);
if (bigramPos != targetBigramPos) {
continue;
}
@@ -152,4 +190,26 @@ bool DynamicBigramListPolicy::removeBigram(const int bigramListPos, const int ta
return false;
}
+int DynamicBigramListPolicy::followBigramLinkAndGetCurrentBigramPtNodePos(
+ const int originalBigramPos) const {
+ if (originalBigramPos == NOT_A_VALID_WORD_POS) {
+ return NOT_A_VALID_WORD_POS;
+ }
+ int currentPos = originalBigramPos;
+ DynamicPatriciaTrieNodeReader nodeReader(mBuffer, this /* bigramsPolicy */, mShortcutPolicy);
+ nodeReader.fetchNodeInfoFromBuffer(currentPos);
+ int bigramLinkCount = 0;
+ while (nodeReader.getBigramLinkedNodePos() != NOT_A_DICT_POS) {
+ currentPos = nodeReader.getBigramLinkedNodePos();
+ nodeReader.fetchNodeInfoFromBuffer(currentPos);
+ bigramLinkCount++;
+ if (bigramLinkCount > BIGRAM_LINK_COUNT_LIMIT) {
+ AKLOGI("Bigram link is invalid. start position: %d", bigramPos);
+ ASSERT(false);
+ return NOT_A_VALID_WORD_POS;
+ }
+ }
+ return currentPos;
+}
+
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h
index b7c05376d..e451e313d 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/bigram/dynamic_bigram_list_policy.h
@@ -21,7 +21,9 @@
#include "defines.h"
#include "suggest/core/policy/dictionary_bigrams_structure_policy.h"
+#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h"
#include "suggest/policyimpl/dictionary/bigram/bigram_list_read_write_utils.h"
+#include "suggest/policyimpl/dictionary/dynamic_patricia_trie_reading_helper.h"
#include "suggest/policyimpl/dictionary/utils/buffer_with_extendable_buffer.h"
namespace latinime {
@@ -31,43 +33,16 @@ namespace latinime {
*/
class DynamicBigramListPolicy : public DictionaryBigramsStructurePolicy {
public:
- DynamicBigramListPolicy(BufferWithExtendableBuffer *const buffer)
- : mBuffer(buffer) {}
+ DynamicBigramListPolicy(BufferWithExtendableBuffer *const buffer,
+ const DictionaryShortcutsStructurePolicy *const shortcutPolicy)
+ : mBuffer(buffer), mShortcutPolicy(shortcutPolicy) {}
~DynamicBigramListPolicy() {}
void getNextBigram(int *const outBigramPos, int *const outProbability, bool *const outHasNext,
- int *const pos) const {
- const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*pos);
- const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer);
- if (usesAdditionalBuffer) {
- *pos -= mBuffer->getOriginalBufferSize();
- }
- const BigramListReadWriteUtils::BigramFlags flags =
- BigramListReadWriteUtils::getFlagsAndForwardPointer(buffer, pos);
- *outBigramPos = BigramListReadWriteUtils::getBigramAddressAndForwardPointer(
- buffer, flags, pos);
- if (usesAdditionalBuffer && *outBigramPos != NOT_A_VALID_WORD_POS) {
- *outBigramPos += mBuffer->getOriginalBufferSize();
- }
- *outProbability = BigramListReadWriteUtils::getProbabilityFromFlags(flags);
- *outHasNext = BigramListReadWriteUtils::hasNext(flags);
- if (usesAdditionalBuffer) {
- *pos += mBuffer->getOriginalBufferSize();
- }
- }
+ int *const pos) const;
- void skipAllBigrams(int *const pos) const {
- const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(*pos);
- const uint8_t *const buffer = mBuffer->getBuffer(usesAdditionalBuffer);
- if (usesAdditionalBuffer) {
- *pos -= mBuffer->getOriginalBufferSize();
- }
- BigramListReadWriteUtils::skipExistingBigrams(buffer, pos);
- if (usesAdditionalBuffer) {
- *pos += mBuffer->getOriginalBufferSize();
- }
- }
+ void skipAllBigrams(int *const pos) const;
// Copy bigrams from the bigram list that starts at fromPos to toPos and advance these
// positions after bigram lists. This method skips invalid bigram entries.
@@ -81,7 +56,13 @@ class DynamicBigramListPolicy : public DictionaryBigramsStructurePolicy {
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicBigramListPolicy);
+ static const int BIGRAM_LINK_COUNT_LIMIT;
+
BufferWithExtendableBuffer *const mBuffer;
+ const DictionaryShortcutsStructurePolicy *const mShortcutPolicy;
+
+ // Follow bigram link and return the position of bigram target PtNode that is currently valid.
+ int followBigramLinkAndGetCurrentBigramPtNodePos(const int originalBigramPos) const;
};
} // namespace latinime
#endif // LATINIME_DYNAMIC_BIGRAM_LIST_POLICY_H
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 14682e3ce..56ef60ae4 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
@@ -62,6 +62,11 @@ void DynamicPatriciaTrieNodeReader::fetchNodeInfoFromBufferAndProcessMovedNode(c
if (usesAdditionalBuffer && mChildrenPos != NOT_A_DICT_POS) {
mChildrenPos += mBuffer->getOriginalBufferSize();
}
+ if (mSiblingPos == NOT_A_VALID_WORD_POS && DynamicPatriciaTrieReadingUtils::isMoved(mFlags)) {
+ mBigramLinkedNodePos = mChildrenPos;
+ } else {
+ mBigramLinkedNodePos = NOT_A_DICT_POS;
+ }
if (usesAdditionalBuffer) {
pos += mBuffer->getOriginalBufferSize();
}
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 30d251f3e..89d38a590 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,11 +39,11 @@ class DynamicPatriciaTrieNodeReader {
const DictionaryBigramsStructurePolicy *const bigramsPolicy,
const DictionaryShortcutsStructurePolicy *const shortcutsPolicy)
: mBuffer(buffer), mBigramsPolicy(bigramsPolicy),
- mShortcutsPolicy(shortcutsPolicy), mNodePos(NOT_A_VALID_WORD_POS),
- 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),
- mShortcutPos(NOT_A_DICT_POS), mBigramPos(NOT_A_DICT_POS),
+ mShortcutsPolicy(shortcutsPolicy), mHeadPos(NOT_A_VALID_WORD_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) {}
~DynamicPatriciaTrieNodeReader() {}
@@ -56,13 +56,9 @@ class DynamicPatriciaTrieNodeReader {
AK_FORCE_INLINE void fetchNodeInfoFromBufferAndGetNodeCodePoints(const int nodePos,
const int maxCodePointCount, int *const outCodePoints) {
- mNodePos = nodePos;
mSiblingPos = NOT_A_VALID_WORD_POS;
- fetchNodeInfoFromBufferAndProcessMovedNode(mNodePos, maxCodePointCount, outCodePoints);
- }
-
- AK_FORCE_INLINE int getNodePos() const {
- return mNodePos;
+ mBigramLinkedNodePos = NOT_A_DICT_POS;
+ fetchNodeInfoFromBufferAndProcessMovedNode(nodePos, maxCodePointCount, outCodePoints);
}
// HeadPos is different from NodePos when the current PtNode is a moved PtNode.
@@ -119,6 +115,11 @@ class DynamicPatriciaTrieNodeReader {
return mChildrenPos;
}
+ // Bigram linked node position.
+ AK_FORCE_INLINE int getBigramLinkedNodePos() const {
+ return mBigramLinkedNodePos;
+ }
+
// Shortcutlist position
AK_FORCE_INLINE int getShortcutPos() const {
return mShortcutPos;
@@ -140,7 +141,6 @@ class DynamicPatriciaTrieNodeReader {
const BufferWithExtendableBuffer *const mBuffer;
const DictionaryBigramsStructurePolicy *const mBigramsPolicy;
const DictionaryShortcutsStructurePolicy *const mShortcutsPolicy;
- int mNodePos;
int mHeadPos;
DynamicPatriciaTrieReadingUtils::NodeFlags mFlags;
int mParentPos;
@@ -149,6 +149,7 @@ class DynamicPatriciaTrieNodeReader {
int mProbability;
int mChildrenPosFieldPos;
int mChildrenPos;
+ int mBigramLinkedNodePos;
int mShortcutPos;
int mBigramPos;
int mSiblingPos;
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 945677b50..ece1781f1 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
@@ -38,7 +38,7 @@ void DynamicPatriciaTriePolicy::createAndGetAllChildNodes(const DicNode *const d
readingHelper.initWithNodeArrayPos(dicNode->getChildrenPos());
const DynamicPatriciaTrieNodeReader *const nodeReader = readingHelper.getNodeReader();
while (!readingHelper.isEnd()) {
- childDicNodes->pushLeavingChild(dicNode, nodeReader->getNodePos(),
+ childDicNodes->pushLeavingChild(dicNode, nodeReader->getHeadPos(),
nodeReader->getChildrenPos(), nodeReader->getProbability(),
nodeReader->isTerminal() && !nodeReader->isDeleted(),
nodeReader->hasChildren(), nodeReader->isBlacklisted() || nodeReader->isNotAWord(),
@@ -122,7 +122,7 @@ int DynamicPatriciaTriePolicy::getTerminalNodePositionOfWord(const int *const in
// All characters are matched.
if (length == readingHelper.getTotalCodePointCount()) {
// Terminal position is found.
- return nodeReader->getNodePos();
+ return nodeReader->getHeadPos();
}
if (!nodeReader->hasChildren()) {
return NOT_A_VALID_WORD_POS;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
index cdab0e16a..50c724012 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_policy.h
@@ -36,8 +36,8 @@ class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
: mBuffer(buffer), mHeaderPolicy(mBuffer->getBuffer()),
mBufferWithExtendableBuffer(mBuffer->getBuffer() + mHeaderPolicy.getSize(),
mBuffer->getBufferSize() - mHeaderPolicy.getSize()),
- mBigramListPolicy(&mBufferWithExtendableBuffer),
- mShortcutListPolicy(&mBufferWithExtendableBuffer) {}
+ mShortcutListPolicy(&mBufferWithExtendableBuffer),
+ mBigramListPolicy(&mBufferWithExtendableBuffer, &mShortcutListPolicy) {}
~DynamicPatriciaTriePolicy() {
delete mBuffer;
@@ -91,8 +91,8 @@ class DynamicPatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
const MmappedBuffer *const mBuffer;
const HeaderPolicy mHeaderPolicy;
BufferWithExtendableBuffer mBufferWithExtendableBuffer;
- DynamicBigramListPolicy mBigramListPolicy;
DynamicShortcutListPolicy mShortcutListPolicy;
+ DynamicBigramListPolicy mBigramListPolicy;
};
} // namespace latinime
#endif // LATINIME_DYNAMIC_PATRICIA_TRIE_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp
index 7dfa9ec5a..dbc80f66a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.cpp
@@ -63,7 +63,7 @@ bool DynamicPatriciaTrieWritingHelper::addUnigramWord(
codePointCount - readingHelper->getTotalCodePointCount());
}
// Advance to the children nodes.
- parentPos = nodeReader->getNodePos();
+ parentPos = nodeReader->getHeadPos();
readingHelper->readChildNode();
}
if (readingHelper->isError()) {
@@ -100,8 +100,9 @@ bool DynamicPatriciaTrieWritingHelper::removeBigramWords(const int word0Pos, con
}
bool DynamicPatriciaTrieWritingHelper::markNodeAsMovedAndSetPosition(
- const DynamicPatriciaTrieNodeReader *const originalNode, const int movedPos) {
- int pos = originalNode->getNodePos();
+ const DynamicPatriciaTrieNodeReader *const originalNode, const int movedPos,
+ const int bigramLinkedNodePos) {
+ int pos = originalNode->getHeadPos();
const bool usesAdditionalBuffer = mBuffer->isInAdditionalBuffer(pos);
const uint8_t *const dictBuf = mBuffer->getBuffer(usesAdditionalBuffer);
if (usesAdditionalBuffer) {
@@ -113,18 +114,24 @@ bool DynamicPatriciaTrieWritingHelper::markNodeAsMovedAndSetPosition(
const PatriciaTrieReadingUtils::NodeFlags updatedFlags =
DynamicPatriciaTrieReadingUtils::updateAndGetFlags(originalFlags, true /* isMoved */,
false /* isDeleted */);
- int writingPos = originalNode->getNodePos();
+ int writingPos = originalNode->getHeadPos();
// Update flags.
if (!DynamicPatriciaTrieWritingUtils::writeFlagsAndAdvancePosition(mBuffer, updatedFlags,
&writingPos)) {
return false;
}
// Update moved position, which is stored in the parent offset field.
- const int movedPosOffset = movedPos - originalNode->getNodePos();
+ const int movedPosOffset = movedPos - originalNode->getHeadPos();
if (!DynamicPatriciaTrieWritingUtils::writeParentOffsetAndAdvancePosition(
mBuffer, movedPosOffset, &writingPos)) {
return false;
}
+ // Update bigram linked node position, which is stored in the children position field.
+ int childrenPosFieldPos = originalNode->getChildrenPosFieldPos();
+ if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(
+ mBuffer, bigramLinkedNodePos, &childrenPosFieldPos)) {
+ return false;
+ }
if (originalNode->hasChildren()) {
// Update children's parent position.
DynamicPatriciaTrieReadingHelper readingHelper(mBuffer, mBigramPolicy, mShortcutPolicy);
@@ -248,7 +255,7 @@ bool DynamicPatriciaTrieWritingHelper::setPtNodeProbability(
} else {
// Make the node terminal and write the probability.
int movedPos = mBuffer->getTailPosition();
- if (!markNodeAsMovedAndSetPosition(originalPtNode, movedPos)) {
+ if (!markNodeAsMovedAndSetPosition(originalPtNode, movedPos, movedPos)) {
return false;
}
if (!writePtNodeToBufferByCopyingPtNodeInfo(originalPtNode, originalPtNode->getParentPos(),
@@ -268,7 +275,7 @@ bool DynamicPatriciaTrieWritingHelper::createChildrenPtNodeArrayAndAChildPtNode(
newPtNodeArrayPos, &childrenPosFieldPos)) {
return false;
}
- return createNewPtNodeArrayWithAChildPtNode(parentNode->getNodePos(), codePoints,
+ return createNewPtNodeArrayWithAChildPtNode(parentNode->getHeadPos(), codePoints,
codePointCount, probability);
}
@@ -305,11 +312,8 @@ bool DynamicPatriciaTrieWritingHelper::reallocatePtNodeAndAddNewPtNodes(
// Reallocating PtNode: abcde, newNode: abc.
// abc (1st, terminal) __ de (2nd)
const bool addsExtraChild = newNodeCodePointCount > overlappingCodePointCount;
- const int firstPtNodePos = mBuffer->getTailPosition();
- if (!markNodeAsMovedAndSetPosition(reallocatingPtNode, firstPtNodePos)) {
- return false;
- }
- int writingPos = firstPtNodePos;
+ const int firstPartOfReallocatedPtNodePos = mBuffer->getTailPosition();
+ int writingPos = firstPartOfReallocatedPtNodePos;
// Write the 1st part of the reallocating node. The children position will be updated later
// with actual children position.
const int newProbability = addsExtraChild ? NOT_A_PROBABILITY : probabilityOfNewPtNode;
@@ -325,15 +329,15 @@ bool DynamicPatriciaTrieWritingHelper::reallocatePtNodeAndAddNewPtNodes(
return false;
}
// Write the 2nd part of the reallocating node.
- if (!writePtNodeToBufferByCopyingPtNodeInfo(reallocatingPtNode,
- reallocatingPtNode->getNodePos(),
+ const int secondPartOfReallocatedPtNodePos = writingPos;
+ if (!writePtNodeToBufferByCopyingPtNodeInfo(reallocatingPtNode, firstPartOfReallocatedPtNodePos,
reallocatingPtNodeCodePoints + overlappingCodePointCount,
reallocatingPtNode->getCodePointCount() - overlappingCodePointCount,
reallocatingPtNode->getProbability(), &writingPos)) {
return false;
}
if (addsExtraChild) {
- if (!writePtNodeToBuffer(reallocatingPtNode->getNodePos(),
+ if (!writePtNodeToBuffer(firstPartOfReallocatedPtNodePos,
newNodeCodePoints + overlappingCodePointCount,
newNodeCodePointCount - overlappingCodePointCount, probabilityOfNewPtNode,
&writingPos)) {
@@ -344,9 +348,14 @@ bool DynamicPatriciaTrieWritingHelper::reallocatePtNodeAndAddNewPtNodes(
NOT_A_DICT_POS /* forwardLinkPos */, &writingPos)) {
return false;
}
+ // Update original reallocatingPtNode as moved.
+ if (!markNodeAsMovedAndSetPosition(reallocatingPtNode, firstPartOfReallocatedPtNodePos,
+ secondPartOfReallocatedPtNodePos)) {
+ return false;
+ }
// Load node info. Information of the 1st part will be fetched.
DynamicPatriciaTrieNodeReader nodeReader(mBuffer, mBigramPolicy, mShortcutPolicy);
- nodeReader.fetchNodeInfoFromBuffer(firstPtNodePos);
+ nodeReader.fetchNodeInfoFromBuffer(firstPartOfReallocatedPtNodePos);
// Update children position.
int childrenPosFieldPos = nodeReader.getChildrenPosFieldPos();
if (!DynamicPatriciaTrieWritingUtils::writeChildrenPositionAndAdvancePosition(mBuffer,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h
index ada634a54..e1b9d2e75 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dynamic_patricia_trie_writing_helper.h
@@ -54,7 +54,7 @@ class DynamicPatriciaTrieWritingHelper {
DynamicShortcutListPolicy *const mShortcutPolicy;
bool markNodeAsMovedAndSetPosition(const DynamicPatriciaTrieNodeReader *const nodeToUpdate,
- const int movedPos);
+ const int movedPos, const int bigramLinkedNodePos);
bool writePtNodeWithFullInfoToBuffer(const bool isBlacklisted, const bool isNotAWord,
const int parentPos, const int *const codePoints, const int codePointCount,
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index 2603b35f5..234bb1b31 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -259,7 +259,8 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
protected void pickSuggestionManually(final int index, final String suggestion) {
mLatinIME.pickSuggestionManually(index, new SuggestedWordInfo(suggestion, 1,
SuggestedWordInfo.KIND_CORRECTION, null /* sourceDict */,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
}
// Helper to avoid writing the try{}catch block each time
diff --git a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
index a5f3685da..4cf83339a 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
@@ -35,11 +35,13 @@ public class SuggestedWordsTests extends AndroidTestCase {
final ArrayList<SuggestedWordInfo> list = CollectionUtils.newArrayList();
list.add(new SuggestedWordInfo(TYPED_WORD, TYPED_WORD_FREQ,
SuggestedWordInfo.KIND_TYPED, null /* sourceDict */,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) {
list.add(new SuggestedWordInfo("" + i, 1, SuggestedWordInfo.KIND_CORRECTION,
null /* sourceDict */,
- SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */));
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
}
final SuggestedWords words = new SuggestedWords(
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
index 2d57100f5..807c25244 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictDecoderEncoderTests.java
@@ -25,6 +25,7 @@ import android.util.SparseArray;
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.CharEncoding;
import com.android.inputmethod.latin.makedict.BinaryDictDecoderUtils.DictBuffer;
import com.android.inputmethod.latin.makedict.FormatSpec.FileHeader;
+import com.android.inputmethod.latin.makedict.FusionDictionary.DictionaryOptions;
import com.android.inputmethod.latin.makedict.FusionDictionary.PtNode;
import com.android.inputmethod.latin.makedict.FusionDictionary.PtNodeArray;
import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
@@ -264,6 +265,27 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
return result + ", supportsDynamicUpdate = " + formatOptions.mSupportsDynamicUpdate;
}
+ private DictionaryOptions getDictionaryOptions(final String id, final String version) {
+ final DictionaryOptions options = new DictionaryOptions(new HashMap<String, String>(),
+ false, false);
+ options.mAttributes.put("version", version);
+ options.mAttributes.put("dictionary", id);
+ return options;
+ }
+
+ private File setUpDictionaryFile(final String name, final String version) {
+ File file = null;
+ try {
+ file = new File(getContext().getCacheDir(), name + "." + version
+ + TEST_DICT_FILE_EXTENSION);
+ file.createNewFile();
+ } catch (IOException e) {
+ // do nothing
+ }
+ assertTrue("Failed to create the dictionary file.", file.exists());
+ return file;
+ }
+
// Tests for readDictionaryBinary and writeDictionaryBinary
private long timeReadingAndCheckDict(final File file, final List<String> words,
@@ -292,17 +314,13 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
final SparseArray<List<Integer>> bigrams, final HashMap<String, List<String>> shortcuts,
final int bufferType, final FormatSpec.FormatOptions formatOptions,
final String message) {
- File file = null;
- try {
- file = File.createTempFile("runReadAndWrite", TEST_DICT_FILE_EXTENSION,
- getContext().getCacheDir());
- } catch (IOException e) {
- Log.e(TAG, "IOException", e);
- }
- assertNotNull(file);
+
+ final String dictName = "runReadAndWrite";
+ final String dictVersion = Long.toString(System.currentTimeMillis());
+ final File file = setUpDictionaryFile(dictName, dictVersion);
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
- new FusionDictionary.DictionaryOptions(new HashMap<String,String>(), false, false));
+ getDictionaryOptions(dictName, dictVersion));
addUnigrams(words.size(), dict, words, shortcuts);
addBigrams(dict, words, bigrams);
checkDictionary(dict, words, bigrams, shortcuts);
@@ -454,19 +472,13 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
private String runReadUnigramsAndBigramsBinary(final ArrayList<String> words,
final SparseArray<List<Integer>> bigrams, final int bufferType,
final FormatSpec.FormatOptions formatOptions, final String message) {
- File file = null;
- try {
- file = File.createTempFile("runReadUnigrams", TEST_DICT_FILE_EXTENSION,
- getContext().getCacheDir());
- } catch (IOException e) {
- Log.e(TAG, "IOException", e);
- }
- assertNotNull(file);
+ final String dictName = "runReadUnigrams";
+ final String dictVersion = Long.toString(System.currentTimeMillis());
+ final File file = setUpDictionaryFile(dictName, dictVersion);
// making the dictionary from lists of words.
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
- new FusionDictionary.DictionaryOptions(
- new HashMap<String, String>(), false, false));
+ getDictionaryOptions(dictName, dictVersion));
addUnigrams(words.size(), dict, words, null /* shortcutMap */);
addBigrams(dict, words, bigrams);
@@ -552,18 +564,12 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
}
public void testGetTerminalPosition() {
- File file = null;
- try {
- file = File.createTempFile("testGetTerminalPosition", TEST_DICT_FILE_EXTENSION,
- getContext().getCacheDir());
- } catch (IOException e) {
- // do nothing
- }
- assertNotNull(file);
+ final String dictName = "testGetTerminalPosition";
+ final String dictVersion = Long.toString(System.currentTimeMillis());
+ final File file = setUpDictionaryFile(dictName, dictVersion);
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
- new FusionDictionary.DictionaryOptions(
- new HashMap<String, String>(), false, false));
+ getDictionaryOptions(dictName, dictVersion));
addUnigrams(sWords.size(), dict, sWords, null /* shortcutMap */);
timeWritingDictToFile(file, dict, VERSION3_WITH_DYNAMIC_UPDATE);
@@ -609,14 +615,9 @@ public class BinaryDictDecoderEncoderTests extends AndroidTestCase {
}
public void testDeleteWord() {
- File file = null;
- try {
- file = File.createTempFile("testDeleteWord", TEST_DICT_FILE_EXTENSION,
- getContext().getCacheDir());
- } catch (IOException e) {
- // do nothing
- }
- assertNotNull(file);
+ final String dictName = "testDeleteWord";
+ final String dictVersion = Long.toString(System.currentTimeMillis());
+ final File file = setUpDictionaryFile(dictName, dictVersion);
final FusionDictionary dict = new FusionDictionary(new PtNodeArray(),
new FusionDictionary.DictionaryOptions(
diff --git a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
index d15e88bdb..bf44a1424 100644
--- a/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/personalization/UserHistoryDictionaryTests.java
@@ -46,6 +46,7 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
};
private static final int MIN_USER_HISTORY_DICTIONARY_FILE_SIZE = 1000;
+ private static final int WAIT_TERMINATING_IN_MILLISECONDS = 100;
@Override
public void setUp() {
@@ -122,8 +123,14 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
true /* checksContents */);
} finally {
try {
+ final UserHistoryPredictionDictionary dict =
+ PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(),
+ testFilenameSuffix, mPrefs);
Log.d(TAG, "waiting for writing ...");
- Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS));
+ dict.shutdownExecutorForTests();
+ while (!dict.isTerminatedForTests()) {
+ Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS);
+ }
} catch (InterruptedException e) {
Log.d(TAG, "InterruptedException: " + e);
}
@@ -146,11 +153,11 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
final int numberOfWordsInsertedForEachLanguageSwitch = 100;
final File dictFiles[] = new File[numberOfLanguages];
+ final String testFilenameSuffixes[] = new String[numberOfLanguages];
try {
final Random random = new Random(123456);
// Create filename suffixes for this test.
- String testFilenameSuffixes[] = new String[numberOfLanguages];
for (int i = 0; i < numberOfLanguages; i++) {
testFilenameSuffixes[i] = "testSwitchingLanguages" + i;
final String fileName = UserHistoryPredictionDictionary.NAME + "." +
@@ -174,7 +181,15 @@ public class UserHistoryDictionaryTests extends AndroidTestCase {
} finally {
try {
Log.d(TAG, "waiting for writing ...");
- Thread.sleep(TimeUnit.MILLISECONDS.convert(5L, TimeUnit.SECONDS));
+ for (int i = 0; i < numberOfLanguages; i++) {
+ final UserHistoryPredictionDictionary dict =
+ PersonalizationHelper.getUserHistoryPredictionDictionary(getContext(),
+ testFilenameSuffixes[i], mPrefs);
+ dict.shutdownExecutorForTests();
+ while (!dict.isTerminatedForTests()) {
+ Thread.sleep(WAIT_TERMINATING_IN_MILLISECONDS);
+ }
+ }
} catch (InterruptedException e) {
Log.d(TAG, "InterruptedException: " + e);
}
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>