aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/res/values-sw/strings.xml2
-rw-r--r--java/res/xml-sw600dp/keys_arabic3_left.xml32
-rw-r--r--java/res/xml-sw600dp/keys_farsi3_right.xml32
-rw-r--r--java/res/xml-sw600dp/rowkeys_arabic1.xml112
-rw-r--r--java/res/xml-sw600dp/rowkeys_arabic2.xml94
-rw-r--r--java/res/xml-sw600dp/rowkeys_arabic3.xml70
-rw-r--r--java/res/xml-sw600dp/rowkeys_farsi1.xml107
-rw-r--r--java/res/xml-sw600dp/rowkeys_farsi2.xml84
-rw-r--r--java/res/xml-sw600dp/rowkeys_farsi3.xml66
-rw-r--r--java/res/xml-sw600dp/rows_arabic.xml3
-rw-r--r--java/res/xml-sw600dp/rows_farsi.xml8
-rw-r--r--java/res/xml-sw768dp/rows_arabic.xml2
-rw-r--r--java/res/xml-sw768dp/rows_farsi.xml12
-rw-r--r--java/res/xml/keys_arabic3_left.xml28
-rw-r--r--java/res/xml/keys_farsi3_right.xml28
-rw-r--r--java/res/xml/method.xml18
-rw-r--r--java/res/xml/rowkeys_arabic1.xml54
-rw-r--r--java/res/xml/rowkeys_arabic2.xml8
-rw-r--r--java/res/xml/rowkeys_arabic3.xml42
-rw-r--r--java/res/xml/rowkeys_east_slavic1.xml3
-rw-r--r--java/res/xml/rowkeys_east_slavic2.xml6
-rw-r--r--java/res/xml/rowkeys_farsi1.xml56
-rw-r--r--java/res/xml/rowkeys_farsi2.xml11
-rw-r--r--java/res/xml/rowkeys_farsi3.xml22
-rw-r--r--java/res/xml/rows_arabic.xml12
-rw-r--r--java/res/xml/rows_farsi.xml12
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/ActionBatch.java4
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DictionaryService.java12
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java25
-rw-r--r--java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java14
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java5
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java9
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java1
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java49
-rw-r--r--java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java1
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java9
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java17
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java1251
-rw-r--r--java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java78
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java1
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java10
-rw-r--r--java/src/com/android/inputmethod/latin/Constants.java7
-rw-r--r--java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java6
-rw-r--r--java/src/com/android/inputmethod/latin/DebugSettings.java4
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryWriter.java107
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java180
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableDictionary.java364
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java55
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java109
-rw-r--r--java/src/com/android/inputmethod/latin/SettingsFragment.java4
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java15
-rw-r--r--java/src/com/android/inputmethod/latin/UserBinaryDictionary.java6
-rw-r--r--java/src/com/android/inputmethod/latin/UserHistoryDictionary.java6
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java34
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java4
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java5
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java5
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java65
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java6
-rw-r--r--java/src/com/android/inputmethod/latin/utils/LatinImeLoggerUtils.java77
-rw-r--r--java/src/com/android/inputmethod/latin/utils/TextRange.java116
-rw-r--r--java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java (renamed from java/src/com/android/inputmethod/keyboard/TypefaceUtils.java)4
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UsabilityStudyLogUtils.java255
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java7
-rw-r--r--java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java1
-rw-r--r--java/src/com/android/inputmethod/latin/utils/Utils.java374
-rw-r--r--java/src/com/android/inputmethod/latin/utils/ViewLayoutUtils.java (renamed from java/src/com/android/inputmethod/keyboard/ViewLayoutUtils.java)8
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLog.java2
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java22
-rw-r--r--java/src/com/android/inputmethod/research/Statistics.java6
-rw-r--r--java/src/com/android/inputmethod/research/UploaderService.java1
-rw-r--r--native/jni/Android.mk3
-rw-r--r--native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp6
-rw-r--r--native/jni/src/defines.h76
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node.h61
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node_properties.h32
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node_proximity_filter.h58
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node_utils.cpp91
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node_utils.h26
-rw-r--r--native/jni/src/suggest/core/dicnode/dic_node_vector.h13
-rw-r--r--native/jni/src/suggest/core/dictionary/binary_dictionary_format_utils.cpp53
-rw-r--r--native/jni/src/suggest/core/dictionary/binary_dictionary_format_utils.h8
-rw-r--r--native/jni/src/suggest/core/dictionary/binary_dictionary_header.h14
-rw-r--r--native/jni/src/suggest/core/dictionary/binary_dictionary_header_reading_utils.cpp38
-rw-r--r--native/jni/src/suggest/core/dictionary/binary_dictionary_header_reading_utils.h49
-rw-r--r--native/jni/src/suggest/core/dictionary/binary_dictionary_info.h37
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary.cpp6
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary.h4
-rw-r--r--native/jni/src/suggest/core/dictionary/terminal_attributes.h22
-rw-r--r--native/jni/src/suggest/core/layout/proximity_info_utils.h4
-rw-r--r--native/jni/src/suggest/core/policy/traversal.h2
-rw-r--r--native/jni/src/suggest/core/suggest.cpp75
-rw-r--r--native/jni/src/suggest/core/suggest.h2
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_policy_factory.h5
-rw-r--r--native/jni/src/suggest/policyimpl/typing/typing_traversal.h5
-rw-r--r--native/jni/src/suggest/policyimpl/typing/typing_weighting.h7
-rw-r--r--native/jni/src/utils/log_utils.cpp72
-rw-r--r--native/jni/src/utils/log_utils.h37
-rw-r--r--tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java24
-rw-r--r--tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java52
-rw-r--r--tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java133
-rw-r--r--tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java8
-rw-r--r--tests/src/com/android/inputmethod/latin/WordComposerTests.java93
-rw-r--r--tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java69
-rw-r--r--tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java15
-rw-r--r--tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java13
-rw-r--r--tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java77
-rw-r--r--tools/maketext/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl2
-rw-r--r--tools/maketext/res/values-az/donottranslate-more-keys.xml59
-rw-r--r--tools/maketext/res/values-kk/donottranslate-more-keys.xml57
-rw-r--r--tools/maketext/res/values/donottranslate-more-keys.xml3
111 files changed, 3139 insertions, 2537 deletions
diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml
index 50ae4dcae..cd31740b6 100644
--- a/java/res/values-sw/strings.xml
+++ b/java/res/values-sw/strings.xml
@@ -75,7 +75,7 @@
<string name="gesture_floating_preview_text_summary" msgid="4472696213996203533">"Onyesha neno lililopendekezwa unapoonyesha ishara"</string>
<string name="added_word" msgid="8993883354622484372">"<xliff:g id="WORD">%s</xliff:g> : Imehifadhiwa"</string>
<string name="label_go_key" msgid="1635148082137219148">"Nenda"</string>
- <string name="label_next_key" msgid="362972844525672568">"Ifuatayo"</string>
+ <string name="label_next_key" msgid="362972844525672568">"Inayofuata"</string>
<string name="label_previous_key" msgid="1211868118071386787">"Iliyotangulia"</string>
<string name="label_done_key" msgid="2441578748772529288">"Kwisha"</string>
<string name="label_send_key" msgid="2815056534433717444">"Tuma"</string>
diff --git a/java/res/xml-sw600dp/keys_arabic3_left.xml b/java/res/xml-sw600dp/keys_arabic3_left.xml
new file mode 100644
index 000000000..0f2ccc0ac
--- /dev/null
+++ b/java/res/xml-sw600dp/keys_arabic3_left.xml
@@ -0,0 +1,32 @@
+<?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"
+>
+ <!-- U+0630: "ذ" ARABIC LETTER THAL -->
+ <Key
+ latin:keyLabel="&#x0630;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE -->
+ <Key
+ latin:keyLabel="&#x0626;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml-sw600dp/keys_farsi3_right.xml b/java/res/xml-sw600dp/keys_farsi3_right.xml
new file mode 100644
index 000000000..3c91ae92d
--- /dev/null
+++ b/java/res/xml-sw600dp/keys_farsi3_right.xml
@@ -0,0 +1,32 @@
+<?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"
+>
+ <!-- U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE -->
+ <Key
+ latin:keyLabel="&#x0622;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0686: "چ" ARABIC LETTER TCHEH -->
+ <Key
+ latin:keyLabel="&#x0686;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_arabic1.xml b/java/res/xml-sw600dp/rowkeys_arabic1.xml
deleted file mode 100644
index 3c0acf112..000000000
--- a/java/res/xml-sw600dp/rowkeys_arabic1.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <!-- U+0636: "ض" ARABIC LETTER DAD
- U+0661: "١" ARABIC-INDIC DIGIT ONE -->
- <Key
- latin:keyLabel="&#x0636;"
- latin:keyHintLabel="1"
- latin:additionalMoreKeys="1,&#x0661;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0635: "ص" ARABIC LETTER SAD
- U+0662: "٢" ARABIC-INDIC DIGIT TWO -->
- <Key
- latin:keyLabel="&#x0635;"
- latin:keyHintLabel="2"
- latin:additionalMoreKeys="2,&#x0662;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+062B: "ث" ARABIC LETTER THEH
- U+0663: "٣" ARABIC-INDIC DIGIT THREE -->
- <Key
- latin:keyLabel="&#x062B;"
- latin:keyHintLabel="3"
- latin:additionalMoreKeys="3,&#x0663;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0642: "ق" ARABIC LETTER QAF
- U+06A8: "ڨ" ARABIC LETTER QAF WITH THREE DOTS ABOVE
- U+0664: "٤" ARABIC-INDIC DIGIT FOUR -->
- <!-- TODO: DroidSansArabic lacks the glyph of U+06A8 ARABIC LETTER QAF WITH THREE DOTS ABOVE -->
- <Key
- latin:keyLabel="&#x0642;"
- latin:keyHintLabel="4"
- latin:additionalMoreKeys="4,&#x0664;"
- latin:moreKeys="&#x06A8;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0641: "ف" ARABIC LETTER FEH
- U+06A4: "ڤ" ARABIC LETTER VEH
- U+06A2: "ڢ" ARABIC LETTER FEH WITH DOT MOVED BELOW
- U+06A5: "ڥ" ARABIC LETTER FEH WITH THREE DOTS BELOW
- U+0665: "٥" ARABIC-INDIC DIGIT FIVE -->
- <!-- TODO: DroidSansArabic lacks the glyph of U+06A2 ARABIC LETTER FEH WITH DOT MOVED BELOW -->
- <!-- TODO: DroidSansArabic lacks the glyph of U+06A5 ARABIC LETTER FEH WITH THREE DOTS BELOW -->
- <Key
- latin:keyLabel="&#x0641;"
- latin:keyHintLabel="5"
- latin:additionalMoreKeys="5,&#x0665;"
- latin:moreKeys="&#x06A4;,&#x06A2;,&#x06A5;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+063A: "غ" ARABIC LETTER GHAIN
- U+0666: "٦" ARABIC-INDIC DIGIT SIX -->
- <Key
- latin:keyLabel="&#x063A;"
- latin:keyHintLabel="6"
- latin:additionalMoreKeys="6,&#x0666;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0639: "ع" ARABIC LETTER AIN
- U+0667: "٧" ARABIC-INDIC DIGIT SEVEN -->
- <Key
- latin:keyLabel="&#x0639;"
- latin:keyHintLabel="7"
- latin:additionalMoreKeys="7,&#x0667;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0647: "ه" ARABIC LETTER HEH
- U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM
- U+0647 U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER
- U+0668: "٨" ARABIC-INDIC DIGIT EIGHT -->
- <Key
- latin:keyLabel="&#x0647;"
- latin:keyHintLabel="8"
- latin:additionalMoreKeys="8,&#x0668;"
- latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+062E: "خ" ARABIC LETTER KHAH
- U+0669: "٩" ARABIC-INDIC DIGIT NINE -->
- <Key
- latin:keyLabel="&#x062E;"
- latin:keyHintLabel="9"
- latin:additionalMoreKeys="9,&#x0669;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+062D: "ح" ARABIC LETTER HAH
- U+0660: "٠" ARABIC-INDIC DIGIT ZERO -->
- <Key
- latin:keyLabel="&#x062D;"
- latin:keyHintLabel="0"
- latin:additionalMoreKeys="0,&#x0660;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+062C: "ج" ARABIC LETTER JEEM
- U+0686: "چ" ARABIC LETTER TCHEH -->
- <Key
- latin:keyLabel="&#x062C;"
- latin:moreKeys="&#x0686;"
- latin:keyLabelFlags="fontNormal" />
-</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_arabic2.xml b/java/res/xml-sw600dp/rowkeys_arabic2.xml
deleted file mode 100644
index 00e69ace7..000000000
--- a/java/res/xml-sw600dp/rowkeys_arabic2.xml
+++ /dev/null
@@ -1,94 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <!-- U+0634: "ش" ARABIC LETTER SHEEN
- U+069C: "ڜ" ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE -->
- <!-- TODO: DroidSansArabic lacks the glyph of U+069C ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE -->
- <Key
- latin:keyLabel="&#x0634;"
- latin:moreKeys="&#x069C;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0633: "س" ARABIC LETTER SEEN -->
- <Key
- latin:keyLabel="&#x0633;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+064A: "ي" ARABIC LETTER YEH
- U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE
- U+0649: "ى" ARABIC LETTER ALEF MAKSURA -->
- <Key
- latin:keyLabel="&#x064A;"
- latin:moreKeys="&#x0626;,&#x0649;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0628: "ب" ARABIC LETTER BEH
- U+067E: "پ" ARABIC LETTER PEH -->
- <Key
- latin:keyLabel="&#x0628;"
- latin:moreKeys="&#x067E;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0644: "ل" ARABIC LETTER LAM
- U+FEFB: "ﻻ" ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM
- U+0627: "ا" ARABIC LETTER ALEF
- U+FEF7: "ﻷ" ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM
- U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE
- U+FEF9: "ﻹ" ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM
- U+0625: "إ" ARABIC LETTER ALEF WITH HAMZA BELOW
- U+FEF5: "ﻵ" ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM
- U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE -->
- <Key
- latin:keyLabel="&#x0644;"
- latin:moreKeys="&#xFEFB;|&#x0644;&#x0627;,&#xFEF7;|&#x0644;&#x0623;,&#xFEF9;|&#x0644;&#x0625;,&#xFEF5;|&#x0644;&#x0622;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0627: "ا" ARABIC LETTER ALEF
- U+0621: "ء" ARABIC LETTER HAMZA
- U+0671: "ٱ" ARABIC LETTER ALEF WASLA
- U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE
- U+0625: "إ" ARABIC LETTER ALEF WITH HAMZA BELOW
- U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE -->
- <Key
- latin:keyLabel="&#x0627;"
- latin:moreKeys="&#x0621;,&#x0671;,&#x0623;,&#x0625;,&#x0622;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+062A: "ت" ARABIC LETTER TEH -->
- <Key
- latin:keyLabel="&#x062A;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0646: "ن" ARABIC LETTER NOON -->
- <Key
- latin:keyLabel="&#x0646;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0645: "م" ARABIC LETTER MEEM -->
- <Key
- latin:keyLabel="&#x0645;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0643: "ك" ARABIC LETTER KAF
- U+06AF: "گ" ARABIC LETTER GAF
- U+06A9: "ک" ARABIC LETTER KEHEH -->
- <Key
- latin:keyLabel="&#x0643;"
- latin:moreKeys="&#x06AF;,&#x06A9;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0637: "ط" ARABIC LETTER TAH -->
- <Key
- latin:keyLabel="&#x0637;"
- latin:keyLabelFlags="fontNormal" />
-</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_arabic3.xml b/java/res/xml-sw600dp/rowkeys_arabic3.xml
deleted file mode 100644
index b0bcd78d6..000000000
--- a/java/res/xml-sw600dp/rowkeys_arabic3.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <!-- U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE -->
- <Key
- latin:keyLabel="&#x0626;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0621: "ء" ARABIC LETTER HAMZA -->
- <Key
- latin:keyLabel="&#x0621;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0624: "ؤ" ARABIC LETTER WAW WITH HAMZA ABOVE -->
- <Key
- latin:keyLabel="&#x0624;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0631: "ر" ARABIC LETTER REH -->
- <Key
- latin:keyLabel="&#x0631;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0630: "ذ" ARABIC LETTER THAL -->
- <Key
- latin:keyLabel="&#x0630;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0649: "ى" ARABIC LETTER ALEF MAKSURA -->
- <Key
- latin:keyLabel="&#x0649;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0629: "ة" ARABIC LETTER TEH MARBUTA -->
- <Key
- latin:keyLabel="&#x0629;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0648: "و" ARABIC LETTER WAW -->
- <Key
- latin:keyLabel="&#x0648;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0632: "ز" ARABIC LETTER ZAIN
- U+0698: "ژ" ARABIC LETTER JEH -->
- <Key
- latin:keyLabel="&#x0632;"
- latin:moreKeys="&#x0698;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0638: "ظ" ARABIC LETTER ZAH -->
- <Key
- latin:keyLabel="&#x0638;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+062F: "د" ARABIC LETTER DAL -->
- <Key
- latin:keyLabel="&#x062F;"
- latin:keyLabelFlags="fontNormal" />
-</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_farsi1.xml b/java/res/xml-sw600dp/rowkeys_farsi1.xml
deleted file mode 100644
index 6dd9a6575..000000000
--- a/java/res/xml-sw600dp/rowkeys_farsi1.xml
+++ /dev/null
@@ -1,107 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <!-- U+0636: "ض" ARABIC LETTER DAD
- U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE -->
- <Key
- latin:keyLabel="&#x0636;"
- latin:keyHintLabel="&#x06F1;"
- latin:additionalMoreKeys="&#x06F1;,1"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0635: "ص" ARABIC LETTER SAD
- U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO -->
- <Key
- latin:keyLabel="&#x0635;"
- latin:keyHintLabel="&#x06F2;"
- latin:additionalMoreKeys="&#x06F2;,2"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+062B: "ث" ARABIC LETTER THEH
- U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE -->
- <Key
- latin:keyLabel="&#x062B;"
- latin:keyHintLabel="&#x06F3;"
- latin:additionalMoreKeys="&#x06F3;,3"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0642: "ق" ARABIC LETTER QAF
- U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR -->
- <Key
- latin:keyLabel="&#x0642;"
- latin:keyHintLabel="&#x06F4;"
- latin:additionalMoreKeys="&#x06F4;,4"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0641: "ف" ARABIC LETTER FEH
- U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE -->
- <Key
- latin:keyLabel="&#x0641;"
- latin:keyHintLabel="&#x06F5;"
- latin:additionalMoreKeys="&#x06F5;,5"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+063A: "غ" ARABIC LETTER GHAIN
- U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX -->
- <Key
- latin:keyLabel="&#x063A;"
- latin:keyHintLabel="&#x06F6;"
- latin:additionalMoreKeys="&#x06F6;,6"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0639: "ع" ARABIC LETTER AIN
- U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN -->
- <Key
- latin:keyLabel="&#x0639;"
- latin:keyHintLabel="&#x06F7;"
- latin:additionalMoreKeys="&#x06F7;,7"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0647: "ه" ARABIC LETTER HEH
- U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM
- U+0647/U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER
- U+0647/U+0654: ARABIC LETTER HEH + ARABIC HAMZA ABOVE
- U+0629: "ة" ARABIC LETTER TEH MARBUTA
- U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT -->
- <Key
- latin:keyLabel="&#x0647;"
- latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;,&#x0647;&#x0654;,&#x0629;,%"
- latin:keyHintLabel="&#x06F8;"
- latin:additionalMoreKeys="&#x06F8;,8"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+062E: "خ" ARABIC LETTER KHAH
- U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE -->
- <Key
- latin:keyLabel="&#x062E;"
- latin:keyHintLabel="&#x06F9;"
- latin:additionalMoreKeys="&#x06F9;,9"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+062D: "ح" ARABIC LETTER HAH
- U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO -->
- <Key
- latin:keyLabel="&#x062D;"
- latin:keyHintLabel="&#x06F0;"
- latin:additionalMoreKeys="&#x06F0;,0"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+062C: "ج" ARABIC LETTER JEEM -->
- <Key
- latin:keyLabel="&#x062C;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0686: "چ" ARABIC LETTER TCHEH -->
- <Key
- latin:keyLabel="&#x0686;"
- latin:keyLabelFlags="fontNormal" />
-</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_farsi2.xml b/java/res/xml-sw600dp/rowkeys_farsi2.xml
deleted file mode 100644
index 3b759b66c..000000000
--- a/java/res/xml-sw600dp/rowkeys_farsi2.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <!-- U+0634: "ش" ARABIC LETTER SHEEN -->
- <Key
- latin:keyLabel="&#x0634;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0633: "س" ARABIC LETTER SEEN -->
- <Key
- latin:keyLabel="&#x0633;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+06CC: "ی" ARABIC LETTER FARSI YEH
- U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE
- U+064A: "ي" ARABIC LETTER YEH
- U+FBE8: "ﯨ" ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM
- U+0649: "ى" ARABIC LETTER ALEF MAKSURA -->
- <Key
- latin:keyLabel="&#x06CC;"
- latin:moreKeys="&#x0626;,&#x064A;,&#xFBE8;|&#x0649;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0628: "ب" ARABIC LETTER BEH -->
- <Key
- latin:keyLabel="&#x0628;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0644: "ل" ARABIC LETTER LAM -->
- <Key
- latin:keyLabel="&#x0644;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0627: "ا" ARABIC LETTER ALEF
- U+0621: "ء" ARABIC LETTER HAMZA
- U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE
- U+0623: "أ" ARABIC LETTER ALEF WITH HAMZA ABOVE
- U+0671: "ٱ" ARABIC LETTER ALEF WASLA
- U+0625: "إ" ARABIC LETTER ALEF WITH HAMZA BELOW -->
- <Key
- latin:keyLabel="&#x0627;"
- latin:moreKeys="&#x0621;,&#x0622;,&#x0623;,&#x0671;,&#x0625;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+062A: "ت" ARABIC LETTER TEH
- U+062B: "ﺙ" ARABIC LETTER THEH
- U+0629: "ة": ARABIC LETTER TEH MARBUTA -->
- <Key
- latin:keyLabel="&#x062A;"
- latin:moreKeys="&#x062B;,&#x0629;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0646: "ن" ARABIC LETTER NOON -->
- <Key
- latin:keyLabel="&#x0646;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0645: "م" ARABIC LETTER MEEM -->
- <Key
- latin:keyLabel="&#x0645;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+06A9: "ک" ARABIC LETTER KEHEH
- U+0643: "ك" ARABIC LETTER KAF -->
- <Key
- latin:keyLabel="&#x06A9;"
- latin:moreKeys="&#x0643;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+06AF: "گ" ARABIC LETTER GAF -->
- <Key
- latin:keyLabel="&#x06AF;"
- latin:keyLabelFlags="fontNormal" />
-</merge>
diff --git a/java/res/xml-sw600dp/rowkeys_farsi3.xml b/java/res/xml-sw600dp/rowkeys_farsi3.xml
deleted file mode 100644
index 3597618ce..000000000
--- a/java/res/xml-sw600dp/rowkeys_farsi3.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<merge
- xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
->
- <!-- U+0638: "ظ" ARABIC LETTER ZAH -->
- <Key
- latin:keyLabel="&#x0638;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0637: "ط" ARABIC LETTER TAH -->
- <Key
- latin:keyLabel="&#x0637;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0698: "ژ" ARABIC LETTER JEH -->
- <Key
- latin:keyLabel="&#x0698;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0632: "ز" ARABIC LETTER ZAIN -->
- <Key
- latin:keyLabel="&#x0632;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0631: "ر" ARABIC LETTER REH -->
- <Key
- latin:keyLabel="&#x0631;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0630: "ذ" ARABIC LETTER THAL -->
- <Key
- latin:keyLabel="&#x0630;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+062F: "د" ARABIC LETTER DAL -->
- <Key
- latin:keyLabel="&#x062F;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+067E: "پ" ARABIC LETTER PEH -->
- <Key
- latin:keyLabel="&#x067E;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0648: "و" ARABIC LETTER WAW
- U+0624: "ؤ" ARABIC LETTER WAW WITH HAMZA ABOVE -->
- <Key
- latin:keyLabel="&#x0648;"
- latin:moreKeys="&#x0624;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0622: "آ" ARABIC LETTER ALEF WITH MADDA ABOVE -->
- <Key
- latin:keyLabel="&#x0622;"
- latin:keyLabelFlags="fontNormal" />
-</merge>
diff --git a/java/res/xml-sw600dp/rows_arabic.xml b/java/res/xml-sw600dp/rows_arabic.xml
index ec7c2ad96..5a28d4572 100644
--- a/java/res/xml-sw600dp/rows_arabic.xml
+++ b/java/res/xml-sw600dp/rows_arabic.xml
@@ -45,8 +45,7 @@
latin:keyWidth="8.182%p"
>
<include
- latin:keyboardLayout="@xml/rowkeys_arabic3"
- latin:keyXPos="4.091%p" />
+ latin:keyboardLayout="@xml/rowkeys_arabic3" />
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml-sw600dp/rows_farsi.xml b/java/res/xml-sw600dp/rows_farsi.xml
index 52c2d9329..a353b67c7 100644
--- a/java/res/xml-sw600dp/rows_farsi.xml
+++ b/java/res/xml-sw600dp/rows_farsi.xml
@@ -28,6 +28,9 @@
>
<include
latin:keyboardLayout="@xml/rowkeys_farsi1" />
+ <Key
+ latin:keyStyle="deleteKeyStyle"
+ latin:keyWidth="fillRight" />
</Row>
<Row
latin:keyWidth="8.182%p"
@@ -35,7 +38,7 @@
<include
latin:keyboardLayout="@xml/rowkeys_farsi2" />
<Key
- latin:keyStyle="deleteKeyStyle"
+ latin:keyStyle="enterKeyStyle"
latin:keyWidth="fillRight" />
</Row>
<Row
@@ -44,9 +47,6 @@
<include
latin:keyboardLayout="@xml/rowkeys_farsi3"
latin:keyXPos="4.091%p" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml-sw768dp/rows_arabic.xml b/java/res/xml-sw768dp/rows_arabic.xml
index 8b05d9376..204f6d590 100644
--- a/java/res/xml-sw768dp/rows_arabic.xml
+++ b/java/res/xml-sw768dp/rows_arabic.xml
@@ -54,7 +54,7 @@
>
<include
latin:keyboardLayout="@xml/rowkeys_arabic3"
- latin:keyXPos="13.829%p" />
+ latin:keyXPos="6.602%p" />
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml-sw768dp/rows_farsi.xml b/java/res/xml-sw768dp/rows_farsi.xml
index 4b4c970fd..8d3fb0579 100644
--- a/java/res/xml-sw768dp/rows_farsi.xml
+++ b/java/res/xml-sw768dp/rows_farsi.xml
@@ -32,6 +32,9 @@
latin:keyWidth="7.969%p" />
<include
latin:keyboardLayout="@xml/rowkeys_farsi1" />
+ <Key
+ latin:keyStyle="deleteKeyStyle"
+ latin:keyWidth="fillRight" />
</Row>
<Row
latin:keyWidth="7.227%p"
@@ -39,22 +42,19 @@
<Key
latin:keyStyle="toSymbolKeyStyle"
latin:keyLabelFlags="alignLeft"
- latin:keyWidth="11.172%p"/>
+ latin:keyWidth="11.172%p" />
<include
latin:keyboardLayout="@xml/rowkeys_farsi2" />
<Key
- latin:keyStyle="deleteKeyStyle"
+ latin:keyStyle="enterKeyStyle"
latin:keyWidth="fillRight" />
</Row>
<Row
- latin:keyWidth="7.186%p"
+ latin:keyWidth="7.227%p"
>
<include
latin:keyboardLayout="@xml/rowkeys_farsi3"
latin:keyXPos="13.829%p" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml/keys_arabic3_left.xml b/java/res/xml/keys_arabic3_left.xml
new file mode 100644
index 000000000..157af4a52
--- /dev/null
+++ b/java/res/xml/keys_arabic3_left.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.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+0630: "ذ" ARABIC LETTER THAL -->
+ <Key
+ latin:keyLabel="&#x0630;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml/keys_farsi3_right.xml b/java/res/xml/keys_farsi3_right.xml
new file mode 100644
index 000000000..77efb0a21
--- /dev/null
+++ b/java/res/xml/keys_farsi3_right.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.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- U+0686: "چ" ARABIC LETTER TCHEH -->
+ <Key
+ latin:keyLabel="&#x0686;"
+ latin:keyLabelFlags="fontNormal" />
+</merge>
diff --git a/java/res/xml/method.xml b/java/res/xml/method.xml
index f30ef2362..5e33601e6 100644
--- a/java/res/xml/method.xml
+++ b/java/res/xml/method.xml
@@ -21,9 +21,10 @@
<!-- for the Input Method Manager. -->
<!-- Supported subtypes
- keyboard_locale: script_name/keyboard_layout_set[:keyboard_locale]
+ keyboard_locale: script_name/keyboard_layout_set
af: Afrikaans/qwerty
ar: Arabic/arabic
+ az: Azerbaijani/qwerty
be: Belarusian/east_slavic
bg: Bulgarian/bulgarian
bg: Bulgarian/bulgarian_bds
@@ -51,6 +52,7 @@
it: Italian/qwerty
iw: Hebrew/hebrew # "he" is official language code of Hebrew.
ka: Georgian/georgian
+ kk: Kazakh/east_slavic
ky: Kyrgyz/east_slavic
lt: Lithuanian/qwerty
lv: Latvian/qwerty
@@ -117,6 +119,13 @@
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
+ android:subtypeId="0x2a362219"
+ android:imeSubtypeLocale="az"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="AsciiCapable,SupportTouchPositionCorrection"
+ />
+ <subtype android:icon="@drawable/ic_subtype_keyboard"
+ android:label="@string/subtype_generic"
android:subtypeId="0x1dc3a859"
android:imeSubtypeLocale="be"
android:imeSubtypeMode="keyboard"
@@ -296,6 +305,13 @@
/>
<subtype android:icon="@drawable/ic_subtype_keyboard"
android:label="@string/subtype_generic"
+ android:subtypeId="0x2d73d2f6"
+ android:imeSubtypeLocale="kk"
+ android:imeSubtypeMode="keyboard"
+ android:imeSubtypeExtraValue="KeyboardLayoutSet=east_slavic"
+ />
+ <subtype android:icon="@drawable/ic_subtype_keyboard"
+ android:label="@string/subtype_generic"
android:subtypeId="0x2e391c04"
android:imeSubtypeLocale="ky"
android:imeSubtypeMode="keyboard"
diff --git a/java/res/xml/rowkeys_arabic1.xml b/java/res/xml/rowkeys_arabic1.xml
index a4bef83c6..3c0acf112 100644
--- a/java/res/xml/rowkeys_arabic1.xml
+++ b/java/res/xml/rowkeys_arabic1.xml
@@ -35,74 +35,78 @@
latin:keyHintLabel="2"
latin:additionalMoreKeys="2,&#x0662;"
latin:keyLabelFlags="fontNormal" />
+ <!-- U+062B: "ث" ARABIC LETTER THEH
+ U+0663: "٣" ARABIC-INDIC DIGIT THREE -->
+ <Key
+ latin:keyLabel="&#x062B;"
+ latin:keyHintLabel="3"
+ latin:additionalMoreKeys="3,&#x0663;"
+ latin:keyLabelFlags="fontNormal" />
<!-- U+0642: "ق" ARABIC LETTER QAF
U+06A8: "ڨ" ARABIC LETTER QAF WITH THREE DOTS ABOVE
- U+0663: "٣" ARABIC-INDIC DIGIT THREE -->
+ U+0664: "٤" ARABIC-INDIC DIGIT FOUR -->
<!-- TODO: DroidSansArabic lacks the glyph of U+06A8 ARABIC LETTER QAF WITH THREE DOTS ABOVE -->
<Key
latin:keyLabel="&#x0642;"
- latin:keyHintLabel="3"
- latin:additionalMoreKeys="3,&#x0663;"
+ latin:keyHintLabel="4"
+ latin:additionalMoreKeys="4,&#x0664;"
latin:moreKeys="&#x06A8;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0641: "ف" ARABIC LETTER FEH
U+06A4: "ڤ" ARABIC LETTER VEH
U+06A2: "ڢ" ARABIC LETTER FEH WITH DOT MOVED BELOW
U+06A5: "ڥ" ARABIC LETTER FEH WITH THREE DOTS BELOW
- U+0664: "٤" ARABIC-INDIC DIGIT FOUR -->
+ U+0665: "٥" ARABIC-INDIC DIGIT FIVE -->
<!-- TODO: DroidSansArabic lacks the glyph of U+06A2 ARABIC LETTER FEH WITH DOT MOVED BELOW -->
<!-- TODO: DroidSansArabic lacks the glyph of U+06A5 ARABIC LETTER FEH WITH THREE DOTS BELOW -->
<Key
latin:keyLabel="&#x0641;"
- latin:keyHintLabel="4"
- latin:additionalMoreKeys="4,&#x0664;"
+ latin:keyHintLabel="5"
+ latin:additionalMoreKeys="5,&#x0665;"
latin:moreKeys="&#x06A4;,&#x06A2;,&#x06A5;"
latin:keyLabelFlags="fontNormal" />
<!-- U+063A: "غ" ARABIC LETTER GHAIN
- U+0665: "٥" ARABIC-INDIC DIGIT FIVE -->
+ U+0666: "٦" ARABIC-INDIC DIGIT SIX -->
<Key
latin:keyLabel="&#x063A;"
- latin:keyHintLabel="5"
- latin:additionalMoreKeys="5,&#x0665;"
+ latin:keyHintLabel="6"
+ latin:additionalMoreKeys="6,&#x0666;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0639: "ع" ARABIC LETTER AIN
- U+0666: "٦" ARABIC-INDIC DIGIT SIX -->
+ U+0667: "٧" ARABIC-INDIC DIGIT SEVEN -->
<Key
latin:keyLabel="&#x0639;"
- latin:keyHintLabel="6"
- latin:additionalMoreKeys="6,&#x0666;"
+ latin:keyHintLabel="7"
+ latin:additionalMoreKeys="7,&#x0667;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0647: "ه" ARABIC LETTER HEH
U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM
U+0647 U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER
- U+0667: "٧" ARABIC-INDIC DIGIT SEVEN -->
+ U+0668: "٨" ARABIC-INDIC DIGIT EIGHT -->
<Key
latin:keyLabel="&#x0647;"
- latin:keyHintLabel="7"
- latin:additionalMoreKeys="7,&#x0667;"
+ latin:keyHintLabel="8"
+ latin:additionalMoreKeys="8,&#x0668;"
latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;"
latin:keyLabelFlags="fontNormal" />
<!-- U+062E: "خ" ARABIC LETTER KHAH
- U+0668: "٨" ARABIC-INDIC DIGIT EIGHT -->
+ U+0669: "٩" ARABIC-INDIC DIGIT NINE -->
<Key
latin:keyLabel="&#x062E;"
- latin:keyHintLabel="8"
- latin:additionalMoreKeys="8,&#x0668;"
+ latin:keyHintLabel="9"
+ latin:additionalMoreKeys="9,&#x0669;"
latin:keyLabelFlags="fontNormal" />
<!-- U+062D: "ح" ARABIC LETTER HAH
- U+0669: "٩" ARABIC-INDIC DIGIT NINE -->
+ U+0660: "٠" ARABIC-INDIC DIGIT ZERO -->
<Key
latin:keyLabel="&#x062D;"
- latin:keyHintLabel="9"
- latin:additionalMoreKeys="9,&#x0669;"
+ latin:keyHintLabel="0"
+ latin:additionalMoreKeys="0,&#x0660;"
latin:keyLabelFlags="fontNormal" />
<!-- U+062C: "ج" ARABIC LETTER JEEM
- U+0686: "چ" ARABIC LETTER TCHEH
- U+0660: "٠" ARABIC-INDIC DIGIT ZERO -->
+ U+0686: "چ" ARABIC LETTER TCHEH -->
<Key
latin:keyLabel="&#x062C;"
- latin:keyHintLabel="0"
- latin:additionalMoreKeys="0,&#x0660;"
latin:moreKeys="&#x0686;"
latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml/rowkeys_arabic2.xml b/java/res/xml/rowkeys_arabic2.xml
index d733f6411..00e69ace7 100644
--- a/java/res/xml/rowkeys_arabic2.xml
+++ b/java/res/xml/rowkeys_arabic2.xml
@@ -68,11 +68,9 @@
latin:keyLabel="&#x0627;"
latin:moreKeys="&#x0621;,&#x0671;,&#x0623;,&#x0625;,&#x0622;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+062A: "ت" ARABIC LETTER TEH
- U+062B: "ﺙ" ARABIC LETTER THEH -->
+ <!-- U+062A: "ت" ARABIC LETTER TEH -->
<Key
latin:keyLabel="&#x062A;"
- latin:moreKeys="&#x062B;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0646: "ن" ARABIC LETTER NOON -->
<Key
@@ -89,4 +87,8 @@
latin:keyLabel="&#x0643;"
latin:moreKeys="&#x06AF;,&#x06A9;"
latin:keyLabelFlags="fontNormal" />
+ <!-- U+0637: "ط" ARABIC LETTER TAH -->
+ <Key
+ latin:keyLabel="&#x0637;"
+ latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml/rowkeys_arabic3.xml b/java/res/xml/rowkeys_arabic3.xml
index e4e694812..8a17b4b98 100644
--- a/java/res/xml/rowkeys_arabic3.xml
+++ b/java/res/xml/rowkeys_arabic3.xml
@@ -21,21 +21,33 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <!-- U+0638: "ظ" ARABIC LETTER ZAH -->
+ <include
+ latin:keyboardLayout="@xml/keys_arabic3_left" />
+ <!-- U+0621: "ء" ARABIC LETTER HAMZA -->
<Key
- latin:keyLabel="&#x0638;"
+ latin:keyLabel="&#x0621;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0637: "ط" ARABIC LETTER TAH -->
+ <!-- U+0624: "ؤ" ARABIC LETTER WAW WITH HAMZA ABOVE -->
<Key
- latin:keyLabel="&#x0637;"
+ latin:keyLabel="&#x0624;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0630: "ذ" ARABIC LETTER THAL -->
+ <!-- U+0631: "ر" ARABIC LETTER REH -->
<Key
- latin:keyLabel="&#x0630;"
+ latin:keyLabel="&#x0631;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+062F: "د" ARABIC LETTER DAL -->
+ <!-- U+0649: "ى" ARABIC LETTER ALEF MAKSURA
+ U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE -->
<Key
- latin:keyLabel="&#x062F;"
+ latin:keyLabel="&#x0649;"
+ latin:moreKeys="&#x0626;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0629: "ة" ARABIC LETTER TEH MARBUTA -->
+ <Key
+ latin:keyLabel="&#x0629;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0648: "و" ARABIC LETTER WAW -->
+ <Key
+ latin:keyLabel="&#x0648;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0632: "ز" ARABIC LETTER ZAIN
U+0698: "ژ" ARABIC LETTER JEH -->
@@ -43,18 +55,12 @@
latin:keyLabel="&#x0632;"
latin:moreKeys="&#x0698;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0631: "ر" ARABIC LETTER REH -->
- <Key
- latin:keyLabel="&#x0631;"
- latin:keyLabelFlags="fontNormal" />
- <!-- U+0629: "ة" ARABIC LETTER TEH MARBUTA -->
+ <!-- U+0638: "ظ" ARABIC LETTER ZAH -->
<Key
- latin:keyLabel="&#x0629;"
+ latin:keyLabel="&#x0638;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0648: "و" ARABIC LETTER WAW
- U+0624: "ﺅ" ARABIC LETTER WAW WITH HAMZA ABOVE -->
+ <!-- U+062F: "د" ARABIC LETTER DAL -->
<Key
- latin:keyLabel="&#x0648;"
- latin:moreKeys="&#x0624;"
+ latin:keyLabel="&#x062F;"
latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml/rowkeys_east_slavic1.xml b/java/res/xml/rowkeys_east_slavic1.xml
index c1b43bd36..5b3b4b48d 100644
--- a/java/res/xml/rowkeys_east_slavic1.xml
+++ b/java/res/xml/rowkeys_east_slavic1.xml
@@ -41,7 +41,8 @@
<Key
latin:keyLabel="&#x043A;"
latin:keyHintLabel="4"
- latin:additionalMoreKeys="4" />
+ latin:additionalMoreKeys="4"
+ latin:moreKeys="!text/more_keys_for_cyrillic_ka" />
<!-- U+0435: "е" CYRILLIC SMALL LETTER IE -->
<Key
latin:keyLabel="&#x0435;"
diff --git a/java/res/xml/rowkeys_east_slavic2.xml b/java/res/xml/rowkeys_east_slavic2.xml
index 9743727c1..2e412f08c 100644
--- a/java/res/xml/rowkeys_east_slavic2.xml
+++ b/java/res/xml/rowkeys_east_slavic2.xml
@@ -32,7 +32,8 @@
latin:keyLabel="&#x0432;" />
<!-- U+0430: "а" CYRILLIC SMALL LETTER A -->
<Key
- latin:keyLabel="&#x0430;" />
+ latin:keyLabel="&#x0430;"
+ latin:moreKeys="!text/more_keys_for_cyrillic_a" />
<!-- U+043F: "п" CYRILLIC SMALL LETTER PE -->
<Key
latin:keyLabel="&#x043F;" />
@@ -53,5 +54,6 @@
<Key
latin:keyLabel="&#x0436;" />
<Key
- latin:keyLabel="!text/keylabel_for_east_slavic_row2_11" />
+ latin:keyLabel="!text/keylabel_for_east_slavic_row2_11"
+ latin:moreKeys="!text/more_keys_for_east_slavic_row2_11" />
</merge>
diff --git a/java/res/xml/rowkeys_farsi1.xml b/java/res/xml/rowkeys_farsi1.xml
index 0ccf1ab54..5a22a2462 100644
--- a/java/res/xml/rowkeys_farsi1.xml
+++ b/java/res/xml/rowkeys_farsi1.xml
@@ -21,81 +21,83 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <!-- U+0635: "ص" ARABIC LETTER SAD
- U+0636: "ض" ARABIC LETTER DAD
+ <!-- U+0636: "ض" ARABIC LETTER DAD
U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE -->
<Key
- latin:keyLabel="&#x0635;"
- latin:moreKeys="&#x0636;,%"
+ latin:keyLabel="&#x0636;"
latin:keyHintLabel="&#x06F1;"
latin:additionalMoreKeys="&#x06F1;,1"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0642: "ق" ARABIC LETTER QAF
+ <!-- U+0635: "ص" ARABIC LETTER SAD
U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO -->
<Key
- latin:keyLabel="&#x0642;"
+ latin:keyLabel="&#x0635;"
latin:keyHintLabel="&#x06F2;"
latin:additionalMoreKeys="&#x06F2;,2"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0641: "ف" ARABIC LETTER FEH
+ <!-- U+062B: "ث" ARABIC LETTER THEH
U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE -->
<Key
- latin:keyLabel="&#x0641;"
+ latin:keyLabel="&#x062B;"
latin:keyHintLabel="&#x06F3;"
latin:additionalMoreKeys="&#x06F3;,3"
latin:keyLabelFlags="fontNormal" />
- <!-- U+063A: "غ" ARABIC LETTER GHAIN
+ <!-- U+0642: "ق" ARABIC LETTER QAF
U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR -->
<Key
- latin:keyLabel="&#x063A;"
+ latin:keyLabel="&#x0642;"
latin:keyHintLabel="&#x06F4;"
latin:additionalMoreKeys="&#x06F4;,4"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0639: "ع" ARABIC LETTER AIN
+ <!-- U+0641: "ف" ARABIC LETTER FEH
U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE -->
<Key
- latin:keyLabel="&#x0639;"
+ latin:keyLabel="&#x0641;"
latin:keyHintLabel="&#x06F5;"
latin:additionalMoreKeys="&#x06F5;,5"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0647: "ه" ARABIC LETTER HEH
- U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM
- U+0647/U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER
- U+0647/U+0654: ARABIC LETTER HEH + ARABIC HAMZA ABOVE
- U+0629: "ة" ARABIC LETTER TEH MARBUTA
+ <!-- U+063A: "غ" ARABIC LETTER GHAIN
U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX -->
<Key
- latin:keyLabel="&#x0647;"
- latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;,&#x0647;&#x0654;,&#x0629;,%"
+ latin:keyLabel="&#x063A;"
latin:keyHintLabel="&#x06F6;"
latin:additionalMoreKeys="&#x06F6;,6"
latin:keyLabelFlags="fontNormal" />
- <!-- U+062E: "خ" ARABIC LETTER KHAH
+ <!-- U+0639: "ع" ARABIC LETTER AIN
U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN -->
<Key
- latin:keyLabel="&#x062E;"
+ latin:keyLabel="&#x0639;"
latin:keyHintLabel="&#x06F7;"
latin:additionalMoreKeys="&#x06F7;,7"
latin:keyLabelFlags="fontNormal" />
- <!-- U+062D: "ح" ARABIC LETTER HAH
+ <!-- U+0647: "ه" ARABIC LETTER HEH
+ U+FEEB: "ﻫ" ARABIC LETTER HEH INITIAL FORM
+ U+0647/U+200D: ARABIC LETTER HEH + ZERO WIDTH JOINER
+ U+0647/U+0654: ARABIC LETTER HEH + ARABIC HAMZA ABOVE
+ U+0629: "ة" ARABIC LETTER TEH MARBUTA
U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT -->
<Key
- latin:keyLabel="&#x062D;"
+ latin:keyLabel="&#x0647;"
+ latin:moreKeys="&#xFEEB;|&#x0647;&#x200D;,&#x0647;&#x0654;,&#x0629;,%"
latin:keyHintLabel="&#x06F8;"
latin:additionalMoreKeys="&#x06F8;,8"
latin:keyLabelFlags="fontNormal" />
- <!-- U+062C: "ج" ARABIC LETTER JEEM
+ <!-- U+062E: "خ" ARABIC LETTER KHAH
U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE -->
<Key
- latin:keyLabel="&#x062C;"
+ latin:keyLabel="&#x062E;"
latin:keyHintLabel="&#x06F9;"
latin:additionalMoreKeys="&#x06F9;,9"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0686: "چ" ARABIC LETTER TCHEH
+ <!-- U+062D: "ح" ARABIC LETTER HAH
U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO -->
<Key
- latin:keyLabel="&#x0686;"
+ latin:keyLabel="&#x062D;"
latin:keyHintLabel="&#x06F0;"
latin:additionalMoreKeys="&#x06F0;,0"
latin:keyLabelFlags="fontNormal" />
+ <!-- U+062C: "ج" ARABIC LETTER JEEM -->
+ <Key
+ latin:keyLabel="&#x062C;"
+ latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml/rowkeys_farsi2.xml b/java/res/xml/rowkeys_farsi2.xml
index 4b6abe2ab..fc6789eba 100644
--- a/java/res/xml/rowkeys_farsi2.xml
+++ b/java/res/xml/rowkeys_farsi2.xml
@@ -25,11 +25,9 @@
<Key
latin:keyLabel="&#x0634;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0633: "س" ARABIC LETTER SEEN
- U+0636: "ض" ARABIC LETTER DAD -->
+ <!-- U+0633: "س" ARABIC LETTER SEEN -->
<Key
latin:keyLabel="&#x0633;"
- latin:moreKeys="&#x0636;"
latin:keyLabelFlags="fontNormal" />
<!-- U+06CC: "ی" ARABIC LETTER FARSI YEH
U+0626: "ئ" ARABIC LETTER YEH WITH HAMZA ABOVE
@@ -59,11 +57,10 @@
latin:moreKeys="&#x0621;,&#x0622;,&#x0623;,&#x0671;,&#x0625;"
latin:keyLabelFlags="fontNormal" />
<!-- U+062A: "ت" ARABIC LETTER TEH
- U+062B: "ﺙ" ARABIC LETTER THEH
U+0629: "ة": ARABIC LETTER TEH MARBUTA -->
<Key
latin:keyLabel="&#x062A;"
- latin:moreKeys="&#x062B;,&#x0629;"
+ latin:moreKeys="&#x0629;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0646: "ن" ARABIC LETTER NOON -->
<Key
@@ -79,4 +76,8 @@
latin:keyLabel="&#x06A9;"
latin:moreKeys="&#x0643;"
latin:keyLabelFlags="fontNormal" />
+ <!-- U+06AF: "گ" ARABIC LETTER GAF -->
+ <Key
+ latin:keyLabel="&#x06AF;"
+ latin:keyLabelFlags="fontNormal" />
</merge>
diff --git a/java/res/xml/rowkeys_farsi3.xml b/java/res/xml/rowkeys_farsi3.xml
index 7d2e81f7d..98949f4c0 100644
--- a/java/res/xml/rowkeys_farsi3.xml
+++ b/java/res/xml/rowkeys_farsi3.xml
@@ -21,17 +21,21 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <!-- U+0637: "ط" ARABIC LETTER TAH
- U+0638: "ظ" ARABIC LETTER ZAH -->
+ <!-- U+0638: "ظ" ARABIC LETTER ZAH -->
+ <Key
+ latin:keyLabel="&#x0638;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0637: "ط" ARABIC LETTER TAH -->
<Key
latin:keyLabel="&#x0637;"
- latin:moreKeys="&#x0638;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+0632: "ز" ARABIC LETTER ZAIN
- U+0698: "ژ" ARABIC LETTER JEH -->
+ <!-- U+0698: "ژ" ARABIC LETTER JEH -->
+ <Key
+ latin:keyLabel="&#x0698;"
+ latin:keyLabelFlags="fontNormal" />
+ <!-- U+0632: "ز" ARABIC LETTER ZAIN -->
<Key
latin:keyLabel="&#x0632;"
- latin:moreKeys="&#x0698;"
latin:keyLabelFlags="fontNormal" />
<!-- U+0631: "ر" ARABIC LETTER REH -->
<Key
@@ -55,8 +59,6 @@
latin:keyLabel="&#x0648;"
latin:moreKeys="&#x0624;"
latin:keyLabelFlags="fontNormal" />
- <!-- U+06AF: "گ" ARABIC LETTER GAF -->
- <Key
- latin:keyLabel="&#x06AF;"
- latin:keyLabelFlags="fontNormal" />
+ <include
+ latin:keyboardLayout="@xml/keys_farsi3_right" />
</merge>
diff --git a/java/res/xml/rows_arabic.xml b/java/res/xml/rows_arabic.xml
index 6449af219..798c23e81 100644
--- a/java/res/xml/rows_arabic.xml
+++ b/java/res/xml/rows_arabic.xml
@@ -24,27 +24,25 @@
<include
latin:keyboardLayout="@xml/key_styles_common" />
<Row
- latin:keyWidth="10%p"
+ latin:keyWidth="9.091%p"
>
<include
latin:keyboardLayout="@xml/rowkeys_arabic1" />
</Row>
<Row
- latin:keyWidth="10%p"
+ latin:keyWidth="9.091%p"
>
<include
latin:keyboardLayout="@xml/rowkeys_arabic2" />
</Row>
<Row
- latin:keyWidth="10%p"
+ latin:keyWidth="9.091%p"
>
<include
- latin:keyboardLayout="@xml/rowkeys_arabic3"
- latin:keyXPos="5.0%p" />
+ latin:keyboardLayout="@xml/rowkeys_arabic3" />
<Key
latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight"
- latin:visualInsetsLeft="1%p" />
+ latin:keyWidth="fillRight" />
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/res/xml/rows_farsi.xml b/java/res/xml/rows_farsi.xml
index cc0c526b3..c74614fcf 100644
--- a/java/res/xml/rows_farsi.xml
+++ b/java/res/xml/rows_farsi.xml
@@ -24,27 +24,25 @@
<include
latin:keyboardLayout="@xml/key_styles_common" />
<Row
- latin:keyWidth="10%p"
+ latin:keyWidth="9.091%p"
>
<include
latin:keyboardLayout="@xml/rowkeys_farsi1" />
</Row>
<Row
- latin:keyWidth="10%p"
+ latin:keyWidth="9.091%p"
>
<include
latin:keyboardLayout="@xml/rowkeys_farsi2" />
</Row>
<Row
- latin:keyWidth="10%p"
+ latin:keyWidth="9.091%p"
>
<include
- latin:keyboardLayout="@xml/rowkeys_farsi3"
- latin:keyXPos="5.0%p" />
+ latin:keyboardLayout="@xml/rowkeys_farsi3" />
<Key
latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight"
- latin:visualInsetsLeft="1%p" />
+ latin:keyWidth="fillRight" />
</Row>
<include
latin:keyboardLayout="@xml/row_qwerty4" />
diff --git a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
index 3bed2c7a0..d5e638e7e 100644
--- a/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
+++ b/java/src/com/android/inputmethod/dictionarypack/ActionBatch.java
@@ -28,8 +28,8 @@ import android.util.Log;
import com.android.inputmethod.compat.DownloadManagerCompatUtils;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.DebugLogUtils;
-import com.android.inputmethod.latin.utils.Utils;
import java.util.LinkedList;
import java.util.Queue;
@@ -144,7 +144,7 @@ public final class ActionBatch {
// DownloadManager also stupidly cuts the extension to replace with its own that it
// gets from the content-type. We need to circumvent this.
final String disambiguator = "#" + System.currentTimeMillis()
- + Utils.getVersionName(context) + ".dict";
+ + ApplicationUtils.getVersionName(context) + ".dict";
final Uri uri = Uri.parse(mWordList.mRemoteFilename + disambiguator);
final Request request = new Request(uri);
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java b/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java
index 6e3dd7109..767f895dc 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DictionaryService.java
@@ -22,7 +22,6 @@ import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
-import android.text.format.DateUtils;
import android.util.Log;
import android.widget.Toast;
@@ -30,6 +29,7 @@ import com.android.inputmethod.latin.R;
import java.util.Locale;
import java.util.Random;
+import java.util.concurrent.TimeUnit;
/**
* Service that handles background tasks for the dictionary provider.
@@ -77,19 +77,19 @@ public final class DictionaryService extends Service {
* How often, in milliseconds, we want to update the metadata. This is a
* floor value; actually, it may happen several hours later, or even more.
*/
- private static final long UPDATE_FREQUENCY = 4 * DateUtils.DAY_IN_MILLIS;
+ private static final long UPDATE_FREQUENCY = TimeUnit.DAYS.toMillis(4);
/**
* We are waked around midnight, local time. We want to wake between midnight and 6 am,
* roughly. So use a random time between 0 and this delay.
*/
- private static final int MAX_ALARM_DELAY = 6 * ((int)AlarmManager.INTERVAL_HOUR);
+ private static final int MAX_ALARM_DELAY = (int)TimeUnit.HOURS.toMillis(6);
/**
* How long we consider a "very long time". If no update took place in this time,
* the content provider will trigger an update in the background.
*/
- private static final long VERY_LONG_TIME = 14 * DateUtils.DAY_IN_MILLIS;
+ private static final long VERY_LONG_TIME = TimeUnit.DAYS.toMillis(14);
/**
* The last seen start Id. This must be stored because we must only call stopSelfResult() with
@@ -170,7 +170,7 @@ public final class DictionaryService extends Service {
checkTimeAndMaybeSetupUpdateAlarm(context);
} else if (DictionaryPackConstants.UPDATE_NOW_INTENT_ACTION.equals(intent.getAction())) {
// Intent to trigger an update now.
- UpdateHandler.update(context, false);
+ UpdateHandler.tryUpdate(context, false);
} else {
UpdateHandler.downloadFinished(context, intent);
}
@@ -221,7 +221,7 @@ public final class DictionaryService extends Service {
*/
public static void updateNowIfNotUpdatedInAVeryLongTime(final Context context) {
if (!isLastUpdateAtLeastThisOld(context, VERY_LONG_TIME)) return;
- UpdateHandler.update(context, false);
+ UpdateHandler.tryUpdate(context, false);
}
/**
diff --git a/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java b/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java
index 4b89d20bb..7bbd041e7 100644
--- a/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java
+++ b/java/src/com/android/inputmethod/dictionarypack/DictionarySettingsFragment.java
@@ -30,6 +30,7 @@ import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.animation.AnimationUtils;
@@ -104,9 +105,16 @@ public final class DictionarySettingsFragment extends PreferenceFragment
@Override
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
- mUpdateNowMenu = menu.add(Menu.NONE, MENU_UPDATE_NOW, 0, R.string.check_for_updates_now);
- mUpdateNowMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
- refreshNetworkState();
+ final String metadataUri =
+ MetadataDbHelper.getMetadataUriAsString(getActivity(), mClientId);
+ // We only add the "Refresh" button if we have a non-empty URL to refresh from. If the
+ // URL is empty, of course we can't refresh so it makes no sense to display this.
+ if (!TextUtils.isEmpty(metadataUri)) {
+ mUpdateNowMenu =
+ menu.add(Menu.NONE, MENU_UPDATE_NOW, 0, R.string.check_for_updates_now);
+ mUpdateNowMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
+ refreshNetworkState();
+ }
}
@Override
@@ -353,7 +361,12 @@ public final class DictionarySettingsFragment extends PreferenceFragment
new Thread("updateByHand") {
@Override
public void run() {
- UpdateHandler.update(activity, true);
+ // We call tryUpdate(), which returns whether we could successfully start an update.
+ // If we couldn't, we'll never receive the end callback, so we stop the loading
+ // animation and return to the previous screen.
+ if (!UpdateHandler.tryUpdate(activity, true)) {
+ stopLoadingAnimation();
+ }
}
}.start();
}
@@ -368,7 +381,9 @@ public final class DictionarySettingsFragment extends PreferenceFragment
private void startLoadingAnimation() {
mLoadingView.setVisibility(View.VISIBLE);
getView().setVisibility(View.GONE);
- mUpdateNowMenu.setTitle(R.string.cancel);
+ // We come here when the menu element is pressed so presumably it can't be null. But
+ // better safe than sorry.
+ if (null != mUpdateNowMenu) mUpdateNowMenu.setTitle(R.string.cancel);
}
private void stopLoadingAnimation() {
diff --git a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
index 719f24e59..f66ef8733 100644
--- a/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
+++ b/java/src/com/android/inputmethod/dictionarypack/UpdateHandler.java
@@ -38,8 +38,8 @@ import android.util.Log;
import com.android.inputmethod.compat.ConnectivityManagerCompatUtils;
import com.android.inputmethod.compat.DownloadManagerCompatUtils;
import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.DebugLogUtils;
-import com.android.inputmethod.latin.utils.Utils;
import java.io.File;
import java.io.FileInputStream;
@@ -173,14 +173,15 @@ public final class UpdateHandler {
* Download latest metadata from the server through DownloadManager for all known clients
* @param context The context for retrieving resources
* @param updateNow Whether we should update NOW, or respect bandwidth policies
+ * @return true if an update successfully started, false otherwise.
*/
- public static void update(final Context context, final boolean updateNow) {
+ public static boolean tryUpdate(final Context context, final boolean updateNow) {
// TODO: loop through all clients instead of only doing the default one.
final TreeSet<String> uris = new TreeSet<String>();
final Cursor cursor = MetadataDbHelper.queryClientIds(context);
- if (null == cursor) return;
+ if (null == cursor) return false;
try {
- if (!cursor.moveToFirst()) return;
+ if (!cursor.moveToFirst()) return false;
do {
final String clientId = cursor.getString(0);
final String metadataUri =
@@ -192,6 +193,7 @@ public final class UpdateHandler {
} finally {
cursor.close();
}
+ boolean started = false;
for (final String metadataUri : uris) {
if (!TextUtils.isEmpty(metadataUri)) {
// If the metadata URI is empty, that means we should never update it at all.
@@ -200,8 +202,10 @@ public final class UpdateHandler {
// is a bug and it happens anyway, doing nothing is the right thing to do.
// For more information, {@see DictionaryProvider#insert(Uri, ContentValues)}.
updateClientsWithMetadataUri(context, updateNow, metadataUri);
+ started = true;
}
}
+ return started;
}
/**
@@ -218,7 +222,7 @@ public final class UpdateHandler {
// DownloadManager also stupidly cuts the extension to replace with its own that it
// gets from the content-type. We need to circumvent this.
final String disambiguator = "#" + System.currentTimeMillis()
- + Utils.getVersionName(context) + ".json";
+ + ApplicationUtils.getVersionName(context) + ".json";
final Request metadataRequest = new Request(Uri.parse(metadataUri + disambiguator));
DebugLogUtils.l("Request =", metadataRequest);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
index 9eeee5baf..00ea20d2c 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java
@@ -20,7 +20,6 @@ import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.InputPointers;
public interface KeyboardActionListener {
-
/**
* Called when the user presses a key. This is sent before the {@link #onCodeInput} is called.
* For keys that repeat, this is only called once.
@@ -99,9 +98,9 @@ public interface KeyboardActionListener {
*/
public boolean onCustomRequest(int requestCode);
- public static class Adapter implements KeyboardActionListener {
- public static final Adapter EMPTY_LISTENER = new Adapter();
+ public static final KeyboardActionListener EMPTY_LISTENER = new Adapter();
+ public static class Adapter implements KeyboardActionListener {
@Override
public void onPressKey(int primaryCode, boolean isSinglePointer) {}
@Override
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 4323f7171..98e2baee2 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -31,7 +31,6 @@ import com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
import com.android.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException;
import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
import com.android.inputmethod.keyboard.internal.KeyboardState;
-import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
import com.android.inputmethod.latin.InputView;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
@@ -210,7 +209,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
}
public void onPressKey(final int code, final boolean isSinglePointer) {
- hapticAndAudioFeedback(code);
mState.onPressKey(code, isSinglePointer, mLatinIME.getCurrentAutoCapsState());
}
@@ -299,13 +297,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
? keyboardView.getTimerProxy().isInDoubleTapShiftKeyTimeout() : false;
}
- private void hapticAndAudioFeedback(final int code) {
- if (mKeyboardView == null || mKeyboardView.isInSlidingKeyInput()) {
- return;
- }
- AudioAndHapticFeedbackManager.getInstance().hapticAndAudioFeedback(code, mKeyboardView);
- }
-
/**
* Updates state machine to figure out when to automatically switch back to the previous mode.
*/
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 4cee4cfa6..254b20b87 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -37,6 +37,7 @@ import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.utils.CollectionUtils;
+import com.android.inputmethod.latin.utils.TypefaceUtils;
import com.android.inputmethod.research.ResearchLogger;
import java.util.HashSet;
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 8a926d655..f85e60449 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -57,10 +57,8 @@ import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams;
import com.android.inputmethod.keyboard.internal.PreviewPlacerView;
import com.android.inputmethod.keyboard.internal.SlidingKeyInputPreview;
import com.android.inputmethod.keyboard.internal.TouchScreenRegulator;
-import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.DebugSettings;
-import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.Settings;
@@ -72,7 +70,9 @@ import com.android.inputmethod.latin.utils.CoordinateUtils;
import com.android.inputmethod.latin.utils.ResourceUtils;
import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper;
import com.android.inputmethod.latin.utils.StringUtils;
-import com.android.inputmethod.latin.utils.Utils.UsabilityStudyLogUtils;
+import com.android.inputmethod.latin.utils.TypefaceUtils;
+import com.android.inputmethod.latin.utils.UsabilityStudyLogUtils;
+import com.android.inputmethod.latin.utils.ViewLayoutUtils;
import com.android.inputmethod.research.ResearchLogger;
import java.util.Locale;
@@ -240,11 +240,15 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
break;
case MSG_REPEAT_KEY:
final Key currentKey = tracker.getKey();
- if (currentKey != null && currentKey.mCode == msg.arg1) {
- tracker.onRepeatKey(currentKey);
- AudioAndHapticFeedbackManager.getInstance().hapticAndAudioFeedback(
- currentKey.mCode, keyboardView);
+ final int code = msg.arg1;
+ if (currentKey != null && currentKey.mCode == code) {
startKeyRepeatTimer(tracker, mKeyRepeatInterval);
+ startTypingStateTimer(currentKey);
+ final KeyboardActionListener listener =
+ keyboardView.getKeyboardActionListener();
+ listener.onPressKey(code, true /* isSinglePointer */);
+ listener.onCodeInput(code,
+ Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
}
break;
case MSG_LONGPRESS_KEY:
@@ -564,6 +568,8 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
altCodeKeyWhileTypingFadeoutAnimatorResId, this);
mAltCodeKeyWhileTypingFadeinAnimator = loadObjectAnimator(
altCodeKeyWhileTypingFadeinAnimatorResId, this);
+
+ mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
}
private ObjectAnimator loadObjectAnimator(final int resId, final Object target) {
@@ -977,39 +983,28 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
ResearchLogger.mainKeyboardView_onLongPress();
}
- final int code = key.mCode;
+ final KeyboardActionListener listener = mKeyboardActionListener;
if (key.hasNoPanelAutoMoreKey()) {
- final int embeddedCode = key.mMoreKeys[0].mCode;
+ final int moreKeyCode = key.mMoreKeys[0].mCode;
tracker.onLongPressed();
- invokeCodeInput(embeddedCode);
- invokeReleaseKey(code);
- AudioAndHapticFeedbackManager.getInstance().hapticAndAudioFeedback(code, this);
+ listener.onPressKey(moreKeyCode, true /* isSinglePointer */);
+ listener.onCodeInput(moreKeyCode,
+ Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
+ listener.onReleaseKey(moreKeyCode, false /* withSliding */);
return;
}
+ final int code = key.mCode;
if (code == Constants.CODE_SPACE || code == Constants.CODE_LANGUAGE_SWITCH) {
// Long pressing the space key invokes IME switcher dialog.
- if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) {
+ if (listener.onCustomRequest(Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER)) {
tracker.onLongPressed();
- invokeReleaseKey(code);
+ listener.onReleaseKey(code, false /* withSliding */);
return;
}
}
openMoreKeysPanel(key, tracker);
}
- private boolean invokeCustomRequest(final int requestCode) {
- return mKeyboardActionListener.onCustomRequest(requestCode);
- }
-
- private void invokeCodeInput(final int code) {
- mKeyboardActionListener.onCodeInput(
- code, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
- }
-
- private void invokeReleaseKey(final int code) {
- mKeyboardActionListener.onReleaseKey(code, false);
- }
-
private void openMoreKeysPanel(final Key key, final PointerTracker tracker) {
final MoreKeysPanel moreKeysPanel = onCreateMoreKeysPanel(key, getContext());
if (moreKeysPanel == null) {
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index 51f5446db..d29e6382c 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -29,6 +29,7 @@ import com.android.inputmethod.keyboard.internal.KeyboardParams;
import com.android.inputmethod.keyboard.internal.MoreKeySpec;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.utils.StringUtils;
+import com.android.inputmethod.latin.utils.TypefaceUtils;
public final class MoreKeysKeyboard extends Keyboard {
private final int mDefaultKeyCoordX;
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 7b14259a0..53207597a 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -175,7 +175,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
private DrawingProxy mDrawingProxy;
private TimerProxy mTimerProxy;
private KeyDetector mKeyDetector;
- private KeyboardActionListener mListener = KeyboardActionListener.Adapter.EMPTY_LISTENER;
+ private KeyboardActionListener mListener = KeyboardActionListener.EMPTY_LISTENER;
private Keyboard mKeyboard;
private int mPhantonSuddenMoveThreshold;
@@ -1263,13 +1263,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
if (!key.isRepeatable()) return;
// Don't start key repeat when we are in sliding input mode.
if (mIsInSlidingKeyInput) return;
- onRepeatKey(key);
- mTimerProxy.startKeyRepeatTimer(this);
- }
-
- public void onRepeatKey(final Key key) {
detectAndSendKey(key, key.mX, key.mY, SystemClock.uptimeMillis());
- mTimerProxy.startTypingStateTimer(key);
+ mTimerProxy.startKeyRepeatTimer(this);
}
private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final long eventTime,
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index 370d0cb93..8ead44c31 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -81,9 +81,6 @@ public final class KeyboardState {
private boolean mPrevSymbolsKeyboardWasShifted;
private int mRecapitalizeMode;
- // For handling long press.
- private boolean mLongPressShiftLockFired;
-
// For handling double tap.
private boolean mIsInAlphabetUnshiftedFromShifted;
private boolean mIsInDoubleTapShiftKey;
@@ -325,10 +322,11 @@ public final class KeyboardState {
}
if (code == Constants.CODE_SHIFT) {
onPressShift();
+ } else if (code == Constants.CODE_CAPSLOCK) {
+ // Nothing to do here. See {@link #onReleaseKey(int,boolean)}.
} else if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) {
onPressSymbol();
} else {
- mLongPressShiftLockFired = false;
mShiftKeyState.onOtherKeyPressed();
mSymbolKeyState.onOtherKeyPressed();
// It is required to reset the auto caps state when all of the following conditions
@@ -356,6 +354,8 @@ public final class KeyboardState {
}
if (code == Constants.CODE_SHIFT) {
onReleaseShift(withSliding);
+ } else if (code == Constants.CODE_CAPSLOCK) {
+ setShiftLocked(!mAlphabetShiftState.isShiftLocked());
} else if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) {
onReleaseSymbol(withSliding);
}
@@ -437,7 +437,6 @@ public final class KeyboardState {
}
private void onPressShift() {
- mLongPressShiftLockFired = false;
// If we are recapitalizing, we don't do any of the normal processing, including
// importantly the double tap timer.
if (RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE != mRecapitalizeMode) {
@@ -499,8 +498,6 @@ public final class KeyboardState {
// Double tap shift key has been handled in {@link #onPressShift}, so that just
// ignore this release shift key here.
mIsInDoubleTapShiftKey = false;
- } else if (mLongPressShiftLockFired) {
- setShiftLocked(!mAlphabetShiftState.isShiftLocked());
} else if (mShiftKeyState.isChording()) {
if (mAlphabetShiftState.isShiftLockShifted()) {
// After chording input while shift locked state.
@@ -610,12 +607,6 @@ public final class KeyboardState {
break;
}
- if (code == Constants.CODE_CAPSLOCK) {
- // Changing shift lock state will be handled at {@link #onPressShift()} when the shift
- // key is released.
- mLongPressShiftLockFired = true;
- }
-
// If the code is a letter, update keyboard shift state.
if (Constants.isLetterCode(code)) {
updateAlphabetShiftState(autoCaps, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
index 467c15ffd..1594df75b 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.java
@@ -133,122 +133,125 @@ public final class KeyboardTextsSet {
/* 28 */ "keylabel_for_east_slavic_row2_11",
/* 29 */ "keylabel_for_east_slavic_row3_5",
/* 30 */ "more_keys_for_cyrillic_u",
- /* 31 */ "more_keys_for_cyrillic_en",
- /* 32 */ "more_keys_for_cyrillic_ghe",
- /* 33 */ "more_keys_for_east_slavic_row2_1",
- /* 34 */ "more_keys_for_cyrillic_o",
- /* 35 */ "more_keys_for_cyrillic_soft_sign",
- /* 36 */ "keylabel_for_south_slavic_row1_6",
- /* 37 */ "keylabel_for_south_slavic_row2_11",
- /* 38 */ "keylabel_for_south_slavic_row3_1",
- /* 39 */ "keylabel_for_south_slavic_row3_8",
- /* 40 */ "more_keys_for_cyrillic_ie",
- /* 41 */ "more_keys_for_cyrillic_i",
- /* 42 */ "label_to_alpha_key",
- /* 43 */ "single_quotes",
- /* 44 */ "double_quotes",
- /* 45 */ "single_angle_quotes",
- /* 46 */ "double_angle_quotes",
- /* 47 */ "more_keys_for_currency_dollar",
- /* 48 */ "keylabel_for_currency_generic",
- /* 49 */ "more_keys_for_currency_generic",
- /* 50 */ "more_keys_for_punctuation",
- /* 51 */ "more_keys_for_star",
- /* 52 */ "more_keys_for_bullet",
- /* 53 */ "more_keys_for_plus",
- /* 54 */ "more_keys_for_left_parenthesis",
- /* 55 */ "more_keys_for_right_parenthesis",
- /* 56 */ "more_keys_for_less_than",
- /* 57 */ "more_keys_for_greater_than",
- /* 58 */ "more_keys_for_arabic_diacritics",
- /* 59 */ "keyhintlabel_for_arabic_diacritics",
- /* 60 */ "keylabel_for_symbols_1",
- /* 61 */ "keylabel_for_symbols_2",
- /* 62 */ "keylabel_for_symbols_3",
- /* 63 */ "keylabel_for_symbols_4",
- /* 64 */ "keylabel_for_symbols_5",
- /* 65 */ "keylabel_for_symbols_6",
- /* 66 */ "keylabel_for_symbols_7",
- /* 67 */ "keylabel_for_symbols_8",
- /* 68 */ "keylabel_for_symbols_9",
- /* 69 */ "keylabel_for_symbols_0",
- /* 70 */ "label_to_symbol_key",
- /* 71 */ "label_to_symbol_with_microphone_key",
- /* 72 */ "additional_more_keys_for_symbols_1",
- /* 73 */ "additional_more_keys_for_symbols_2",
- /* 74 */ "additional_more_keys_for_symbols_3",
- /* 75 */ "additional_more_keys_for_symbols_4",
- /* 76 */ "additional_more_keys_for_symbols_5",
- /* 77 */ "additional_more_keys_for_symbols_6",
- /* 78 */ "additional_more_keys_for_symbols_7",
- /* 79 */ "additional_more_keys_for_symbols_8",
- /* 80 */ "additional_more_keys_for_symbols_9",
- /* 81 */ "additional_more_keys_for_symbols_0",
- /* 82 */ "more_keys_for_symbols_1",
- /* 83 */ "more_keys_for_symbols_2",
- /* 84 */ "more_keys_for_symbols_3",
- /* 85 */ "more_keys_for_symbols_4",
- /* 86 */ "more_keys_for_symbols_5",
- /* 87 */ "more_keys_for_symbols_6",
- /* 88 */ "more_keys_for_symbols_7",
- /* 89 */ "more_keys_for_symbols_8",
- /* 90 */ "more_keys_for_symbols_9",
- /* 91 */ "more_keys_for_symbols_0",
- /* 92 */ "keylabel_for_comma",
- /* 93 */ "more_keys_for_comma",
- /* 94 */ "keylabel_for_symbols_question",
- /* 95 */ "keylabel_for_symbols_semicolon",
- /* 96 */ "keylabel_for_symbols_percent",
- /* 97 */ "more_keys_for_symbols_exclamation",
- /* 98 */ "more_keys_for_symbols_question",
- /* 99 */ "more_keys_for_symbols_semicolon",
- /* 100 */ "more_keys_for_symbols_percent",
- /* 101 */ "keylabel_for_tablet_comma",
- /* 102 */ "keyhintlabel_for_tablet_comma",
- /* 103 */ "more_keys_for_tablet_comma",
- /* 104 */ "keyhintlabel_for_tablet_period",
- /* 105 */ "more_keys_for_tablet_period",
- /* 106 */ "keylabel_for_apostrophe",
- /* 107 */ "keyhintlabel_for_apostrophe",
- /* 108 */ "more_keys_for_apostrophe",
- /* 109 */ "more_keys_for_q",
- /* 110 */ "more_keys_for_x",
- /* 111 */ "keylabel_for_q",
- /* 112 */ "keylabel_for_w",
- /* 113 */ "keylabel_for_y",
- /* 114 */ "keylabel_for_x",
- /* 115 */ "keylabel_for_spanish_row2_10",
- /* 116 */ "more_keys_for_am_pm",
- /* 117 */ "settings_as_more_key",
- /* 118 */ "shortcut_as_more_key",
- /* 119 */ "action_next_as_more_key",
- /* 120 */ "action_previous_as_more_key",
- /* 121 */ "label_to_more_symbol_key",
- /* 122 */ "label_to_more_symbol_for_tablet_key",
- /* 123 */ "label_tab_key",
- /* 124 */ "label_to_phone_numeric_key",
- /* 125 */ "label_to_phone_symbols_key",
- /* 126 */ "label_time_am",
- /* 127 */ "label_time_pm",
- /* 128 */ "label_to_symbol_key_pcqwerty",
- /* 129 */ "keylabel_for_popular_domain",
- /* 130 */ "more_keys_for_popular_domain",
- /* 131 */ "more_keys_for_smiley",
- /* 132 */ "single_laqm_raqm",
- /* 133 */ "single_laqm_raqm_rtl",
- /* 134 */ "single_raqm_laqm",
- /* 135 */ "double_laqm_raqm",
- /* 136 */ "double_laqm_raqm_rtl",
- /* 137 */ "double_raqm_laqm",
- /* 138 */ "single_lqm_rqm",
- /* 139 */ "single_9qm_lqm",
- /* 140 */ "single_9qm_rqm",
- /* 141 */ "double_lqm_rqm",
- /* 142 */ "double_9qm_lqm",
- /* 143 */ "double_9qm_rqm",
- /* 144 */ "more_keys_for_single_quote",
- /* 145 */ "more_keys_for_double_quote",
- /* 146 */ "more_keys_for_tablet_double_quote",
+ /* 31 */ "more_keys_for_cyrillic_ka",
+ /* 32 */ "more_keys_for_cyrillic_en",
+ /* 33 */ "more_keys_for_cyrillic_ghe",
+ /* 34 */ "more_keys_for_east_slavic_row2_1",
+ /* 35 */ "more_keys_for_cyrillic_a",
+ /* 36 */ "more_keys_for_cyrillic_o",
+ /* 37 */ "more_keys_for_cyrillic_soft_sign",
+ /* 38 */ "more_keys_for_east_slavic_row2_11",
+ /* 39 */ "keylabel_for_south_slavic_row1_6",
+ /* 40 */ "keylabel_for_south_slavic_row2_11",
+ /* 41 */ "keylabel_for_south_slavic_row3_1",
+ /* 42 */ "keylabel_for_south_slavic_row3_8",
+ /* 43 */ "more_keys_for_cyrillic_ie",
+ /* 44 */ "more_keys_for_cyrillic_i",
+ /* 45 */ "label_to_alpha_key",
+ /* 46 */ "single_quotes",
+ /* 47 */ "double_quotes",
+ /* 48 */ "single_angle_quotes",
+ /* 49 */ "double_angle_quotes",
+ /* 50 */ "more_keys_for_currency_dollar",
+ /* 51 */ "keylabel_for_currency_generic",
+ /* 52 */ "more_keys_for_currency_generic",
+ /* 53 */ "more_keys_for_punctuation",
+ /* 54 */ "more_keys_for_star",
+ /* 55 */ "more_keys_for_bullet",
+ /* 56 */ "more_keys_for_plus",
+ /* 57 */ "more_keys_for_left_parenthesis",
+ /* 58 */ "more_keys_for_right_parenthesis",
+ /* 59 */ "more_keys_for_less_than",
+ /* 60 */ "more_keys_for_greater_than",
+ /* 61 */ "more_keys_for_arabic_diacritics",
+ /* 62 */ "keyhintlabel_for_arabic_diacritics",
+ /* 63 */ "keylabel_for_symbols_1",
+ /* 64 */ "keylabel_for_symbols_2",
+ /* 65 */ "keylabel_for_symbols_3",
+ /* 66 */ "keylabel_for_symbols_4",
+ /* 67 */ "keylabel_for_symbols_5",
+ /* 68 */ "keylabel_for_symbols_6",
+ /* 69 */ "keylabel_for_symbols_7",
+ /* 70 */ "keylabel_for_symbols_8",
+ /* 71 */ "keylabel_for_symbols_9",
+ /* 72 */ "keylabel_for_symbols_0",
+ /* 73 */ "label_to_symbol_key",
+ /* 74 */ "label_to_symbol_with_microphone_key",
+ /* 75 */ "additional_more_keys_for_symbols_1",
+ /* 76 */ "additional_more_keys_for_symbols_2",
+ /* 77 */ "additional_more_keys_for_symbols_3",
+ /* 78 */ "additional_more_keys_for_symbols_4",
+ /* 79 */ "additional_more_keys_for_symbols_5",
+ /* 80 */ "additional_more_keys_for_symbols_6",
+ /* 81 */ "additional_more_keys_for_symbols_7",
+ /* 82 */ "additional_more_keys_for_symbols_8",
+ /* 83 */ "additional_more_keys_for_symbols_9",
+ /* 84 */ "additional_more_keys_for_symbols_0",
+ /* 85 */ "more_keys_for_symbols_1",
+ /* 86 */ "more_keys_for_symbols_2",
+ /* 87 */ "more_keys_for_symbols_3",
+ /* 88 */ "more_keys_for_symbols_4",
+ /* 89 */ "more_keys_for_symbols_5",
+ /* 90 */ "more_keys_for_symbols_6",
+ /* 91 */ "more_keys_for_symbols_7",
+ /* 92 */ "more_keys_for_symbols_8",
+ /* 93 */ "more_keys_for_symbols_9",
+ /* 94 */ "more_keys_for_symbols_0",
+ /* 95 */ "keylabel_for_comma",
+ /* 96 */ "more_keys_for_comma",
+ /* 97 */ "keylabel_for_symbols_question",
+ /* 98 */ "keylabel_for_symbols_semicolon",
+ /* 99 */ "keylabel_for_symbols_percent",
+ /* 100 */ "more_keys_for_symbols_exclamation",
+ /* 101 */ "more_keys_for_symbols_question",
+ /* 102 */ "more_keys_for_symbols_semicolon",
+ /* 103 */ "more_keys_for_symbols_percent",
+ /* 104 */ "keylabel_for_tablet_comma",
+ /* 105 */ "keyhintlabel_for_tablet_comma",
+ /* 106 */ "more_keys_for_tablet_comma",
+ /* 107 */ "keyhintlabel_for_tablet_period",
+ /* 108 */ "more_keys_for_tablet_period",
+ /* 109 */ "keylabel_for_apostrophe",
+ /* 110 */ "keyhintlabel_for_apostrophe",
+ /* 111 */ "more_keys_for_apostrophe",
+ /* 112 */ "more_keys_for_q",
+ /* 113 */ "more_keys_for_x",
+ /* 114 */ "keylabel_for_q",
+ /* 115 */ "keylabel_for_w",
+ /* 116 */ "keylabel_for_y",
+ /* 117 */ "keylabel_for_x",
+ /* 118 */ "keylabel_for_spanish_row2_10",
+ /* 119 */ "more_keys_for_am_pm",
+ /* 120 */ "settings_as_more_key",
+ /* 121 */ "shortcut_as_more_key",
+ /* 122 */ "action_next_as_more_key",
+ /* 123 */ "action_previous_as_more_key",
+ /* 124 */ "label_to_more_symbol_key",
+ /* 125 */ "label_to_more_symbol_for_tablet_key",
+ /* 126 */ "label_tab_key",
+ /* 127 */ "label_to_phone_numeric_key",
+ /* 128 */ "label_to_phone_symbols_key",
+ /* 129 */ "label_time_am",
+ /* 130 */ "label_time_pm",
+ /* 131 */ "label_to_symbol_key_pcqwerty",
+ /* 132 */ "keylabel_for_popular_domain",
+ /* 133 */ "more_keys_for_popular_domain",
+ /* 134 */ "more_keys_for_smiley",
+ /* 135 */ "single_laqm_raqm",
+ /* 136 */ "single_laqm_raqm_rtl",
+ /* 137 */ "single_raqm_laqm",
+ /* 138 */ "double_laqm_raqm",
+ /* 139 */ "double_laqm_raqm_rtl",
+ /* 140 */ "double_raqm_laqm",
+ /* 141 */ "single_lqm_rqm",
+ /* 142 */ "single_9qm_lqm",
+ /* 143 */ "single_9qm_rqm",
+ /* 144 */ "double_lqm_rqm",
+ /* 145 */ "double_9qm_lqm",
+ /* 146 */ "double_9qm_rqm",
+ /* 147 */ "more_keys_for_single_quote",
+ /* 148 */ "more_keys_for_double_quote",
+ /* 149 */ "more_keys_for_tablet_double_quote",
};
private static final String EMPTY = "";
@@ -259,147 +262,147 @@ public final class KeyboardTextsSet {
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
- EMPTY, EMPTY, EMPTY,
- /* ~41 */
+ EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
+ /* ~44 */
// Label for "switch to alphabetic" key.
- /* 42 */ "ABC",
- /* 43 */ "!text/single_lqm_rqm",
- /* 44 */ "!text/double_lqm_rqm",
- /* 45 */ "!text/single_laqm_raqm",
- /* 46 */ "!text/double_laqm_raqm",
+ /* 45 */ "ABC",
+ /* 46 */ "!text/single_lqm_rqm",
+ /* 47 */ "!text/double_lqm_rqm",
+ /* 48 */ "!text/single_laqm_raqm",
+ /* 49 */ "!text/double_laqm_raqm",
// U+00A2: "¢" CENT SIGN
// U+00A3: "£" POUND SIGN
// U+20AC: "€" EURO SIGN
// U+00A5: "¥" YEN SIGN
// U+20B1: "₱" PESO SIGN
- /* 47 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
- /* 48 */ "$",
- /* 49 */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1",
- /* 50 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(,)",
+ /* 50 */ "\u00A2,\u00A3,\u20AC,\u00A5,\u20B1",
+ /* 51 */ "$",
+ /* 52 */ "$,\u00A2,\u20AC,\u00A3,\u00A5,\u20B1",
+ /* 53 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\\,,?,@,&,\\%,+,;,/,(,)",
// U+2020: "†" DAGGER
// U+2021: "‡" DOUBLE DAGGER
// U+2605: "★" BLACK STAR
- /* 51 */ "\u2020,\u2021,\u2605",
+ /* 54 */ "\u2020,\u2021,\u2605",
// U+266A: "♪" EIGHTH NOTE
// U+2665: "♥" BLACK HEART SUIT
// U+2660: "♠" BLACK SPADE SUIT
// U+2666: "♦" BLACK DIAMOND SUIT
// U+2663: "♣" BLACK CLUB SUIT
- /* 52 */ "\u266A,\u2665,\u2660,\u2666,\u2663",
+ /* 55 */ "\u266A,\u2665,\u2660,\u2666,\u2663",
// U+00B1: "±" PLUS-MINUS SIGN
- /* 53 */ "\u00B1",
+ /* 56 */ "\u00B1",
// The all letters need to be mirrored are found at
// http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt
- /* 54 */ "!fixedColumnOrder!3,<,{,[",
- /* 55 */ "!fixedColumnOrder!3,>,},]",
+ /* 57 */ "!fixedColumnOrder!3,<,{,[",
+ /* 58 */ "!fixedColumnOrder!3,>,},]",
// U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
// U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
// U+2264: "≤" LESS-THAN OR EQUAL TO
// U+2265: "≥" GREATER-THAN EQUAL TO
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
- /* 56 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB",
- /* 57 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB",
- /* 58 */ EMPTY,
- /* 59 */ EMPTY,
- /* 60 */ "1",
- /* 61 */ "2",
- /* 62 */ "3",
- /* 63 */ "4",
- /* 64 */ "5",
- /* 65 */ "6",
- /* 66 */ "7",
- /* 67 */ "8",
- /* 68 */ "9",
- /* 69 */ "0",
+ /* 59 */ "!fixedColumnOrder!3,\u2039,\u2264,\u00AB",
+ /* 60 */ "!fixedColumnOrder!3,\u203A,\u2265,\u00BB",
+ /* 61 */ EMPTY,
+ /* 62 */ EMPTY,
+ /* 63 */ "1",
+ /* 64 */ "2",
+ /* 65 */ "3",
+ /* 66 */ "4",
+ /* 67 */ "5",
+ /* 68 */ "6",
+ /* 69 */ "7",
+ /* 70 */ "8",
+ /* 71 */ "9",
+ /* 72 */ "0",
// Label for "switch to symbols" key.
- /* 70 */ "?123",
+ /* 73 */ "?123",
// Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
// part because it'll be appended by the code.
- /* 71 */ "123",
- /* 72~ */
+ /* 74 */ "123",
+ /* 75~ */
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
- /* ~81 */
+ /* ~84 */
// U+00B9: "¹" SUPERSCRIPT ONE
// U+00BD: "½" VULGAR FRACTION ONE HALF
// U+2153: "⅓" VULGAR FRACTION ONE THIRD
// U+00BC: "¼" VULGAR FRACTION ONE QUARTER
// U+215B: "⅛" VULGAR FRACTION ONE EIGHTH
- /* 82 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
+ /* 85 */ "\u00B9,\u00BD,\u2153,\u00BC,\u215B",
// U+00B2: "²" SUPERSCRIPT TWO
// U+2154: "⅔" VULGAR FRACTION TWO THIRDS
- /* 83 */ "\u00B2,\u2154",
+ /* 86 */ "\u00B2,\u2154",
// U+00B3: "³" SUPERSCRIPT THREE
// U+00BE: "¾" VULGAR FRACTION THREE QUARTERS
// U+215C: "⅜" VULGAR FRACTION THREE EIGHTHS
- /* 84 */ "\u00B3,\u00BE,\u215C",
+ /* 87 */ "\u00B3,\u00BE,\u215C",
// U+2074: "⁴" SUPERSCRIPT FOUR
- /* 85 */ "\u2074",
+ /* 88 */ "\u2074",
// U+215D: "⅝" VULGAR FRACTION FIVE EIGHTHS
- /* 86 */ "\u215D",
- /* 87 */ EMPTY,
- // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
- /* 88 */ "\u215E",
- /* 89 */ EMPTY,
+ /* 89 */ "\u215D",
/* 90 */ EMPTY,
+ // U+215E: "⅞" VULGAR FRACTION SEVEN EIGHTHS
+ /* 91 */ "\u215E",
+ /* 92 */ EMPTY,
+ /* 93 */ EMPTY,
// U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
// U+2205: "∅" EMPTY SET
- /* 91 */ "\u207F,\u2205",
- /* 92 */ ",",
- /* 93 */ EMPTY,
- /* 94 */ "?",
- /* 95 */ ";",
- /* 96 */ "%",
+ /* 94 */ "\u207F,\u2205",
+ /* 95 */ ",",
+ /* 96 */ EMPTY,
+ /* 97 */ "?",
+ /* 98 */ ";",
+ /* 99 */ "%",
// U+00A1: "¡" INVERTED EXCLAMATION MARK
- /* 97 */ "\u00A1",
+ /* 100 */ "\u00A1",
// U+00BF: "¿" INVERTED QUESTION MARK
- /* 98 */ "\u00BF",
- /* 99 */ EMPTY,
+ /* 101 */ "\u00BF",
+ /* 102 */ EMPTY,
// U+2030: "‰" PER MILLE SIGN
- /* 100 */ "\u2030",
- /* 101 */ ",",
- /* 102 */ "!",
- /* 103 */ "!",
- /* 104 */ "?",
- /* 105 */ "?",
- /* 106 */ "\'",
- /* 107 */ "\"",
- /* 108 */ "\"",
- /* 109 */ EMPTY,
- /* 110 */ EMPTY,
- /* 111 */ "q",
- /* 112 */ "w",
- /* 113 */ "y",
- /* 114 */ "x",
+ /* 103 */ "\u2030",
+ /* 104 */ ",",
+ /* 105 */ "!",
+ /* 106 */ "!",
+ /* 107 */ "?",
+ /* 108 */ "?",
+ /* 109 */ "\'",
+ /* 110 */ "\"",
+ /* 111 */ "\"",
+ /* 112 */ EMPTY,
+ /* 113 */ EMPTY,
+ /* 114 */ "q",
+ /* 115 */ "w",
+ /* 116 */ "y",
+ /* 117 */ "x",
// U+00F1: "ñ" LATIN SMALL LETTER N WITH TILDE
- /* 115 */ "\u00F1",
- /* 116 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm",
- /* 117 */ "!icon/settings_key|!code/key_settings",
- /* 118 */ "!icon/shortcut_key|!code/key_shortcut",
- /* 119 */ "!hasLabels!,!text/label_next_key|!code/key_action_next",
- /* 120 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous",
+ /* 118 */ "\u00F1",
+ /* 119 */ "!fixedColumnOrder!2,!hasLabels!,!text/label_time_am,!text/label_time_pm",
+ /* 120 */ "!icon/settings_key|!code/key_settings",
+ /* 121 */ "!icon/shortcut_key|!code/key_shortcut",
+ /* 122 */ "!hasLabels!,!text/label_next_key|!code/key_action_next",
+ /* 123 */ "!hasLabels!,!text/label_previous_key|!code/key_action_previous",
// Label for "switch to more symbol" modifier key. Must be short to fit on key!
- /* 121 */ "= \\ <",
+ /* 124 */ "= \\ <",
// Label for "switch to more symbol" modifier key on tablets. Must be short to fit on key!
- /* 122 */ "~ \\ {",
+ /* 125 */ "~ \\ {",
// Label for "Tab" key. Must be short to fit on key!
- /* 123 */ "Tab",
+ /* 126 */ "Tab",
// Label for "switch to phone numeric" key. Must be short to fit on key!
- /* 124 */ "123",
+ /* 127 */ "123",
// Label for "switch to phone symbols" key. Must be short to fit on key!
// U+FF0A: "*" FULLWIDTH ASTERISK
// U+FF03: "#" FULLWIDTH NUMBER SIGN
- /* 125 */ "\uFF0A\uFF03",
+ /* 128 */ "\uFF0A\uFF03",
// Key label for "ante meridiem"
- /* 126 */ "AM",
+ /* 129 */ "AM",
// Key label for "post meridiem"
- /* 127 */ "PM",
+ /* 130 */ "PM",
// Label for "switch to symbols" key on PC QWERTY layout
- /* 128 */ "Sym",
- /* 129 */ ".com",
+ /* 131 */ "Sym",
+ /* 132 */ ".com",
// popular web domains for the locale - most popular, displayed on the keyboard
- /* 130 */ "!hasLabels!,.net,.org,.gov,.edu",
- /* 131 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ",
+ /* 133 */ "!hasLabels!,.net,.org,.gov,.edu",
+ /* 134 */ "!fixedColumnOrder!5,!hasLabels!,=-O|=-O ,:-P|:-P ,;-)|;-) ,:-(|:-( ,:-)|:-) ,:-!|:-! ,:-$|:-$ ,B-)|B-) ,:O|:O ,:-*|:-* ,:-D|:-D ,:\'(|:\'( ,:-\\\\|:-\\\\ ,O:-)|O:-) ,:-[|:-[ ",
// U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
// U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
@@ -421,24 +424,24 @@ public final class KeyboardTextsSet {
// The following each quotation mark pair consist of
// <opening quotation mark>, <closing quotation mark>
// and is named after (single|double)_<opening quotation mark>_<closing quotation mark>.
- /* 132 */ "\u2039,\u203A",
- /* 133 */ "\u2039|\u203A,\u203A|\u2039",
- /* 134 */ "\u203A,\u2039",
- /* 135 */ "\u00AB,\u00BB",
- /* 136 */ "\u00AB|\u00BB,\u00BB|\u00AB",
- /* 137 */ "\u00BB,\u00AB",
+ /* 135 */ "\u2039,\u203A",
+ /* 136 */ "\u2039|\u203A,\u203A|\u2039",
+ /* 137 */ "\u203A,\u2039",
+ /* 138 */ "\u00AB,\u00BB",
+ /* 139 */ "\u00AB|\u00BB,\u00BB|\u00AB",
+ /* 140 */ "\u00BB,\u00AB",
// The following each quotation mark triplet consists of
// <another quotation mark>, <opening quotation mark>, <closing quotation mark>
// and is named after (single|double)_<opening quotation mark>_<closing quotation mark>.
- /* 138 */ "\u201A,\u2018,\u2019",
- /* 139 */ "\u2019,\u201A,\u2018",
- /* 140 */ "\u2018,\u201A,\u2019",
- /* 141 */ "\u201E,\u201C,\u201D",
- /* 142 */ "\u201D,\u201E,\u201C",
- /* 143 */ "\u201C,\u201E,\u201D",
- /* 144 */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes",
- /* 145 */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes",
- /* 146 */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes",
+ /* 141 */ "\u201A,\u2018,\u2019",
+ /* 142 */ "\u2019,\u201A,\u2018",
+ /* 143 */ "\u2018,\u201A,\u2019",
+ /* 144 */ "\u201E,\u201C,\u201D",
+ /* 145 */ "\u201D,\u201E,\u201C",
+ /* 146 */ "\u201C,\u201E,\u201D",
+ /* 147 */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes",
+ /* 148 */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes",
+ /* 149 */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes",
};
/* Language af: Afrikaans */
@@ -499,45 +502,45 @@ public final class KeyboardTextsSet {
/* 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,
- /* ~41 */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~44 */
// Label for "switch to alphabetic" key.
// U+0623: "ا" ARABIC LETTER ALEF
// U+200C: ZERO WIDTH NON-JOINER
// U+0628: "ب" ARABIC LETTER BEH
// U+062C: "پ" ARABIC LETTER PEH
- /* 42 */ "\u0623\u200C\u0628\u200C\u062C",
- /* 43 */ null,
- /* 44 */ null,
- /* 45 */ "!text/single_laqm_raqm_rtl",
- /* 46 */ "!text/double_laqm_raqm_rtl",
- /* 47~ */
+ /* 45 */ "\u0623\u200C\u0628\u200C\u062C",
+ /* 46 */ null,
+ /* 47 */ null,
+ /* 48 */ "!text/single_laqm_raqm_rtl",
+ /* 49 */ "!text/double_laqm_raqm_rtl",
+ /* 50~ */
null, null, null,
- /* ~49 */
+ /* ~52 */
// U+061F: "؟" ARABIC QUESTION MARK
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
- /* 50 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(,)",
+ /* 53 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(,)",
// U+2605: "★" BLACK STAR
// U+066D: "٭" ARABIC FIVE POINTED STAR
- /* 51 */ "\u2605,\u066D",
+ /* 54 */ "\u2605,\u066D",
// U+266A: "♪" EIGHTH NOTE
- /* 52 */ "\u266A",
- /* 53 */ null,
+ /* 55 */ "\u266A",
+ /* 56 */ null,
// The all letters need to be mirrored are found at
// http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt
// U+FD3E: "﴾" ORNATE LEFT PARENTHESIS
// U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS
- /* 54 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
- /* 55 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
+ /* 57 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
+ /* 58 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
// U+2264: "≤" LESS-THAN OR EQUAL TO
// U+2265: "≥" GREATER-THAN EQUAL TO
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
// U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
- /* 56 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
- /* 57 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+ /* 59 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
+ /* 60 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
// U+0655: "ٕ" ARABIC HAMZA BELOW
// U+0654: "ٔ" ARABIC HAMZA ABOVE
// U+0652: "ْ" ARABIC SUKUN
@@ -554,70 +557,115 @@ public final class KeyboardTextsSet {
// U+0640: "ـ" ARABIC TATWEEL
// In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
// Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly.
- /* 58 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0654|\u0654, \u0652|\u0652, \u064D|\u064D, \u064C|\u064C, \u064B|\u064B, \u0651|\u0651, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u0650|\u0650, \u064F|\u064F, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
- /* 59 */ "\u0651",
+ /* 61 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0654|\u0654, \u0652|\u0652, \u064D|\u064D, \u064C|\u064C, \u064B|\u064B, \u0651|\u0651, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u0650|\u0650, \u064F|\u064F, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
+ /* 62 */ "\u0651",
// U+0661: "١" ARABIC-INDIC DIGIT ONE
- /* 60 */ "\u0661",
+ /* 63 */ "\u0661",
// U+0662: "٢" ARABIC-INDIC DIGIT TWO
- /* 61 */ "\u0662",
+ /* 64 */ "\u0662",
// U+0663: "٣" ARABIC-INDIC DIGIT THREE
- /* 62 */ "\u0663",
+ /* 65 */ "\u0663",
// U+0664: "٤" ARABIC-INDIC DIGIT FOUR
- /* 63 */ "\u0664",
+ /* 66 */ "\u0664",
// U+0665: "٥" ARABIC-INDIC DIGIT FIVE
- /* 64 */ "\u0665",
+ /* 67 */ "\u0665",
// U+0666: "٦" ARABIC-INDIC DIGIT SIX
- /* 65 */ "\u0666",
+ /* 68 */ "\u0666",
// U+0667: "٧" ARABIC-INDIC DIGIT SEVEN
- /* 66 */ "\u0667",
+ /* 69 */ "\u0667",
// U+0668: "٨" ARABIC-INDIC DIGIT EIGHT
- /* 67 */ "\u0668",
+ /* 70 */ "\u0668",
// U+0669: "٩" ARABIC-INDIC DIGIT NINE
- /* 68 */ "\u0669",
+ /* 71 */ "\u0669",
// U+0660: "٠" ARABIC-INDIC DIGIT ZERO
- /* 69 */ "\u0660",
+ /* 72 */ "\u0660",
// Label for "switch to symbols" key.
// U+061F: "؟" ARABIC QUESTION MARK
- /* 70 */ "\u0663\u0662\u0661\u061F",
+ /* 73 */ "\u0663\u0662\u0661\u061F",
// Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
// part because it'll be appended by the code.
- /* 71 */ "\u0663\u0662\u0661",
- /* 72 */ "1",
- /* 73 */ "2",
- /* 74 */ "3",
- /* 75 */ "4",
- /* 76 */ "5",
- /* 77 */ "6",
- /* 78 */ "7",
- /* 79 */ "8",
- /* 80 */ "9",
+ /* 74 */ "\u0663\u0662\u0661",
+ /* 75 */ "1",
+ /* 76 */ "2",
+ /* 77 */ "3",
+ /* 78 */ "4",
+ /* 79 */ "5",
+ /* 80 */ "6",
+ /* 81 */ "7",
+ /* 82 */ "8",
+ /* 83 */ "9",
// U+066B: "٫" ARABIC DECIMAL SEPARATOR
// U+066C: "٬" ARABIC THOUSANDS SEPARATOR
- /* 81 */ "0,\u066B,\u066C",
- /* 82~ */
+ /* 84 */ "0,\u066B,\u066C",
+ /* 85~ */
null, null, null, null, null, null, null, null, null, null,
- /* ~91 */
+ /* ~94 */
// U+060C: "،" ARABIC COMMA
- /* 92 */ "\u060C",
- /* 93 */ "\\,",
- /* 94 */ "\u061F",
- /* 95 */ "\u061B",
+ /* 95 */ "\u060C",
+ /* 96 */ "\\,",
+ /* 97 */ "\u061F",
+ /* 98 */ "\u061B",
// U+066A: "٪" ARABIC PERCENT SIGN
- /* 96 */ "\u066A",
- /* 97 */ null,
- /* 98 */ "?",
- /* 99 */ ";",
+ /* 99 */ "\u066A",
+ /* 100 */ null,
+ /* 101 */ "?",
+ /* 102 */ ";",
// U+2030: "‰" PER MILLE SIGN
- /* 100 */ "\\%,\u2030",
- /* 101~ */
+ /* 103 */ "\\%,\u2030",
+ /* 104~ */
null, null, null, null, null,
- /* ~105 */
+ /* ~108 */
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
// U+061F: "؟" ARABIC QUESTION MARK
- /* 106 */ "\u060C",
- /* 107 */ "\u061F",
- /* 108 */ "\u061F,\u061B,!,:,-,/,\',\"",
+ /* 109 */ "\u060C",
+ /* 110 */ "\u061F",
+ /* 111 */ "\u061F,\u061B,!,:,-,/,\',\"",
+ };
+
+ /* Language az: Azerbaijani */
+ private static final String[] LANGUAGE_az = {
+ /* 0 */ null,
+ // U+0259: "ə" LATIN SMALL LETTER SCHWA
+ /* 1 */ "\u0259",
+ // U+0131: "ı" LATIN SMALL LETTER DOTLESS I
+ // U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+ // U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+ // U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+ // U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+ // U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+ // U+012B: "ī" LATIN SMALL LETTER I WITH MACRON
+ /* 2 */ "\u0131,\u00EE,\u00EF,\u00EC,\u00ED,\u012F,\u012B",
+ // U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+ // U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+ // U+0153: "œ" LATIN SMALL LIGATURE OE
+ // U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+ // U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+ // U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+ // U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+ // U+014D: "ō" LATIN SMALL LETTER O WITH MACRON
+ /* 3 */ "\u00F6,\u00F4,\u0153,\u00F2,\u00F3,\u00F5,\u00F8,\u014D",
+ // U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+ // U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+ // U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+ // U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+ // U+016B: "ū" LATIN SMALL LETTER U WITH MACRON
+ /* 4 */ "\u00FC,\u00FB,\u00F9,\u00FA,\u016B",
+ // U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
+ // U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ // U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+ // U+0161: "š" LATIN SMALL LETTER S WITH CARON
+ /* 5 */ "\u015F,\u00DF,\u015B,\u0161",
+ /* 6 */ null,
+ // U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ // U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+ // U+010D: "č" LATIN SMALL LETTER C WITH CARON
+ /* 7 */ "\u00E7,\u0107,\u010D",
+ /* 8~ */
+ null, null, null, null, null, null, null,
+ /* ~14 */
+ // U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE
+ /* 15 */ "\u011F",
};
/* Language be: Belarusian */
@@ -637,23 +685,23 @@ public final class KeyboardTextsSet {
// U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
/* 29 */ "\u0456",
/* 30~ */
- null, null, null, null, null,
- /* ~34 */
+ null, null, null, null, null, null, null,
+ /* ~36 */
// U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
- /* 35 */ "\u044A",
- /* 36~ */
- null, null, null, null,
- /* ~39 */
+ /* 37 */ "\u044A",
+ /* 38~ */
+ null, null, null, null, null,
+ /* ~42 */
// U+0451: "ё" CYRILLIC SMALL LETTER IO
- /* 40 */ "\u0451",
- /* 41 */ null,
+ /* 43 */ "\u0451",
+ /* 44 */ null,
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
- /* 42 */ "\u0410\u0411\u0412",
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
+ /* 45 */ "\u0410\u0411\u0412",
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
};
/* Language bg: Bulgarian */
@@ -661,16 +709,16 @@ public final class KeyboardTextsSet {
/* 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,
- /* ~41 */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~44 */
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
- /* 42 */ "\u0410\u0411\u0412",
- /* 43 */ null,
+ /* 45 */ "\u0410\u0411\u0412",
+ /* 46 */ null,
// single_quotes of Bulgarian is default single_quotes_right_left.
- /* 44 */ "!text/double_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
};
/* Language ca: Catalan */
@@ -804,11 +852,12 @@ public final class KeyboardTextsSet {
/* 13~ */
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,
- /* ~42 */
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
- /* 45 */ "!text/single_raqm_laqm",
- /* 46 */ "!text/double_raqm_laqm",
+ null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
+ /* 48 */ "!text/single_raqm_laqm",
+ /* 49 */ "!text/double_raqm_laqm",
};
/* Language da: Danish */
@@ -872,12 +921,12 @@ public final class KeyboardTextsSet {
/* 24 */ "\u00F6",
/* 25~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null,
- /* ~42 */
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
- /* 45 */ "!text/single_raqm_laqm",
- /* 46 */ "!text/double_raqm_laqm",
+ null, null, null, null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
+ /* 48 */ "!text/single_raqm_laqm",
+ /* 49 */ "!text/double_raqm_laqm",
};
/* Language de: German */
@@ -923,12 +972,12 @@ public final class KeyboardTextsSet {
/* 7~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null,
- /* ~42 */
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
- /* 45 */ "!text/single_raqm_laqm",
- /* 46 */ "!text/double_raqm_laqm",
+ null, null, null, null, null, null, null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
+ /* 48 */ "!text/single_raqm_laqm",
+ /* 49 */ "!text/double_raqm_laqm",
};
/* Language el: Greek */
@@ -936,13 +985,13 @@ public final class KeyboardTextsSet {
/* 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,
- /* ~41 */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~44 */
// Label for "switch to alphabetic" key.
// U+0391: "Α" GREEK CAPITAL LETTER ALPHA
// U+0392: "Β" GREEK CAPITAL LETTER BETA
// U+0393: "Γ" GREEK CAPITAL LETTER GAMMA
- /* 42 */ "\u0391\u0392\u0393",
+ /* 45 */ "\u0391\u0392\u0393",
};
/* Language en: English */
@@ -1113,20 +1162,21 @@ public final class KeyboardTextsSet {
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- /* ~108 */
- /* 109 */ "q",
- /* 110 */ "x",
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null, null,
+ /* ~111 */
+ /* 112 */ "q",
+ /* 113 */ "x",
// U+015D: "ŝ" LATIN SMALL LETTER S WITH CIRCUMFLEX
- /* 111 */ "\u015D",
+ /* 114 */ "\u015D",
// U+011D: "ĝ" LATIN SMALL LETTER G WITH CIRCUMFLEX
- /* 112 */ "\u011D",
+ /* 115 */ "\u011D",
// U+016D: "ŭ" LATIN SMALL LETTER U WITH BREVE
- /* 113 */ "\u016D",
+ /* 116 */ "\u016D",
// U+0109: "ĉ" LATIN SMALL LETTER C WITH CIRCUMFLEX
- /* 114 */ "\u0109",
+ /* 117 */ "\u0109",
// U+0135: "ĵ" LATIN SMALL LETTER J WITH CIRCUMFLEX
- /* 115 */ "\u0135",
+ /* 118 */ "\u0135",
};
/* Language es: Spanish */
@@ -1184,25 +1234,25 @@ public final class KeyboardTextsSet {
/* 8~ */
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,
- /* ~49 */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~52 */
// U+00A1: "¡" INVERTED EXCLAMATION MARK
// U+00BF: "¿" INVERTED QUESTION MARK
- /* 50 */ "!fixedColumnOrder!9,\u00A1,\",\',#,-,:,!,\\,,?,\u00BF,@,&,\\%,+,;,/,(,)",
- /* 51~ */
+ /* 53 */ "!fixedColumnOrder!9,\u00A1,\",\',#,-,:,!,\\,,?,\u00BF,@,&,\\%,+,;,/,(,)",
+ /* 54~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null,
- /* ~102 */
+ /* ~105 */
// U+00A1: "¡" INVERTED EXCLAMATION MARK
- /* 103 */ "!,\u00A1",
- /* 104 */ null,
+ /* 106 */ "!,\u00A1",
+ /* 107 */ null,
// U+00BF: "¿" INVERTED QUESTION MARK
- /* 105 */ "?,\u00BF",
- /* 106 */ "\"",
- /* 107 */ "\'",
- /* 108 */ "\'",
+ /* 108 */ "?,\u00BF",
+ /* 109 */ "\"",
+ /* 110 */ "\'",
+ /* 111 */ "\'",
};
/* Language et: Estonian */
@@ -1305,10 +1355,10 @@ public final class KeyboardTextsSet {
/* 23 */ "\u00F5",
/* 24~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null,
- /* ~42 */
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
+ null, null, null, null, null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
};
/* Language fa: Persian */
@@ -1316,45 +1366,45 @@ public final class KeyboardTextsSet {
/* 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,
- /* ~41 */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~44 */
// Label for "switch to alphabetic" key.
// U+0627: "ا" ARABIC LETTER ALEF
// U+200C: ZERO WIDTH NON-JOINER
// U+0628: "ب" ARABIC LETTER BEH
// U+067E: "پ" ARABIC LETTER PEH
- /* 42 */ "\u0627\u200C\u0628\u200C\u067E",
- /* 43 */ null,
- /* 44 */ null,
- /* 45 */ "!text/single_laqm_raqm_rtl",
- /* 46 */ "!text/double_laqm_raqm_rtl",
- /* 47~ */
+ /* 45 */ "\u0627\u200C\u0628\u200C\u067E",
+ /* 46 */ null,
+ /* 47 */ null,
+ /* 48 */ "!text/single_laqm_raqm_rtl",
+ /* 49 */ "!text/double_laqm_raqm_rtl",
+ /* 50~ */
null, null, null,
- /* ~49 */
+ /* ~52 */
// U+061F: "؟" ARABIC QUESTION MARK
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
- /* 50 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(,)",
+ /* 53 */ "!fixedColumnOrder!8,\",\',#,-,:,!,\u060C,\u061F,@,&,\\%,+,\u061B,/,(,)",
// U+2605: "★" BLACK STAR
// U+066D: "٭" ARABIC FIVE POINTED STAR
- /* 51 */ "\u2605,\u066D",
+ /* 54 */ "\u2605,\u066D",
// U+266A: "♪" EIGHTH NOTE
- /* 52 */ "\u266A",
- /* 53 */ null,
+ /* 55 */ "\u266A",
+ /* 56 */ null,
// The all letters need to be mirrored are found at
// http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt
// U+FD3E: "﴾" ORNATE LEFT PARENTHESIS
// U+FD3F: "﴿" ORNATE RIGHT PARENTHESIS
- /* 54 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
- /* 55 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
+ /* 57 */ "!fixedColumnOrder!4,\uFD3E|\uFD3F,<|>,{|},[|]",
+ /* 58 */ "!fixedColumnOrder!4,\uFD3F|\uFD3E,>|<,}|{,]|[",
// U+2264: "≤" LESS-THAN OR EQUAL TO
// U+2265: "≥" GREATER-THAN EQUAL TO
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
// U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
- /* 56 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,<|>",
- /* 57 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,>|<",
+ /* 59 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,<|>",
+ /* 60 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,>|<",
// U+0655: "ٕ" ARABIC HAMZA BELOW
// U+0652: "ْ" ARABIC SUKUN
// U+0651: "ّ" ARABIC SHADDA
@@ -1371,74 +1421,74 @@ public final class KeyboardTextsSet {
// U+0640: "ـ" ARABIC TATWEEL
// In order to make Tatweel easily distinguishable from other punctuations, we use consecutive Tatweels only for its displayed label.
// Note: The space character is needed as a preceding letter to draw Arabic diacritics characters correctly.
- /* 58 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0652|\u0652, \u0651|\u0651, \u064C|\u064C, \u064D|\u064D, \u064B|\u064B, \u0654|\u0654, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u064F|\u064F, \u0650|\u0650, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
- /* 59 */ "\u064B",
+ /* 61 */ "!fixedColumnOrder!7, \u0655|\u0655, \u0652|\u0652, \u0651|\u0651, \u064C|\u064C, \u064D|\u064D, \u064B|\u064B, \u0654|\u0654, \u0656|\u0656, \u0670|\u0670, \u0653|\u0653, \u064F|\u064F, \u0650|\u0650, \u064E|\u064E,\u0640\u0640\u0640|\u0640",
+ /* 62 */ "\u064B",
// U+06F1: "۱" EXTENDED ARABIC-INDIC DIGIT ONE
- /* 60 */ "\u06F1",
+ /* 63 */ "\u06F1",
// U+06F2: "۲" EXTENDED ARABIC-INDIC DIGIT TWO
- /* 61 */ "\u06F2",
+ /* 64 */ "\u06F2",
// U+06F3: "۳" EXTENDED ARABIC-INDIC DIGIT THREE
- /* 62 */ "\u06F3",
+ /* 65 */ "\u06F3",
// U+06F4: "۴" EXTENDED ARABIC-INDIC DIGIT FOUR
- /* 63 */ "\u06F4",
+ /* 66 */ "\u06F4",
// U+06F5: "۵" EXTENDED ARABIC-INDIC DIGIT FIVE
- /* 64 */ "\u06F5",
+ /* 67 */ "\u06F5",
// U+06F6: "۶" EXTENDED ARABIC-INDIC DIGIT SIX
- /* 65 */ "\u06F6",
+ /* 68 */ "\u06F6",
// U+06F7: "۷" EXTENDED ARABIC-INDIC DIGIT SEVEN
- /* 66 */ "\u06F7",
+ /* 69 */ "\u06F7",
// U+06F8: "۸" EXTENDED ARABIC-INDIC DIGIT EIGHT
- /* 67 */ "\u06F8",
+ /* 70 */ "\u06F8",
// U+06F9: "۹" EXTENDED ARABIC-INDIC DIGIT NINE
- /* 68 */ "\u06F9",
+ /* 71 */ "\u06F9",
// U+06F0: "۰" EXTENDED ARABIC-INDIC DIGIT ZERO
- /* 69 */ "\u06F0",
+ /* 72 */ "\u06F0",
// Label for "switch to symbols" key.
// U+061F: "؟" ARABIC QUESTION MARK
- /* 70 */ "\u06F3\u06F2\u06F1\u061F",
+ /* 73 */ "\u06F3\u06F2\u06F1\u061F",
// Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
// part because it'll be appended by the code.
- /* 71 */ "\u06F3\u06F2\u06F1",
- /* 72 */ "1",
- /* 73 */ "2",
- /* 74 */ "3",
- /* 75 */ "4",
- /* 76 */ "5",
- /* 77 */ "6",
- /* 78 */ "7",
- /* 79 */ "8",
- /* 80 */ "9",
+ /* 74 */ "\u06F3\u06F2\u06F1",
+ /* 75 */ "1",
+ /* 76 */ "2",
+ /* 77 */ "3",
+ /* 78 */ "4",
+ /* 79 */ "5",
+ /* 80 */ "6",
+ /* 81 */ "7",
+ /* 82 */ "8",
+ /* 83 */ "9",
// U+066B: "٫" ARABIC DECIMAL SEPARATOR
// U+066C: "٬" ARABIC THOUSANDS SEPARATOR
- /* 81 */ "0,\u066B,\u066C",
- /* 82~ */
+ /* 84 */ "0,\u066B,\u066C",
+ /* 85~ */
null, null, null, null, null, null, null, null, null, null,
- /* ~91 */
+ /* ~94 */
// U+060C: "،" ARABIC COMMA
- /* 92 */ "\u060C",
- /* 93 */ "\\,",
- /* 94 */ "\u061F",
- /* 95 */ "\u061B",
+ /* 95 */ "\u060C",
+ /* 96 */ "\\,",
+ /* 97 */ "\u061F",
+ /* 98 */ "\u061B",
// U+066A: "٪" ARABIC PERCENT SIGN
- /* 96 */ "\u066A",
- /* 97 */ null,
- /* 98 */ "?",
- /* 99 */ ";",
+ /* 99 */ "\u066A",
+ /* 100 */ null,
+ /* 101 */ "?",
+ /* 102 */ ";",
// U+2030: "‰" PER MILLE SIGN
- /* 100 */ "\\%,\u2030",
+ /* 103 */ "\\%,\u2030",
// U+060C: "،" ARABIC COMMA
// U+061B: "؛" ARABIC SEMICOLON
// U+061F: "؟" ARABIC QUESTION MARK
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
- /* 101 */ "\u060C",
- /* 102 */ "!",
- /* 103 */ "!,\\,",
- /* 104 */ "\u061F",
- /* 105 */ "\u061F,?",
- /* 106 */ "\u060C",
+ /* 104 */ "\u060C",
+ /* 105 */ "!",
+ /* 106 */ "!,\\,",
/* 107 */ "\u061F",
- /* 108 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB",
+ /* 108 */ "\u061F,?",
+ /* 109 */ "\u060C",
+ /* 110 */ "\u061F",
+ /* 111 */ "!fixedColumnOrder!4,:,!,\u061F,\u061B,-,/,\u00AB|\u00BB,\u00BB|\u00AB",
};
/* Language fi: Finnish */
@@ -1546,56 +1596,56 @@ public final class KeyboardTextsSet {
/* 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,
- /* ~41 */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~44 */
// Label for "switch to alphabetic" key.
// U+0915: "क" DEVANAGARI LETTER KA
// U+0916: "ख" DEVANAGARI LETTER KHA
// U+0917: "ग" DEVANAGARI LETTER GA
- /* 42 */ "\u0915\u0916\u0917",
- /* 43~ */
+ /* 45 */ "\u0915\u0916\u0917",
+ /* 46~ */
null, null, null, null, null,
- /* ~47 */
+ /* ~50 */
// U+20B9: "₹" INDIAN RUPEE SIGN
- /* 48 */ "\u20B9",
- /* 49~ */
+ /* 51 */ "\u20B9",
+ /* 52~ */
null, null, null, null, null, null, null, null, null, null, null,
- /* ~59 */
+ /* ~62 */
// U+0967: "१" DEVANAGARI DIGIT ONE
- /* 60 */ "\u0967",
+ /* 63 */ "\u0967",
// U+0968: "२" DEVANAGARI DIGIT TWO
- /* 61 */ "\u0968",
+ /* 64 */ "\u0968",
// U+0969: "३" DEVANAGARI DIGIT THREE
- /* 62 */ "\u0969",
+ /* 65 */ "\u0969",
// U+096A: "४" DEVANAGARI DIGIT FOUR
- /* 63 */ "\u096A",
+ /* 66 */ "\u096A",
// U+096B: "५" DEVANAGARI DIGIT FIVE
- /* 64 */ "\u096B",
+ /* 67 */ "\u096B",
// U+096C: "६" DEVANAGARI DIGIT SIX
- /* 65 */ "\u096C",
+ /* 68 */ "\u096C",
// U+096D: "७" DEVANAGARI DIGIT SEVEN
- /* 66 */ "\u096D",
+ /* 69 */ "\u096D",
// U+096E: "८" DEVANAGARI DIGIT EIGHT
- /* 67 */ "\u096E",
+ /* 70 */ "\u096E",
// U+096F: "९" DEVANAGARI DIGIT NINE
- /* 68 */ "\u096F",
+ /* 71 */ "\u096F",
// U+0966: "०" DEVANAGARI DIGIT ZERO
- /* 69 */ "\u0966",
+ /* 72 */ "\u0966",
// Label for "switch to symbols" key.
- /* 70 */ "?\u0967\u0968\u0969",
+ /* 73 */ "?\u0967\u0968\u0969",
// Label for "switch to symbols with microphone" key. This string shouldn't include the "mic"
// part because it'll be appended by the code.
- /* 71 */ "\u0967\u0968\u0969",
- /* 72 */ "1",
- /* 73 */ "2",
- /* 74 */ "3",
- /* 75 */ "4",
- /* 76 */ "5",
- /* 77 */ "6",
- /* 78 */ "7",
- /* 79 */ "8",
- /* 80 */ "9",
- /* 81 */ "0",
+ /* 74 */ "\u0967\u0968\u0969",
+ /* 75 */ "1",
+ /* 76 */ "2",
+ /* 77 */ "3",
+ /* 78 */ "4",
+ /* 79 */ "5",
+ /* 80 */ "6",
+ /* 81 */ "7",
+ /* 82 */ "8",
+ /* 83 */ "9",
+ /* 84 */ "0",
};
/* Language hr: Croatian */
@@ -1626,11 +1676,12 @@ public final class KeyboardTextsSet {
/* 13~ */
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,
- /* ~42 */
- /* 43 */ "!text/single_9qm_rqm",
- /* 44 */ "!text/double_9qm_rqm",
- /* 45 */ "!text/single_raqm_laqm",
- /* 46 */ "!text/double_raqm_laqm",
+ null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_rqm",
+ /* 47 */ "!text/double_9qm_rqm",
+ /* 48 */ "!text/single_raqm_laqm",
+ /* 49 */ "!text/double_raqm_laqm",
};
/* Language hu: Hungarian */
@@ -1679,12 +1730,12 @@ public final class KeyboardTextsSet {
/* 5~ */
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,
- /* ~42 */
- /* 43 */ "!text/single_9qm_rqm",
- /* 44 */ "!text/double_9qm_rqm",
- /* 45 */ "!text/single_raqm_laqm",
- /* 46 */ "!text/double_raqm_laqm",
+ null, null, null, null, null, null, null, null, null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_rqm",
+ /* 47 */ "!text/double_9qm_rqm",
+ /* 48 */ "!text/single_raqm_laqm",
+ /* 49 */ "!text/double_raqm_laqm",
};
/* Language is: Icelandic */
@@ -1750,10 +1801,10 @@ public final class KeyboardTextsSet {
/* 22 */ "\u00FE",
/* 23~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null,
- /* ~42 */
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
+ null, null, null, null, null, null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
};
/* Language it: Italian */
@@ -1806,13 +1857,13 @@ public final class KeyboardTextsSet {
/* 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,
- /* ~41 */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~44 */
// Label for "switch to alphabetic" key.
// U+05D0: "א" HEBREW LETTER ALEF
// U+05D1: "ב" HEBREW LETTER BET
// U+05D2: "ג" HEBREW LETTER GIMEL
- /* 42 */ "\u05D0\u05D1\u05D2",
+ /* 45 */ "\u05D0\u05D1\u05D2",
// The following characters don't need BIDI mirroring.
// U+2018: "‘" LEFT SINGLE QUOTATION MARK
// U+2019: "’" RIGHT SINGLE QUOTATION MARK
@@ -1820,31 +1871,31 @@ public final class KeyboardTextsSet {
// U+201C: "“" LEFT DOUBLE QUOTATION MARK
// U+201D: "”" RIGHT DOUBLE QUOTATION MARK
// U+201E: "„" DOUBLE LOW-9 QUOTATION MARK
- /* 43 */ "\u2018,\u2019,\u201A",
- /* 44 */ "\u201C,\u201D,\u201E",
- /* 45 */ "!text/single_laqm_raqm_rtl",
- /* 46 */ "!text/double_laqm_raqm_rtl",
- /* 47~ */
+ /* 46 */ "\u2018,\u2019,\u201A",
+ /* 47 */ "\u201C,\u201D,\u201E",
+ /* 48 */ "!text/single_laqm_raqm_rtl",
+ /* 49 */ "!text/double_laqm_raqm_rtl",
+ /* 50~ */
null, null, null, null,
- /* ~50 */
+ /* ~53 */
// U+2605: "★" BLACK STAR
- /* 51 */ "\u2605",
- /* 52 */ null,
+ /* 54 */ "\u2605",
+ /* 55 */ null,
// U+00B1: "±" PLUS-MINUS SIGN
// U+FB29: "﬩" HEBREW LETTER ALTERNATIVE PLUS SIGN
- /* 53 */ "\u00B1,\uFB29",
+ /* 56 */ "\u00B1,\uFB29",
// The all letters need to be mirrored are found at
// http://www.unicode.org/Public/6.1.0/ucd/BidiMirroring.txt
- /* 54 */ "!fixedColumnOrder!3,<|>,{|},[|]",
- /* 55 */ "!fixedColumnOrder!3,>|<,}|{,]|[",
+ /* 57 */ "!fixedColumnOrder!3,<|>,{|},[|]",
+ /* 58 */ "!fixedColumnOrder!3,>|<,}|{,]|[",
// U+2264: "≤" LESS-THAN OR EQUAL TO
// U+2265: "≥" GREATER-THAN EQUAL TO
// U+00AB: "«" LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+00BB: "»" RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
// U+2039: "‹" SINGLE LEFT-POINTING ANGLE QUOTATION MARK
// U+203A: "›" SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
- /* 56 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
- /* 57 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
+ /* 59 */ "!fixedColumnOrder!3,\u2039|\u203A,\u2264|\u2265,\u00AB|\u00BB",
+ /* 60 */ "!fixedColumnOrder!3,\u203A|\u2039,\u2265|\u2264,\u00BB|\u00AB",
};
/* Language ka: Georgian */
@@ -1852,15 +1903,63 @@ public final class KeyboardTextsSet {
/* 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,
- /* ~41 */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~44 */
// Label for "switch to alphabetic" key.
// U+10D0: "ა" GEORGIAN LETTER AN
// U+10D1: "ბ" GEORGIAN LETTER BAN
// U+10D2: "გ" GEORGIAN LETTER GAN
- /* 42 */ "\u10D0\u10D1\u10D2",
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
+ /* 45 */ "\u10D0\u10D1\u10D2",
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
+ };
+
+ /* Language kk: Kazakh */
+ private static final String[] LANGUAGE_kk = {
+ /* 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,
+ /* ~24 */
+ // U+0449: "щ" CYRILLIC SMALL LETTER SHCHA
+ /* 25 */ "\u0449",
+ // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+ /* 26 */ "\u044A",
+ // U+044B: "ы" CYRILLIC SMALL LETTER YERU
+ /* 27 */ "\u044B",
+ // U+044D: "э" CYRILLIC SMALL LETTER E
+ /* 28 */ "\u044D",
+ // U+0438: "и" CYRILLIC SMALL LETTER I
+ /* 29 */ "\u0438",
+ // U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U
+ // U+04B1: "ұ" CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE
+ /* 30 */ "\u04AF,\u04B1",
+ // U+049B: "қ" CYRILLIC SMALL LETTER KA WITH DESCENDER
+ /* 31 */ "\u049B",
+ // U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER
+ /* 32 */ "\u04A3",
+ // U+0493: "ғ" CYRILLIC SMALL LETTER GHE WITH STROKE
+ /* 33 */ "\u0493",
+ // U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+ /* 34 */ "\u0456",
+ // U+04D9: "ә" CYRILLIC SMALL LETTER SCHWA
+ /* 35 */ "\u04D9",
+ // U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O
+ /* 36 */ "\u04E9",
+ // U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
+ /* 37 */ "\u044A",
+ // U+04BB: "һ" CYRILLIC SMALL LETTER SHHA
+ /* 38 */ "\u04BB",
+ /* 39~ */
+ null, null, null, null,
+ /* ~42 */
+ // U+0451: "ё" CYRILLIC SMALL LETTER IO
+ /* 43 */ "\u0451",
+ /* 44 */ null,
+ // Label for "switch to alphabetic" key.
+ // U+0410: "А" CYRILLIC CAPITAL LETTER A
+ // U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ // U+0412: "В" CYRILLIC CAPITAL LETTER VE
+ /* 45 */ "\u0410\u0411\u0412",
};
/* Language ky: Kirghiz */
@@ -1881,25 +1980,27 @@ public final class KeyboardTextsSet {
/* 29 */ "\u0438",
// U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U
/* 30 */ "\u04AF",
+ /* 31 */ null,
// U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER
- /* 31 */ "\u04A3",
- /* 32 */ null,
- /* 33 */ null,
+ /* 32 */ "\u04A3",
+ /* 33~ */
+ null, null, null,
+ /* ~35 */
// U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O
- /* 34 */ "\u04E9",
+ /* 36 */ "\u04E9",
// U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
- /* 35 */ "\u044A",
- /* 36~ */
- null, null, null, null,
- /* ~39 */
+ /* 37 */ "\u044A",
+ /* 38~ */
+ null, null, null, null, null,
+ /* ~42 */
// U+0451: "ё" CYRILLIC SMALL LETTER IO
- /* 40 */ "\u0451",
- /* 41 */ null,
+ /* 43 */ "\u0451",
+ /* 44 */ null,
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
- /* 42 */ "\u0410\u0411\u0412",
+ /* 45 */ "\u0410\u0411\u0412",
};
/* Language lt: Lithuanian */
@@ -1992,10 +2093,10 @@ public final class KeyboardTextsSet {
/* 15 */ "\u0123,\u011F",
/* 16~ */
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,
- /* ~42 */
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
};
/* Language lv: Latvian */
@@ -2087,10 +2188,10 @@ public final class KeyboardTextsSet {
/* 15 */ "\u0123,\u011F",
/* 16~ */
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,
- /* ~42 */
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
};
/* Language mk: Macedonian */
@@ -2098,27 +2199,27 @@ public final class KeyboardTextsSet {
/* 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,
- /* ~35 */
+ null, null, null, null, null, null, null, null, null,
+ /* ~38 */
// U+0455: "ѕ" CYRILLIC SMALL LETTER DZE
- /* 36 */ "\u0455",
+ /* 39 */ "\u0455",
// U+045C: "ќ" CYRILLIC SMALL LETTER KJE
- /* 37 */ "\u045C",
+ /* 40 */ "\u045C",
// U+0437: "з" CYRILLIC SMALL LETTER ZE
- /* 38 */ "\u0437",
+ /* 41 */ "\u0437",
// U+0453: "ѓ" CYRILLIC SMALL LETTER GJE
- /* 39 */ "\u0453",
+ /* 42 */ "\u0453",
// U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE
- /* 40 */ "\u0450",
+ /* 43 */ "\u0450",
// U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE
- /* 41 */ "\u045D",
+ /* 44 */ "\u045D",
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
- /* 42 */ "\u0410\u0411\u0412",
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
+ /* 45 */ "\u0410\u0411\u0412",
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
};
/* Language mn: Mongolian */
@@ -2126,18 +2227,18 @@ public final class KeyboardTextsSet {
/* 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,
- /* ~41 */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~44 */
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
- /* 42 */ "\u0410\u0411\u0412",
- /* 43~ */
+ /* 45 */ "\u0410\u0411\u0412",
+ /* 46~ */
null, null, null, null, null,
- /* ~47 */
+ /* ~50 */
// U+20AE: "₮" TUGRIK SIGN
- /* 48 */ "\u20AE",
+ /* 51 */ "\u20AE",
};
/* Language nb: Norwegian Bokmål */
@@ -2187,10 +2288,10 @@ public final class KeyboardTextsSet {
/* 24 */ "\u00E4",
/* 25~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null,
- /* ~42 */
- /* 43 */ "!text/single_9qm_rqm",
- /* 44 */ "!text/double_9qm_rqm",
+ null, null, null, null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_rqm",
+ /* 47 */ "!text/double_9qm_rqm",
};
/* Language nl: Dutch */
@@ -2245,10 +2346,10 @@ public final class KeyboardTextsSet {
/* 9~ */
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,
- /* ~42 */
- /* 43 */ "!text/single_9qm_rqm",
- /* 44 */ "!text/double_9qm_rqm",
+ null, null, null, null, null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_rqm",
+ /* 47 */ "!text/double_9qm_rqm",
};
/* Language pl: Polish */
@@ -2305,10 +2406,11 @@ public final class KeyboardTextsSet {
/* 14 */ "\u0142",
/* 15~ */
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,
- /* ~42 */
- /* 43 */ "!text/single_9qm_rqm",
- /* 44 */ "!text/double_9qm_rqm",
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_rqm",
+ /* 47 */ "!text/double_9qm_rqm",
};
/* Language pt: Portuguese */
@@ -2411,10 +2513,10 @@ public final class KeyboardTextsSet {
/* 12~ */
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,
- /* ~42 */
- /* 43 */ "!text/single_9qm_rqm",
- /* 44 */ "!text/double_9qm_rqm",
+ null, null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_rqm",
+ /* 47 */ "!text/double_9qm_rqm",
};
/* Language ru: Russian */
@@ -2434,23 +2536,23 @@ public final class KeyboardTextsSet {
// U+0438: "и" CYRILLIC SMALL LETTER I
/* 29 */ "\u0438",
/* 30~ */
- null, null, null, null, null,
- /* ~34 */
+ null, null, null, null, null, null, null,
+ /* ~36 */
// U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
- /* 35 */ "\u044A",
- /* 36~ */
- null, null, null, null,
- /* ~39 */
+ /* 37 */ "\u044A",
+ /* 38~ */
+ null, null, null, null, null,
+ /* ~42 */
// U+0451: "ё" CYRILLIC SMALL LETTER IO
- /* 40 */ "\u0451",
- /* 41 */ null,
+ /* 43 */ "\u0451",
+ /* 44 */ null,
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
- /* 42 */ "\u0410\u0411\u0412",
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
+ /* 45 */ "\u0410\u0411\u0412",
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
};
/* Language sk: Slovak */
@@ -2543,12 +2645,12 @@ public final class KeyboardTextsSet {
/* 15 */ "\u0123,\u011F",
/* 16~ */
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,
- /* ~42 */
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
- /* 45 */ "!text/single_raqm_laqm",
- /* 46 */ "!text/double_raqm_laqm",
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
+ /* 48 */ "!text/single_raqm_laqm",
+ /* 49 */ "!text/double_raqm_laqm",
};
/* Language sl: Slovenian */
@@ -2572,11 +2674,12 @@ public final class KeyboardTextsSet {
/* 13~ */
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,
- /* ~42 */
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
- /* 45 */ "!text/single_raqm_laqm",
- /* 46 */ "!text/double_raqm_laqm",
+ null, null, null,
+ /* ~45 */
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
+ /* 48 */ "!text/single_raqm_laqm",
+ /* 49 */ "!text/double_raqm_laqm",
};
/* Language sr: Serbian */
@@ -2584,8 +2687,8 @@ public final class KeyboardTextsSet {
/* 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,
- /* ~35 */
+ null, null, null, null, null, null, null, null, null,
+ /* ~38 */
// TODO: Move these to sr-Latn once we can handle IETF language tag with script name specified.
// BEGIN: More keys definitions for Serbian (Latin)
// U+0161: "š" LATIN SMALL LETTER S WITH CARON
@@ -2605,27 +2708,27 @@ public final class KeyboardTextsSet {
// END: More keys definitions for Serbian (Latin)
// BEGIN: More keys definitions for Serbian (Cyrillic)
// U+0437: "з" CYRILLIC SMALL LETTER ZE
- /* 36 */ "\u0437",
+ /* 39 */ "\u0437",
// U+045B: "ћ" CYRILLIC SMALL LETTER TSHE
- /* 37 */ "\u045B",
+ /* 40 */ "\u045B",
// U+0455: "ѕ" CYRILLIC SMALL LETTER DZE
- /* 38 */ "\u0455",
+ /* 41 */ "\u0455",
// U+0452: "ђ" CYRILLIC SMALL LETTER DJE
- /* 39 */ "\u0452",
+ /* 42 */ "\u0452",
// U+0450: "ѐ" CYRILLIC SMALL LETTER IE WITH GRAVE
- /* 40 */ "\u0450",
+ /* 43 */ "\u0450",
// U+045D: "ѝ" CYRILLIC SMALL LETTER I WITH GRAVE
- /* 41 */ "\u045D",
+ /* 44 */ "\u045D",
// END: More keys definitions for Serbian (Cyrillic)
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
- /* 42 */ "\u0410\u0411\u0412",
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
- /* 45 */ "!text/single_raqm_laqm",
- /* 46 */ "!text/double_raqm_laqm",
+ /* 45 */ "\u0410\u0411\u0412",
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
+ /* 48 */ "!text/single_raqm_laqm",
+ /* 49 */ "!text/double_raqm_laqm",
};
/* Language sv: Swedish */
@@ -2670,10 +2773,10 @@ public final class KeyboardTextsSet {
/* 24 */ "\u00E6",
/* 25~ */
null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, null, null, null, null,
- /* ~44 */
- /* 45 */ "!text/single_raqm_laqm",
- /* 46 */ "!text/double_raqm_laqm",
+ null, null, null, null, null, null, null, null,
+ /* ~47 */
+ /* 48 */ "!text/single_raqm_laqm",
+ /* 49 */ "!text/double_raqm_laqm",
};
/* Language sw: Swahili */
@@ -2732,18 +2835,18 @@ public final class KeyboardTextsSet {
/* 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,
- /* ~41 */
+ null, null, null, null, null, null, null, null, null, null, null, null, null, null, null,
+ /* ~44 */
// Label for "switch to alphabetic" key.
// U+0E01: "ก" THAI CHARACTER KO KAI
// U+0E02: "ข" THAI CHARACTER KHO KHAI
// U+0E04: "ค" THAI CHARACTER KHO KHWAI
- /* 42 */ "\u0E01\u0E02\u0E04",
- /* 43~ */
+ /* 45 */ "\u0E01\u0E02\u0E04",
+ /* 46~ */
null, null, null, null, null,
- /* ~47 */
+ /* ~50 */
// U+0E3F: "฿" THAI CURRENCY SYMBOL BAHT
- /* 48 */ "\u0E3F",
+ /* 51 */ "\u0E3F",
};
/* Language tl: Tagalog */
@@ -2861,30 +2964,32 @@ public final class KeyboardTextsSet {
/* 28 */ "\u0454",
// U+0438: "и" CYRILLIC SMALL LETTER I
/* 29 */ "\u0438",
- /* 30 */ null,
- /* 31 */ null,
+ /* 30~ */
+ null, null, null,
+ /* ~32 */
// U+0491: "ґ" CYRILLIC SMALL LETTER GHE WITH UPTURN
- /* 32 */ "\u0491",
+ /* 33 */ "\u0491",
// U+0457: "ї" CYRILLIC SMALL LETTER YI
- /* 33 */ "\u0457",
- /* 34 */ null,
+ /* 34 */ "\u0457",
+ /* 35 */ null,
+ /* 36 */ null,
// U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN
- /* 35 */ "\u044A",
- /* 36~ */
- null, null, null, null, null, null,
- /* ~41 */
+ /* 37 */ "\u044A",
+ /* 38~ */
+ null, null, null, null, null, null, null,
+ /* ~44 */
// Label for "switch to alphabetic" key.
// U+0410: "А" CYRILLIC CAPITAL LETTER A
// U+0411: "Б" CYRILLIC CAPITAL LETTER BE
// U+0412: "В" CYRILLIC CAPITAL LETTER VE
- /* 42 */ "\u0410\u0411\u0412",
- /* 43 */ "!text/single_9qm_lqm",
- /* 44 */ "!text/double_9qm_lqm",
- /* 45~ */
+ /* 45 */ "\u0410\u0411\u0412",
+ /* 46 */ "!text/single_9qm_lqm",
+ /* 47 */ "!text/double_9qm_lqm",
+ /* 48~ */
null, null, null,
- /* ~47 */
+ /* ~50 */
// U+20B4: "₴" HRYVNIA SIGN
- /* 48 */ "\u20B4",
+ /* 51 */ "\u20B4",
};
/* Language vi: Vietnamese */
@@ -2969,10 +3074,10 @@ public final class KeyboardTextsSet {
/* 10~ */
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,
- /* ~47 */
+ null, null, null, null, null, null, null, null, null, null, null,
+ /* ~50 */
// U+20AB: "₫" DONG SIGN
- /* 48 */ "\u20AB",
+ /* 51 */ "\u20AB",
};
/* Language zu: Zulu */
@@ -3149,6 +3254,7 @@ public final class KeyboardTextsSet {
"DEFAULT", LANGUAGE_DEFAULT, /* default */
"af", LANGUAGE_af, /* Afrikaans */
"ar", LANGUAGE_ar, /* Arabic */
+ "az", LANGUAGE_az, /* Azerbaijani */
"be", LANGUAGE_be, /* Belarusian */
"bg", LANGUAGE_bg, /* Bulgarian */
"ca", LANGUAGE_ca, /* Catalan */
@@ -3170,6 +3276,7 @@ public final class KeyboardTextsSet {
"it", LANGUAGE_it, /* Italian */
"iw", LANGUAGE_iw, /* Hebrew */
"ka", LANGUAGE_ka, /* Georgian */
+ "kk", LANGUAGE_kk, /* Kazakh */
"ky", LANGUAGE_ky, /* Kirghiz */
"lt", LANGUAGE_lt, /* Lithuanian */
"lv", LANGUAGE_lv, /* Latvian */
diff --git a/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
new file mode 100644
index 000000000..ebbcedc96
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/AbstractDictionaryWriter.java
@@ -0,0 +1,78 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+// TODO: Quit extending Dictionary after implementing dynamic binary dictionary.
+abstract public class AbstractDictionaryWriter extends Dictionary {
+ /** Used for Log actions from this class */
+ private static final String TAG = AbstractDictionaryWriter.class.getSimpleName();
+
+ private final Context mContext;
+
+ public AbstractDictionaryWriter(final Context context, final String dictType) {
+ super(dictType);
+ mContext = context;
+ }
+
+ abstract public void clear();
+
+ abstract public void addUnigramWord(final String word, final String shortcutTarget,
+ final int frequency, final boolean isNotAWord);
+
+ abstract public void addBigramWords(final String word0, final String word1,
+ final int frequency, final boolean isValid);
+
+ abstract public void removeBigramWords(final String word0, final String word1);
+
+ abstract protected void writeBinaryDictionary(final FileOutputStream out)
+ throws IOException, UnsupportedFormatException;
+
+ public void write(final String fileName) {
+ final String tempFileName = fileName + ".temp";
+ final File file = new File(mContext.getFilesDir(), fileName);
+ final File tempFile = new File(mContext.getFilesDir(), tempFileName);
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(tempFile);
+ writeBinaryDictionary(out);
+ out.flush();
+ out.close();
+ tempFile.renameTo(file);
+ } catch (IOException e) {
+ Log.e(TAG, "IO exception while writing file", e);
+ } catch (UnsupportedFormatException e) {
+ Log.e(TAG, "Unsupported format", e);
+ } finally {
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
index 4b5d02716..6e26a587f 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryFileDumper.java
@@ -308,6 +308,7 @@ public final class BinaryDictionaryFileDumper {
Log.e(TAG, "Could not have the dictionary pack delete a word list");
}
BinaryDictionaryGetter.removeFilesWithIdExcept(context, wordlistId, finalFile);
+ Log.e(TAG, "Successfully copied file for wordlist ID " + wordlistId);
// Success! Close files (through the finally{} clause) and return.
return;
} catch (Exception e) {
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
index 51dc85295..31a892e19 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java
@@ -224,14 +224,10 @@ final public class BinaryDictionaryGetter {
}
}
- // ## HACK ## we prevent usage of a dictionary before version 18 for English only. The reason
- // for this is, since those do not include whitelist entries, the new code with an old version
- // of the dictionary would lose whitelist functionality.
+ // ## HACK ## we prevent usage of a dictionary before version 18. The reason for this is, since
+ // those do not include whitelist entries, the new code with an old version of the dictionary
+ // would lose whitelist functionality.
private static boolean hackCanUseDictionaryFile(final Locale locale, final File f) {
- // Only for English - other languages didn't have a whitelist, hence this
- // ad-hoc ## HACK ##
- if (!Locale.ENGLISH.getLanguage().equals(locale.getLanguage())) return true;
-
FileInputStream inStream = null;
try {
// Read the version of the file
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index bb4a42ede..ad09b6a56 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -149,6 +149,13 @@ public final class Constants {
}
/**
+ * Custom request code used in
+ * {@link com.android.inputmethod.keyboard.KeyboardActionListener#onCustomRequest(int)}.
+ */
+ // The code to show input method picker.
+ public static final int CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER = 1;
+
+ /**
* Some common keys code. Must be positive.
*/
public static final int CODE_ENTER = '\n';
diff --git a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
index 110be9db3..c99d0e2ea 100644
--- a/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ContactsBinaryDictionary.java
@@ -109,7 +109,6 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
@Override
public void loadDictionaryAsync() {
- clearFusionDictionary();
loadDeviceAccountsEmailAddresses();
loadDictionaryAsyncForUri(ContactsContract.Profile.CONTENT_URI);
// TODO: Switch this URL to the newer ContactsContract too
@@ -236,6 +235,11 @@ public class ContactsBinaryDictionary extends ExpandableBinaryDictionary {
}
@Override
+ protected boolean needsToReloadBeforeWriting() {
+ return true;
+ }
+
+ @Override
protected boolean hasContentChanged() {
final long startTime = SystemClock.uptimeMillis();
final int contactCount = getContactCount();
diff --git a/java/src/com/android/inputmethod/latin/DebugSettings.java b/java/src/com/android/inputmethod/latin/DebugSettings.java
index 01ec7f9a7..5dbc9b157 100644
--- a/java/src/com/android/inputmethod/latin/DebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/DebugSettings.java
@@ -25,7 +25,7 @@ import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
-import com.android.inputmethod.latin.utils.Utils;
+import com.android.inputmethod.latin.utils.ApplicationUtils;
public final class DebugSettings extends PreferenceFragment
implements SharedPreferences.OnSharedPreferenceChangeListener {
@@ -118,7 +118,7 @@ public final class DebugSettings extends PreferenceFragment
}
boolean isDebugMode = mDebugMode.isChecked();
final String version = getResources().getString(
- R.string.version_text, Utils.getVersionName(getActivity()));
+ R.string.version_text, ApplicationUtils.getVersionName(getActivity()));
if (!isDebugMode) {
mDebugMode.setTitle(version);
mDebugMode.setSummary("");
diff --git a/java/src/com/android/inputmethod/latin/DictionaryWriter.java b/java/src/com/android/inputmethod/latin/DictionaryWriter.java
new file mode 100644
index 000000000..8be04c1c0
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/DictionaryWriter.java
@@ -0,0 +1,107 @@
+/*
+ * 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;
+
+import android.content.Context;
+
+import com.android.inputmethod.keyboard.ProximityInfo;
+import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
+import com.android.inputmethod.latin.makedict.FormatSpec;
+import com.android.inputmethod.latin.makedict.FusionDictionary;
+import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
+import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
+import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
+import com.android.inputmethod.latin.utils.CollectionUtils;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * An in memory dictionary for memorizing entries and writing a binary dictionary.
+ */
+public class DictionaryWriter extends AbstractDictionaryWriter {
+ // TODO: Regenerate version 3 binary dictionary.
+ private static final int BINARY_DICT_VERSION = 2;
+ private static final FormatSpec.FormatOptions FORMAT_OPTIONS =
+ new FormatSpec.FormatOptions(BINARY_DICT_VERSION);
+
+ private FusionDictionary mFusionDictionary;
+
+ public DictionaryWriter(final Context context, final String dictType) {
+ super(context, dictType);
+ clear();
+ }
+
+ @Override
+ public void clear() {
+ final HashMap<String, String> attributes = CollectionUtils.newHashMap();
+ mFusionDictionary = new FusionDictionary(new Node(),
+ new FusionDictionary.DictionaryOptions(attributes, false, false));
+ }
+
+ /**
+ * Adds a word unigram to the fusion dictionary.
+ */
+ // TODO: Create "cache dictionary" to cache fresh words for frequently updated dictionaries,
+ // considering performance regression.
+ @Override
+ public void addUnigramWord(final String word, final String shortcutTarget, final int frequency,
+ final boolean isNotAWord) {
+ if (shortcutTarget == null) {
+ mFusionDictionary.add(word, frequency, null, isNotAWord);
+ } else {
+ // TODO: Do this in the subclass, with this class taking an arraylist.
+ final ArrayList<WeightedString> shortcutTargets = CollectionUtils.newArrayList();
+ shortcutTargets.add(new WeightedString(shortcutTarget, frequency));
+ mFusionDictionary.add(word, frequency, shortcutTargets, isNotAWord);
+ }
+ }
+
+ @Override
+ public void addBigramWords(final String word0, final String word1, final int frequency,
+ final boolean isValid) {
+ mFusionDictionary.setBigram(word0, word1, frequency);
+ }
+
+ @Override
+ public void removeBigramWords(final String word0, final String word1) {
+ // This class don't support removing bigram words.
+ }
+
+ @Override
+ protected void writeBinaryDictionary(final FileOutputStream out)
+ throws IOException, UnsupportedFormatException {
+ BinaryDictInputOutput.writeDictionaryBinary(out, mFusionDictionary, FORMAT_OPTIONS);
+ }
+
+ @Override
+ public ArrayList<SuggestedWordInfo> getSuggestions(final WordComposer composer,
+ final String prevWord, final ProximityInfo proximityInfo,
+ boolean blockOffensiveWords) {
+ // This class doesn't support suggestion.
+ return null;
+ }
+
+ @Override
+ public boolean isValidWord(String word) {
+ // This class doesn't support dictionary retrieval.
+ return false;
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index 9cdb86c2d..657fc64b4 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -22,20 +22,12 @@ import android.util.Log;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.makedict.BinaryDictInputOutput;
-import com.android.inputmethod.latin.makedict.FormatSpec;
-import com.android.inputmethod.latin.makedict.FusionDictionary;
-import com.android.inputmethod.latin.makedict.FusionDictionary.Node;
-import com.android.inputmethod.latin.makedict.FusionDictionary.WeightedString;
-import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
import com.android.inputmethod.latin.utils.CollectionUtils;
import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Abstract base class for an expandable dictionary that can be created and updated dynamically
@@ -76,8 +68,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
*/
private BinaryDictionary mBinaryDictionary;
- /** The expandable fusion dictionary used to generate the binary dictionary. */
- private FusionDictionary mFusionDictionary;
+ /** The in-memory dictionary used to generate the binary dictionary. */
+ private AbstractDictionaryWriter mDictionaryWriter;
/**
* The name of this dictionary, used as the filename for storing the binary dictionary. Multiple
@@ -92,10 +84,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
/** Controls access to the local binary dictionary for this instance. */
private final DictionaryController mLocalDictionaryController = new DictionaryController();
- private static final int BINARY_DICT_VERSION = 1;
- private static final FormatSpec.FormatOptions FORMAT_OPTIONS =
- new FormatSpec.FormatOptions(BINARY_DICT_VERSION);
-
/**
* Abstract method for loading the unigrams and bigrams of a given dictionary in a background
* thread.
@@ -137,7 +125,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
mContext = context;
mBinaryDictionary = null;
mSharedDictionaryController = getSharedDictionaryController(filename);
- clearFusionDictionary();
+ mDictionaryWriter = new DictionaryWriter(context, dictType);
}
protected static String getFilenameWithLocale(final String name, final String localeStr) {
@@ -150,53 +138,57 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
@Override
public void close() {
// Ensure that no other threads are accessing the local binary dictionary.
- mLocalDictionaryController.lock();
+ mLocalDictionaryController.writeLock().lock();
try {
if (mBinaryDictionary != null) {
mBinaryDictionary.close();
mBinaryDictionary = null;
}
+ mDictionaryWriter.close();
} finally {
- mLocalDictionaryController.unlock();
+ mLocalDictionaryController.writeLock().unlock();
}
}
/**
- * Clears the fusion dictionary on the Java side. Note: Does not modify the binary dictionary on
- * the native side.
+ * Adds a word unigram to the dictionary. Used for loading a dictionary.
*/
- public void clearFusionDictionary() {
- final HashMap<String, String> attributes = CollectionUtils.newHashMap();
- mFusionDictionary = new FusionDictionary(new Node(),
- new FusionDictionary.DictionaryOptions(attributes, false, false));
+ protected void addWord(final String word, final String shortcutTarget,
+ final int frequency, final boolean isNotAWord) {
+ mDictionaryWriter.addUnigramWord(word, shortcutTarget, frequency, isNotAWord);
}
/**
- * Adds a word unigram to the fusion dictionary. Call updateBinaryDictionary when all changes
- * are done to update the binary dictionary.
+ * Sets a word bigram in the dictionary. Used for loading a dictionary.
*/
- // TODO: Create "cache dictionary" to cache fresh words for frequently updated dictionaries,
- // considering performance regression.
- protected void addWord(final String word, final String shortcutTarget, final int frequency,
- final boolean isNotAWord) {
- if (shortcutTarget == null) {
- mFusionDictionary.add(word, frequency, null, isNotAWord);
- } else {
- // TODO: Do this in the subclass, with this class taking an arraylist.
- final ArrayList<WeightedString> shortcutTargets = CollectionUtils.newArrayList();
- shortcutTargets.add(new WeightedString(shortcutTarget, frequency));
- mFusionDictionary.add(word, frequency, shortcutTargets, isNotAWord);
+ protected void setBigram(final String prevWord, final String word, final int frequency) {
+ mDictionaryWriter.addBigramWords(prevWord, word, frequency, true /* isValid */);
+ }
+
+ /**
+ * Dynamically adds a word unigram to the dictionary.
+ */
+ protected void addWordDynamically(final String word, final String shortcutTarget,
+ final int frequency, final boolean isNotAWord) {
+ mLocalDictionaryController.writeLock().lock();
+ try {
+ mDictionaryWriter.addUnigramWord(word, shortcutTarget, frequency, isNotAWord);
+ } finally {
+ mLocalDictionaryController.writeLock().unlock();
}
}
/**
- * Sets a word bigram in the fusion dictionary. Call updateBinaryDictionary when all changes are
- * done to update the binary dictionary.
+ * Dynamically sets a word bigram in the dictionary.
*/
- // TODO: Create "cache dictionary" to cache fresh bigrams for frequently updated dictionaries,
- // considering performance regression.
- protected void setBigram(final String prevWord, final String word, final int frequency) {
- mFusionDictionary.setBigram(prevWord, word, frequency);
+ protected void setBigramDynamically(final String prevWord, final String word,
+ final int frequency) {
+ mLocalDictionaryController.writeLock().lock();
+ try {
+ mDictionaryWriter.addBigramWords(prevWord, word, frequency, true /* isValid */);
+ } finally {
+ mLocalDictionaryController.writeLock().unlock();
+ }
}
@Override
@@ -204,14 +196,29 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
final String prevWord, final ProximityInfo proximityInfo,
final boolean blockOffensiveWords) {
asyncReloadDictionaryIfRequired();
- if (mLocalDictionaryController.tryLock()) {
+ // Write lock because getSuggestions in native updates session status.
+ if (mLocalDictionaryController.writeLock().tryLock()) {
try {
+ final ArrayList<SuggestedWordInfo> inMemDictSuggestion =
+ mDictionaryWriter.getSuggestions(composer, prevWord, proximityInfo,
+ blockOffensiveWords);
if (mBinaryDictionary != null) {
- return mBinaryDictionary.getSuggestions(composer, prevWord, proximityInfo,
- blockOffensiveWords);
+ final ArrayList<SuggestedWordInfo> binarySuggestion =
+ mBinaryDictionary.getSuggestions(composer, prevWord, proximityInfo,
+ blockOffensiveWords);
+ if (inMemDictSuggestion == null) {
+ return binarySuggestion;
+ } else if (binarySuggestion == null) {
+ return inMemDictSuggestion;
+ } else {
+ binarySuggestion.addAll(binarySuggestion);
+ return binarySuggestion;
+ }
+ } else {
+ return inMemDictSuggestion;
}
} finally {
- mLocalDictionaryController.unlock();
+ mLocalDictionaryController.writeLock().unlock();
}
}
return null;
@@ -224,11 +231,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
protected boolean isValidWordInner(final String word) {
- if (mLocalDictionaryController.tryLock()) {
+ if (mLocalDictionaryController.readLock().tryLock()) {
try {
return isValidWordLocked(word);
} finally {
- mLocalDictionaryController.unlock();
+ mLocalDictionaryController.readLock().unlock();
}
}
return false;
@@ -239,22 +246,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
return mBinaryDictionary.isValidWord(word);
}
- protected boolean isValidBigram(final String word1, final String word2) {
- if (mBinaryDictionary == null) return false;
- return mBinaryDictionary.isValidBigram(word1, word2);
- }
-
- protected boolean isValidBigramInner(final String word1, final String word2) {
- if (mLocalDictionaryController.tryLock()) {
- try {
- return isValidBigramLocked(word1, word2);
- } finally {
- mLocalDictionaryController.unlock();
- }
- }
- return false;
- }
-
protected boolean isValidBigramLocked(final String word1, final String word2) {
if (mBinaryDictionary == null) return false;
return mBinaryDictionary.isValidBigram(word1, word2);
@@ -273,7 +264,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* Loads the current binary dictionary from internal storage. Assumes the dictionary file
* exists.
*/
- protected void loadBinaryDictionary() {
+ private void loadBinaryDictionary() {
if (DEBUG) {
Log.d(TAG, "Loading binary dictionary: " + mFilename + " request="
+ mSharedDictionaryController.mLastUpdateRequestTime + " update="
@@ -292,9 +283,12 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
// Ensure all threads accessing the current dictionary have finished before swapping in
// the new one.
final BinaryDictionary oldBinaryDictionary = mBinaryDictionary;
- mLocalDictionaryController.lock();
- mBinaryDictionary = newBinaryDictionary;
- mLocalDictionaryController.unlock();
+ mLocalDictionaryController.writeLock().lock();
+ try {
+ mBinaryDictionary = newBinaryDictionary;
+ } finally {
+ mLocalDictionaryController.writeLock().unlock();
+ }
oldBinaryDictionary.close();
} else {
mBinaryDictionary = newBinaryDictionary;
@@ -302,6 +296,12 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
/**
+ * Abstract method for checking if it is required to reload the dictionary before writing
+ * a binary dictionary.
+ */
+ abstract protected boolean needsToReloadBeforeWriting();
+
+ /**
* Generates and writes a new binary dictionary based on the contents of the fusion dictionary.
*/
private void generateBinaryDictionary() {
@@ -310,33 +310,11 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
+ mSharedDictionaryController.mLastUpdateRequestTime + " update="
+ mSharedDictionaryController.mLastUpdateTime);
}
-
- loadDictionaryAsync();
-
- final String tempFileName = mFilename + ".temp";
- final File file = new File(mContext.getFilesDir(), mFilename);
- final File tempFile = new File(mContext.getFilesDir(), tempFileName);
- FileOutputStream out = null;
- try {
- out = new FileOutputStream(tempFile);
- BinaryDictInputOutput.writeDictionaryBinary(out, mFusionDictionary, FORMAT_OPTIONS);
- out.flush();
- out.close();
- tempFile.renameTo(file);
- clearFusionDictionary();
- } catch (IOException e) {
- Log.e(TAG, "IO exception while writing file", e);
- } catch (UnsupportedFormatException e) {
- Log.e(TAG, "Unsupported format", e);
- } finally {
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- // ignore
- }
- }
+ if (needsToReloadBeforeWriting()) {
+ mDictionaryWriter.clear();
+ loadDictionaryAsync();
}
+ mDictionaryWriter.write(mFilename);
}
/**
@@ -389,7 +367,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
private final void syncReloadDictionaryInternal() {
// Ensure that only one thread attempts to read or write to the shared binary dictionary
// file at the same time.
- mSharedDictionaryController.lock();
+ mSharedDictionaryController.writeLock().lock();
try {
final long time = SystemClock.uptimeMillis();
final boolean dictionaryFileExists = dictionaryFileExists();
@@ -415,9 +393,15 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
// shared dictionary.
loadBinaryDictionary();
}
+ if (mBinaryDictionary != null && !mBinaryDictionary.isValidDictionary()) {
+ // Binary dictionary is not valid. Regenerate the dictionary file.
+ mSharedDictionaryController.mLastUpdateTime = time;
+ generateBinaryDictionary();
+ loadBinaryDictionary();
+ }
mLocalDictionaryController.mLastUpdateTime = time;
} finally {
- mSharedDictionaryController.unlock();
+ mSharedDictionaryController.writeLock().unlock();
}
}
@@ -442,7 +426,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
* dictionary is out of date. Can be shared across multiple dictionary instances that access the
* same filename.
*/
- private static class DictionaryController extends ReentrantLock {
+ private static class DictionaryController extends ReentrantReadWriteLock {
private volatile long mLastUpdateTime = 0;
private volatile long mLastUpdateRequestTime = 0;
diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
index a67c919b3..2666573bb 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java
@@ -728,172 +728,206 @@ public class ExpandableDictionary extends Dictionary {
* to their base characters. If c is in range, BASE_CHARS[c] == c
* if c is not a combined character, or the base character if it
* is combined.
+ *
+ * cf. native/jni/src/utils/char_utils.cpp
*/
private static final char BASE_CHARS[] = {
- 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
- 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
- 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
- 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
- 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
- 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
- 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
- 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
- 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
- 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
- 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
- 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
- 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
- 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
- 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
- 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
- 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
- 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
- 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
- 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
- 0x0020, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
- 0x0020, 0x00a9, 0x0061, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x0020,
- 0x00b0, 0x00b1, 0x0032, 0x0033, 0x0020, 0x03bc, 0x00b6, 0x00b7,
- 0x0020, 0x0031, 0x006f, 0x00bb, 0x0031, 0x0031, 0x0033, 0x00bf,
- 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x00c6, 0x0043,
- 0x0045, 0x0045, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049,
- 0x00d0, 0x004e, 0x004f, 0x004f, 0x004f, 0x004f, 0x004f, 0x00d7,
- 0x004f, 0x0055, 0x0055, 0x0055, 0x0055, 0x0059, 0x00de, 0x0073, // Manually changed d8 to 4f
- // Manually changed df to 73
- 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x00e6, 0x0063,
- 0x0065, 0x0065, 0x0065, 0x0065, 0x0069, 0x0069, 0x0069, 0x0069,
- 0x00f0, 0x006e, 0x006f, 0x006f, 0x006f, 0x006f, 0x006f, 0x00f7,
- 0x006f, 0x0075, 0x0075, 0x0075, 0x0075, 0x0079, 0x00fe, 0x0079, // Manually changed f8 to 6f
- 0x0041, 0x0061, 0x0041, 0x0061, 0x0041, 0x0061, 0x0043, 0x0063,
- 0x0043, 0x0063, 0x0043, 0x0063, 0x0043, 0x0063, 0x0044, 0x0064,
- 0x0110, 0x0111, 0x0045, 0x0065, 0x0045, 0x0065, 0x0045, 0x0065,
- 0x0045, 0x0065, 0x0045, 0x0065, 0x0047, 0x0067, 0x0047, 0x0067,
- 0x0047, 0x0067, 0x0047, 0x0067, 0x0048, 0x0068, 0x0126, 0x0127,
- 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069,
- 0x0049, 0x0131, 0x0049, 0x0069, 0x004a, 0x006a, 0x004b, 0x006b,
- 0x0138, 0x004c, 0x006c, 0x004c, 0x006c, 0x004c, 0x006c, 0x004c,
- 0x006c, 0x0141, 0x0142, 0x004e, 0x006e, 0x004e, 0x006e, 0x004e,
- 0x006e, 0x02bc, 0x014a, 0x014b, 0x004f, 0x006f, 0x004f, 0x006f,
- 0x004f, 0x006f, 0x0152, 0x0153, 0x0052, 0x0072, 0x0052, 0x0072,
- 0x0052, 0x0072, 0x0053, 0x0073, 0x0053, 0x0073, 0x0053, 0x0073,
- 0x0053, 0x0073, 0x0054, 0x0074, 0x0054, 0x0074, 0x0166, 0x0167,
- 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075,
- 0x0055, 0x0075, 0x0055, 0x0075, 0x0057, 0x0077, 0x0059, 0x0079,
- 0x0059, 0x005a, 0x007a, 0x005a, 0x007a, 0x005a, 0x007a, 0x0073,
- 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185, 0x0186, 0x0187,
- 0x0188, 0x0189, 0x018a, 0x018b, 0x018c, 0x018d, 0x018e, 0x018f,
- 0x0190, 0x0191, 0x0192, 0x0193, 0x0194, 0x0195, 0x0196, 0x0197,
- 0x0198, 0x0199, 0x019a, 0x019b, 0x019c, 0x019d, 0x019e, 0x019f,
- 0x004f, 0x006f, 0x01a2, 0x01a3, 0x01a4, 0x01a5, 0x01a6, 0x01a7,
- 0x01a8, 0x01a9, 0x01aa, 0x01ab, 0x01ac, 0x01ad, 0x01ae, 0x0055,
- 0x0075, 0x01b1, 0x01b2, 0x01b3, 0x01b4, 0x01b5, 0x01b6, 0x01b7,
- 0x01b8, 0x01b9, 0x01ba, 0x01bb, 0x01bc, 0x01bd, 0x01be, 0x01bf,
- 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x0044, 0x0044, 0x0064, 0x004c,
- 0x004c, 0x006c, 0x004e, 0x004e, 0x006e, 0x0041, 0x0061, 0x0049,
- 0x0069, 0x004f, 0x006f, 0x0055, 0x0075, 0x00dc, 0x00fc, 0x00dc,
- 0x00fc, 0x00dc, 0x00fc, 0x00dc, 0x00fc, 0x01dd, 0x00c4, 0x00e4,
- 0x0226, 0x0227, 0x00c6, 0x00e6, 0x01e4, 0x01e5, 0x0047, 0x0067,
- 0x004b, 0x006b, 0x004f, 0x006f, 0x01ea, 0x01eb, 0x01b7, 0x0292,
- 0x006a, 0x0044, 0x0044, 0x0064, 0x0047, 0x0067, 0x01f6, 0x01f7,
- 0x004e, 0x006e, 0x00c5, 0x00e5, 0x00c6, 0x00e6, 0x00d8, 0x00f8,
- 0x0041, 0x0061, 0x0041, 0x0061, 0x0045, 0x0065, 0x0045, 0x0065,
- 0x0049, 0x0069, 0x0049, 0x0069, 0x004f, 0x006f, 0x004f, 0x006f,
- 0x0052, 0x0072, 0x0052, 0x0072, 0x0055, 0x0075, 0x0055, 0x0075,
- 0x0053, 0x0073, 0x0054, 0x0074, 0x021c, 0x021d, 0x0048, 0x0068,
- 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0041, 0x0061,
- 0x0045, 0x0065, 0x00d6, 0x00f6, 0x00d5, 0x00f5, 0x004f, 0x006f,
- 0x022e, 0x022f, 0x0059, 0x0079, 0x0234, 0x0235, 0x0236, 0x0237,
- 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f,
- 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247,
- 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f,
- 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257,
- 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f,
- 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267,
- 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f,
- 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277,
- 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f,
- 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287,
- 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f,
- 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297,
- 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f,
- 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7,
- 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af,
- 0x0068, 0x0266, 0x006a, 0x0072, 0x0279, 0x027b, 0x0281, 0x0077,
- 0x0079, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf,
- 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7,
- 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf,
- 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7,
- 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x02de, 0x02df,
- 0x0263, 0x006c, 0x0073, 0x0078, 0x0295, 0x02e5, 0x02e6, 0x02e7,
- 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef,
- 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7,
- 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff,
- 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307,
- 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f,
- 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
- 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f,
- 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327,
- 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f,
- 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337,
- 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f,
- 0x0300, 0x0301, 0x0342, 0x0313, 0x0308, 0x0345, 0x0346, 0x0347,
- 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f,
- 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357,
- 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f,
- 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367,
- 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f,
- 0x0370, 0x0371, 0x0372, 0x0373, 0x02b9, 0x0375, 0x0376, 0x0377,
- 0x0378, 0x0379, 0x0020, 0x037b, 0x037c, 0x037d, 0x003b, 0x037f,
- 0x0380, 0x0381, 0x0382, 0x0383, 0x0020, 0x00a8, 0x0391, 0x00b7,
- 0x0395, 0x0397, 0x0399, 0x038b, 0x039f, 0x038d, 0x03a5, 0x03a9,
- 0x03ca, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
- 0x0398, 0x0399, 0x039a, 0x039b, 0x039c, 0x039d, 0x039e, 0x039f,
- 0x03a0, 0x03a1, 0x03a2, 0x03a3, 0x03a4, 0x03a5, 0x03a6, 0x03a7,
- 0x03a8, 0x03a9, 0x0399, 0x03a5, 0x03b1, 0x03b5, 0x03b7, 0x03b9,
- 0x03cb, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
- 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
- 0x03c0, 0x03c1, 0x03c2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
- 0x03c8, 0x03c9, 0x03b9, 0x03c5, 0x03bf, 0x03c5, 0x03c9, 0x03cf,
- 0x03b2, 0x03b8, 0x03a5, 0x03d2, 0x03d2, 0x03c6, 0x03c0, 0x03d7,
- 0x03d8, 0x03d9, 0x03da, 0x03db, 0x03dc, 0x03dd, 0x03de, 0x03df,
- 0x03e0, 0x03e1, 0x03e2, 0x03e3, 0x03e4, 0x03e5, 0x03e6, 0x03e7,
- 0x03e8, 0x03e9, 0x03ea, 0x03eb, 0x03ec, 0x03ed, 0x03ee, 0x03ef,
- 0x03ba, 0x03c1, 0x03c2, 0x03f3, 0x0398, 0x03b5, 0x03f6, 0x03f7,
- 0x03f8, 0x03a3, 0x03fa, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff,
- 0x0415, 0x0415, 0x0402, 0x0413, 0x0404, 0x0405, 0x0406, 0x0406,
- 0x0408, 0x0409, 0x040a, 0x040b, 0x041a, 0x0418, 0x0423, 0x040f,
- 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
- 0x0418, 0x0418, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f,
- 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
- 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f,
- 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
- 0x0438, 0x0438, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
- 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
- 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
- 0x0435, 0x0435, 0x0452, 0x0433, 0x0454, 0x0455, 0x0456, 0x0456,
- 0x0458, 0x0459, 0x045a, 0x045b, 0x043a, 0x0438, 0x0443, 0x045f,
- 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467,
- 0x0468, 0x0469, 0x046a, 0x046b, 0x046c, 0x046d, 0x046e, 0x046f,
- 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0474, 0x0475,
- 0x0478, 0x0479, 0x047a, 0x047b, 0x047c, 0x047d, 0x047e, 0x047f,
- 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,
- 0x0488, 0x0489, 0x048a, 0x048b, 0x048c, 0x048d, 0x048e, 0x048f,
- 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497,
- 0x0498, 0x0499, 0x049a, 0x049b, 0x049c, 0x049d, 0x049e, 0x049f,
- 0x04a0, 0x04a1, 0x04a2, 0x04a3, 0x04a4, 0x04a5, 0x04a6, 0x04a7,
- 0x04a8, 0x04a9, 0x04aa, 0x04ab, 0x04ac, 0x04ad, 0x04ae, 0x04af,
- 0x04b0, 0x04b1, 0x04b2, 0x04b3, 0x04b4, 0x04b5, 0x04b6, 0x04b7,
- 0x04b8, 0x04b9, 0x04ba, 0x04bb, 0x04bc, 0x04bd, 0x04be, 0x04bf,
- 0x04c0, 0x0416, 0x0436, 0x04c3, 0x04c4, 0x04c5, 0x04c6, 0x04c7,
- 0x04c8, 0x04c9, 0x04ca, 0x04cb, 0x04cc, 0x04cd, 0x04ce, 0x04cf,
- 0x0410, 0x0430, 0x0410, 0x0430, 0x04d4, 0x04d5, 0x0415, 0x0435,
- 0x04d8, 0x04d9, 0x04d8, 0x04d9, 0x0416, 0x0436, 0x0417, 0x0437,
- 0x04e0, 0x04e1, 0x0418, 0x0438, 0x0418, 0x0438, 0x041e, 0x043e,
- 0x04e8, 0x04e9, 0x04e8, 0x04e9, 0x042d, 0x044d, 0x0423, 0x0443,
- 0x0423, 0x0443, 0x0423, 0x0443, 0x0427, 0x0447, 0x04f6, 0x04f7,
- 0x042b, 0x044b, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff,
+ /* U+0000 */ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ /* U+0008 */ 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
+ /* U+0010 */ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ /* U+0018 */ 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
+ /* U+0020 */ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ /* U+0028 */ 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
+ /* U+0030 */ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ /* U+0038 */ 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
+ /* U+0040 */ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
+ /* U+0048 */ 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
+ /* U+0050 */ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
+ /* U+0058 */ 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F,
+ /* U+0060 */ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ /* U+0068 */ 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
+ /* U+0070 */ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ /* U+0078 */ 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
+ /* U+0080 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ /* U+0088 */ 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F,
+ /* U+0090 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ /* U+0098 */ 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F,
+ /* U+00A0 */ 0x0020, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7,
+ /* U+00A8 */ 0x0020, 0x00A9, 0x0061, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0020,
+ /* U+00B0 */ 0x00B0, 0x00B1, 0x0032, 0x0033, 0x0020, 0x03BC, 0x00B6, 0x00B7,
+ /* U+00B8 */ 0x0020, 0x0031, 0x006F, 0x00BB, 0x0031, 0x0031, 0x0033, 0x00BF,
+ /* U+00C0 */ 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x0041, 0x00C6, 0x0043,
+ /* U+00C8 */ 0x0045, 0x0045, 0x0045, 0x0045, 0x0049, 0x0049, 0x0049, 0x0049,
+ /* U+00D0 */ 0x00D0, 0x004E, 0x004F, 0x004F, 0x004F, 0x004F, 0x004F, 0x00D7,
+ /* U+00D8 */ 0x004F, 0x0055, 0x0055, 0x0055, 0x0055, 0x0059, 0x00DE, 0x0073,
+ // U+00D8: Manually changed from 00D8 to 004F
+ // TODO: Check if it's really acceptable to consider Ø a diacritical variant of O
+ // U+00DF: Manually changed from 00DF to 0073
+ /* U+00E0 */ 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x0061, 0x00E6, 0x0063,
+ /* U+00E8 */ 0x0065, 0x0065, 0x0065, 0x0065, 0x0069, 0x0069, 0x0069, 0x0069,
+ /* U+00F0 */ 0x00F0, 0x006E, 0x006F, 0x006F, 0x006F, 0x006F, 0x006F, 0x00F7,
+ /* U+00F8 */ 0x006F, 0x0075, 0x0075, 0x0075, 0x0075, 0x0079, 0x00FE, 0x0079,
+ // U+00F8: Manually changed from 00F8 to 006F
+ // TODO: Check if it's really acceptable to consider ø a diacritical variant of o
+ /* U+0100 */ 0x0041, 0x0061, 0x0041, 0x0061, 0x0041, 0x0061, 0x0043, 0x0063,
+ /* U+0108 */ 0x0043, 0x0063, 0x0043, 0x0063, 0x0043, 0x0063, 0x0044, 0x0064,
+ /* U+0110 */ 0x0110, 0x0111, 0x0045, 0x0065, 0x0045, 0x0065, 0x0045, 0x0065,
+ /* U+0118 */ 0x0045, 0x0065, 0x0045, 0x0065, 0x0047, 0x0067, 0x0047, 0x0067,
+ /* U+0120 */ 0x0047, 0x0067, 0x0047, 0x0067, 0x0048, 0x0068, 0x0126, 0x0127,
+ /* U+0128 */ 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069, 0x0049, 0x0069,
+ /* U+0130 */ 0x0049, 0x0131, 0x0049, 0x0069, 0x004A, 0x006A, 0x004B, 0x006B,
+ /* U+0138 */ 0x0138, 0x004C, 0x006C, 0x004C, 0x006C, 0x004C, 0x006C, 0x004C,
+ /* U+0140 */ 0x006C, 0x004C, 0x006C, 0x004E, 0x006E, 0x004E, 0x006E, 0x004E,
+ // U+0141: Manually changed from 0141 to 004C
+ // U+0142: Manually changed from 0142 to 006C
+ /* U+0148 */ 0x006E, 0x02BC, 0x014A, 0x014B, 0x004F, 0x006F, 0x004F, 0x006F,
+ /* U+0150 */ 0x004F, 0x006F, 0x0152, 0x0153, 0x0052, 0x0072, 0x0052, 0x0072,
+ /* U+0158 */ 0x0052, 0x0072, 0x0053, 0x0073, 0x0053, 0x0073, 0x0053, 0x0073,
+ /* U+0160 */ 0x0053, 0x0073, 0x0054, 0x0074, 0x0054, 0x0074, 0x0166, 0x0167,
+ /* U+0168 */ 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, 0x0055, 0x0075,
+ /* U+0170 */ 0x0055, 0x0075, 0x0055, 0x0075, 0x0057, 0x0077, 0x0059, 0x0079,
+ /* U+0178 */ 0x0059, 0x005A, 0x007A, 0x005A, 0x007A, 0x005A, 0x007A, 0x0073,
+ /* U+0180 */ 0x0180, 0x0181, 0x0182, 0x0183, 0x0184, 0x0185, 0x0186, 0x0187,
+ /* U+0188 */ 0x0188, 0x0189, 0x018A, 0x018B, 0x018C, 0x018D, 0x018E, 0x018F,
+ /* U+0190 */ 0x0190, 0x0191, 0x0192, 0x0193, 0x0194, 0x0195, 0x0196, 0x0197,
+ /* U+0198 */ 0x0198, 0x0199, 0x019A, 0x019B, 0x019C, 0x019D, 0x019E, 0x019F,
+ /* U+01A0 */ 0x004F, 0x006F, 0x01A2, 0x01A3, 0x01A4, 0x01A5, 0x01A6, 0x01A7,
+ /* U+01A8 */ 0x01A8, 0x01A9, 0x01AA, 0x01AB, 0x01AC, 0x01AD, 0x01AE, 0x0055,
+ /* U+01B0 */ 0x0075, 0x01B1, 0x01B2, 0x01B3, 0x01B4, 0x01B5, 0x01B6, 0x01B7,
+ /* U+01B8 */ 0x01B8, 0x01B9, 0x01BA, 0x01BB, 0x01BC, 0x01BD, 0x01BE, 0x01BF,
+ /* U+01C0 */ 0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x0044, 0x0044, 0x0064, 0x004C,
+ /* U+01C8 */ 0x004C, 0x006C, 0x004E, 0x004E, 0x006E, 0x0041, 0x0061, 0x0049,
+ /* U+01D0 */ 0x0069, 0x004F, 0x006F, 0x0055, 0x0075, 0x0055, 0x0075, 0x0055,
+ // U+01D5: Manually changed from 00DC to 0055
+ // U+01D6: Manually changed from 00FC to 0075
+ // U+01D7: Manually changed from 00DC to 0055
+ /* U+01D8 */ 0x0075, 0x0055, 0x0075, 0x0055, 0x0075, 0x01DD, 0x0041, 0x0061,
+ // U+01D8: Manually changed from 00FC to 0075
+ // U+01D9: Manually changed from 00DC to 0055
+ // U+01DA: Manually changed from 00FC to 0075
+ // U+01DB: Manually changed from 00DC to 0055
+ // U+01DC: Manually changed from 00FC to 0075
+ // U+01DE: Manually changed from 00C4 to 0041
+ // U+01DF: Manually changed from 00E4 to 0061
+ /* U+01E0 */ 0x0041, 0x0061, 0x00C6, 0x00E6, 0x01E4, 0x01E5, 0x0047, 0x0067,
+ // U+01E0: Manually changed from 0226 to 0041
+ // U+01E1: Manually changed from 0227 to 0061
+ /* U+01E8 */ 0x004B, 0x006B, 0x004F, 0x006F, 0x004F, 0x006F, 0x01B7, 0x0292,
+ // U+01EC: Manually changed from 01EA to 004F
+ // U+01ED: Manually changed from 01EB to 006F
+ /* U+01F0 */ 0x006A, 0x0044, 0x0044, 0x0064, 0x0047, 0x0067, 0x01F6, 0x01F7,
+ /* U+01F8 */ 0x004E, 0x006E, 0x0041, 0x0061, 0x00C6, 0x00E6, 0x004F, 0x006F,
+ // U+01FA: Manually changed from 00C5 to 0041
+ // U+01FB: Manually changed from 00E5 to 0061
+ // U+01FE: Manually changed from 00D8 to 004F
+ // TODO: Check if it's really acceptable to consider Ø a diacritical variant of O
+ // U+01FF: Manually changed from 00F8 to 006F
+ // TODO: Check if it's really acceptable to consider ø a diacritical variant of o
+ /* U+0200 */ 0x0041, 0x0061, 0x0041, 0x0061, 0x0045, 0x0065, 0x0045, 0x0065,
+ /* U+0208 */ 0x0049, 0x0069, 0x0049, 0x0069, 0x004F, 0x006F, 0x004F, 0x006F,
+ /* U+0210 */ 0x0052, 0x0072, 0x0052, 0x0072, 0x0055, 0x0075, 0x0055, 0x0075,
+ /* U+0218 */ 0x0053, 0x0073, 0x0054, 0x0074, 0x021C, 0x021D, 0x0048, 0x0068,
+ /* U+0220 */ 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0225, 0x0041, 0x0061,
+ /* U+0228 */ 0x0045, 0x0065, 0x004F, 0x006F, 0x004F, 0x006F, 0x004F, 0x006F,
+ // U+022A: Manually changed from 00D6 to 004F
+ // U+022B: Manually changed from 00F6 to 006F
+ // U+022C: Manually changed from 00D5 to 004F
+ // U+022D: Manually changed from 00F5 to 006F
+ /* U+0230 */ 0x004F, 0x006F, 0x0059, 0x0079, 0x0234, 0x0235, 0x0236, 0x0237,
+ // U+0230: Manually changed from 022E to 004F
+ // U+0231: Manually changed from 022F to 006F
+ /* U+0238 */ 0x0238, 0x0239, 0x023A, 0x023B, 0x023C, 0x023D, 0x023E, 0x023F,
+ /* U+0240 */ 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247,
+ /* U+0248 */ 0x0248, 0x0249, 0x024A, 0x024B, 0x024C, 0x024D, 0x024E, 0x024F,
+ /* U+0250 */ 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257,
+ /* U+0258 */ 0x0258, 0x0259, 0x025A, 0x025B, 0x025C, 0x025D, 0x025E, 0x025F,
+ /* U+0260 */ 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267,
+ /* U+0268 */ 0x0268, 0x0269, 0x026A, 0x026B, 0x026C, 0x026D, 0x026E, 0x026F,
+ /* U+0270 */ 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277,
+ /* U+0278 */ 0x0278, 0x0279, 0x027A, 0x027B, 0x027C, 0x027D, 0x027E, 0x027F,
+ /* U+0280 */ 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287,
+ /* U+0288 */ 0x0288, 0x0289, 0x028A, 0x028B, 0x028C, 0x028D, 0x028E, 0x028F,
+ /* U+0290 */ 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297,
+ /* U+0298 */ 0x0298, 0x0299, 0x029A, 0x029B, 0x029C, 0x029D, 0x029E, 0x029F,
+ /* U+02A0 */ 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x02A4, 0x02A5, 0x02A6, 0x02A7,
+ /* U+02A8 */ 0x02A8, 0x02A9, 0x02AA, 0x02AB, 0x02AC, 0x02AD, 0x02AE, 0x02AF,
+ /* U+02B0 */ 0x0068, 0x0266, 0x006A, 0x0072, 0x0279, 0x027B, 0x0281, 0x0077,
+ /* U+02B8 */ 0x0079, 0x02B9, 0x02BA, 0x02BB, 0x02BC, 0x02BD, 0x02BE, 0x02BF,
+ /* U+02C0 */ 0x02C0, 0x02C1, 0x02C2, 0x02C3, 0x02C4, 0x02C5, 0x02C6, 0x02C7,
+ /* U+02C8 */ 0x02C8, 0x02C9, 0x02CA, 0x02CB, 0x02CC, 0x02CD, 0x02CE, 0x02CF,
+ /* U+02D0 */ 0x02D0, 0x02D1, 0x02D2, 0x02D3, 0x02D4, 0x02D5, 0x02D6, 0x02D7,
+ /* U+02D8 */ 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x02DE, 0x02DF,
+ /* U+02E0 */ 0x0263, 0x006C, 0x0073, 0x0078, 0x0295, 0x02E5, 0x02E6, 0x02E7,
+ /* U+02E8 */ 0x02E8, 0x02E9, 0x02EA, 0x02EB, 0x02EC, 0x02ED, 0x02EE, 0x02EF,
+ /* U+02F0 */ 0x02F0, 0x02F1, 0x02F2, 0x02F3, 0x02F4, 0x02F5, 0x02F6, 0x02F7,
+ /* U+02F8 */ 0x02F8, 0x02F9, 0x02FA, 0x02FB, 0x02FC, 0x02FD, 0x02FE, 0x02FF,
+ /* U+0300 */ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307,
+ /* U+0308 */ 0x0308, 0x0309, 0x030A, 0x030B, 0x030C, 0x030D, 0x030E, 0x030F,
+ /* U+0310 */ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
+ /* U+0318 */ 0x0318, 0x0319, 0x031A, 0x031B, 0x031C, 0x031D, 0x031E, 0x031F,
+ /* U+0320 */ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327,
+ /* U+0328 */ 0x0328, 0x0329, 0x032A, 0x032B, 0x032C, 0x032D, 0x032E, 0x032F,
+ /* U+0330 */ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337,
+ /* U+0338 */ 0x0338, 0x0339, 0x033A, 0x033B, 0x033C, 0x033D, 0x033E, 0x033F,
+ /* U+0340 */ 0x0300, 0x0301, 0x0342, 0x0313, 0x0308, 0x0345, 0x0346, 0x0347,
+ /* U+0348 */ 0x0348, 0x0349, 0x034A, 0x034B, 0x034C, 0x034D, 0x034E, 0x034F,
+ /* U+0350 */ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357,
+ /* U+0358 */ 0x0358, 0x0359, 0x035A, 0x035B, 0x035C, 0x035D, 0x035E, 0x035F,
+ /* U+0360 */ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367,
+ /* U+0368 */ 0x0368, 0x0369, 0x036A, 0x036B, 0x036C, 0x036D, 0x036E, 0x036F,
+ /* U+0370 */ 0x0370, 0x0371, 0x0372, 0x0373, 0x02B9, 0x0375, 0x0376, 0x0377,
+ /* U+0378 */ 0x0378, 0x0379, 0x0020, 0x037B, 0x037C, 0x037D, 0x003B, 0x037F,
+ /* U+0380 */ 0x0380, 0x0381, 0x0382, 0x0383, 0x0020, 0x00A8, 0x0391, 0x00B7,
+ /* U+0388 */ 0x0395, 0x0397, 0x0399, 0x038B, 0x039F, 0x038D, 0x03A5, 0x03A9,
+ /* U+0390 */ 0x03CA, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
+ /* U+0398 */ 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
+ /* U+03A0 */ 0x03A0, 0x03A1, 0x03A2, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
+ /* U+03A8 */ 0x03A8, 0x03A9, 0x0399, 0x03A5, 0x03B1, 0x03B5, 0x03B7, 0x03B9,
+ /* U+03B0 */ 0x03CB, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
+ /* U+03B8 */ 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
+ /* U+03C0 */ 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
+ /* U+03C8 */ 0x03C8, 0x03C9, 0x03B9, 0x03C5, 0x03BF, 0x03C5, 0x03C9, 0x03CF,
+ /* U+03D0 */ 0x03B2, 0x03B8, 0x03A5, 0x03D2, 0x03D2, 0x03C6, 0x03C0, 0x03D7,
+ /* U+03D8 */ 0x03D8, 0x03D9, 0x03DA, 0x03DB, 0x03DC, 0x03DD, 0x03DE, 0x03DF,
+ /* U+03E0 */ 0x03E0, 0x03E1, 0x03E2, 0x03E3, 0x03E4, 0x03E5, 0x03E6, 0x03E7,
+ /* U+03E8 */ 0x03E8, 0x03E9, 0x03EA, 0x03EB, 0x03EC, 0x03ED, 0x03EE, 0x03EF,
+ /* U+03F0 */ 0x03BA, 0x03C1, 0x03C2, 0x03F3, 0x0398, 0x03B5, 0x03F6, 0x03F7,
+ /* U+03F8 */ 0x03F8, 0x03A3, 0x03FA, 0x03FB, 0x03FC, 0x03FD, 0x03FE, 0x03FF,
+ /* U+0400 */ 0x0415, 0x0415, 0x0402, 0x0413, 0x0404, 0x0405, 0x0406, 0x0406,
+ /* U+0408 */ 0x0408, 0x0409, 0x040A, 0x040B, 0x041A, 0x0418, 0x0423, 0x040F,
+ /* U+0410 */ 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
+ /* U+0418 */ 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
+ // U+0419: Manually changed from 0418 to 0419
+ /* U+0420 */ 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
+ /* U+0428 */ 0x0428, 0x0429, 0x042C, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
+ // U+042A: Manually changed from 042A to 042C
+ /* U+0430 */ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ /* U+0438 */ 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
+ // U+0439: Manually changed from 0438 to 0439
+ /* U+0440 */ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ /* U+0448 */ 0x0448, 0x0449, 0x044C, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
+ // U+044A: Manually changed from 044A to 044C
+ /* U+0450 */ 0x0435, 0x0435, 0x0452, 0x0433, 0x0454, 0x0455, 0x0456, 0x0456,
+ /* U+0458 */ 0x0458, 0x0459, 0x045A, 0x045B, 0x043A, 0x0438, 0x0443, 0x045F,
+ /* U+0460 */ 0x0460, 0x0461, 0x0462, 0x0463, 0x0464, 0x0465, 0x0466, 0x0467,
+ /* U+0468 */ 0x0468, 0x0469, 0x046A, 0x046B, 0x046C, 0x046D, 0x046E, 0x046F,
+ /* U+0470 */ 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, 0x0475, 0x0474, 0x0475,
+ /* U+0478 */ 0x0478, 0x0479, 0x047A, 0x047B, 0x047C, 0x047D, 0x047E, 0x047F,
+ /* U+0480 */ 0x0480, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,
+ /* U+0488 */ 0x0488, 0x0489, 0x048A, 0x048B, 0x048C, 0x048D, 0x048E, 0x048F,
+ /* U+0490 */ 0x0490, 0x0491, 0x0492, 0x0493, 0x0494, 0x0495, 0x0496, 0x0497,
+ /* U+0498 */ 0x0498, 0x0499, 0x049A, 0x049B, 0x049C, 0x049D, 0x049E, 0x049F,
+ /* U+04A0 */ 0x04A0, 0x04A1, 0x04A2, 0x04A3, 0x04A4, 0x04A5, 0x04A6, 0x04A7,
+ /* U+04A8 */ 0x04A8, 0x04A9, 0x04AA, 0x04AB, 0x04AC, 0x04AD, 0x04AE, 0x04AF,
+ /* U+04B0 */ 0x04B0, 0x04B1, 0x04B2, 0x04B3, 0x04B4, 0x04B5, 0x04B6, 0x04B7,
+ /* U+04B8 */ 0x04B8, 0x04B9, 0x04BA, 0x04BB, 0x04BC, 0x04BD, 0x04BE, 0x04BF,
+ /* U+04C0 */ 0x04C0, 0x0416, 0x0436, 0x04C3, 0x04C4, 0x04C5, 0x04C6, 0x04C7,
+ /* U+04C8 */ 0x04C8, 0x04C9, 0x04CA, 0x04CB, 0x04CC, 0x04CD, 0x04CE, 0x04CF,
+ /* U+04D0 */ 0x0410, 0x0430, 0x0410, 0x0430, 0x04D4, 0x04D5, 0x0415, 0x0435,
+ /* U+04D8 */ 0x04D8, 0x04D9, 0x04D8, 0x04D9, 0x0416, 0x0436, 0x0417, 0x0437,
+ /* U+04E0 */ 0x04E0, 0x04E1, 0x0418, 0x0438, 0x0418, 0x0438, 0x041E, 0x043E,
+ /* U+04E8 */ 0x04E8, 0x04E9, 0x04E8, 0x04E9, 0x042D, 0x044D, 0x0423, 0x0443,
+ /* U+04F0 */ 0x0423, 0x0443, 0x0423, 0x0443, 0x0427, 0x0447, 0x04F6, 0x04F7,
+ /* U+04F8 */ 0x042B, 0x044B, 0x04FA, 0x04FB, 0x04FC, 0x04FD, 0x04FE, 0x04FF,
};
-
- // generated with:
- // cat UnicodeData.txt | perl -e 'while (<>) { @foo = split(/;/); $foo[5] =~ s/<.*> //; $base[hex($foo[0])] = hex($foo[5]);} for ($i = 0; $i < 0x500; $i += 8) { for ($j = $i; $j < $i + 8; $j++) { printf("0x%04x, ", $base[$j] ? $base[$j] : $j)}; print "\n"; }'
-
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 0560cf528..8f5e57182 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -73,22 +73,22 @@ import com.android.inputmethod.keyboard.KeyboardActionListener;
import com.android.inputmethod.keyboard.KeyboardId;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.MainKeyboardView;
-import com.android.inputmethod.latin.RichInputConnection.Range;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.suggestions.SuggestionStripView;
+import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.CapsModeUtils;
import com.android.inputmethod.latin.utils.CollectionUtils;
import com.android.inputmethod.latin.utils.CompletionInfoUtils;
import com.android.inputmethod.latin.utils.InputTypeUtils;
import com.android.inputmethod.latin.utils.IntentUtils;
import com.android.inputmethod.latin.utils.JniUtils;
+import com.android.inputmethod.latin.utils.LatinImeLoggerUtils;
import com.android.inputmethod.latin.utils.PositionalInfoForUserDictPendingAddition;
import com.android.inputmethod.latin.utils.RecapitalizeStatus;
import com.android.inputmethod.latin.utils.StaticInnerHandlerWrapper;
import com.android.inputmethod.latin.utils.TargetPackageInfoGetterTask;
-import com.android.inputmethod.latin.utils.Utils;
-import com.android.inputmethod.latin.utils.Utils.Stats;
+import com.android.inputmethod.latin.utils.TextRange;
import com.android.inputmethod.research.ResearchLogger;
import java.io.FileDescriptor;
@@ -961,7 +961,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// TODO: is it still necessary to test for composingSpan related stuff?
final boolean selectionChangedOrSafeToReset = selectionChanged
|| (!mWordComposer.isComposingWord()) || noComposingSpan;
- if (selectionChangedOrSafeToReset) {
+ final boolean hasOrHadSelection = (oldSelStart != oldSelEnd
+ || newSelStart != newSelEnd);
+ final int moveAmount = newSelStart - oldSelStart;
+ if (selectionChangedOrSafeToReset && (hasOrHadSelection
+ || !mWordComposer.moveCursorByAndReturnIfInsideComposingWord(moveAmount))) {
// If we are composing a word and moving the cursor, we would want to set a
// suggestion span for recorrection to work correctly. Unfortunately, that
// would involve the keyboard committing some new text, which would move the
@@ -1356,14 +1360,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
showSubtypeSelectorAndSettings();
}
- // Virtual codes representing custom requests. These are used in onCustomRequest() below.
- public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1;
-
@Override
public boolean onCustomRequest(final int requestCode) {
if (isShowingOptionDialog()) return false;
switch (requestCode) {
- case CODE_SHOW_INPUT_METHOD_PICKER:
+ case Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER:
if (mRichImm.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) {
mRichImm.getInputMethodManager().showInputMethodPicker();
return true;
@@ -1550,7 +1551,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (SPACE_STATE_PHANTOM == spaceState) {
if (mSettings.isInternal()) {
if (mWordComposer.isComposingWord() && mWordComposer.isBatchMode()) {
- Stats.onAutoCorrection(
+ LatinImeLoggerUtils.onAutoCorrection(
"", mWordComposer.getTypedWord(), " ", mWordComposer);
}
}
@@ -1611,7 +1612,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (mWordComposer.isComposingWord()) {
if (mSettings.isInternal()) {
if (mWordComposer.isBatchMode()) {
- Stats.onAutoCorrection("", mWordComposer.getTypedWord(), " ", mWordComposer);
+ LatinImeLoggerUtils.onAutoCorrection(
+ "", mWordComposer.getTypedWord(), " ", mWordComposer);
}
}
final int wordComposerSize = mWordComposer.size();
@@ -1859,7 +1861,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} else {
if (mLastComposedWord.canRevertCommit()) {
if (mSettings.isInternal()) {
- Stats.onAutoCorrectionCancellation();
+ LatinImeLoggerUtils.onAutoCorrectionCancellation();
}
revertCommit();
return;
@@ -2030,7 +2032,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
mHandler.postUpdateSuggestionStrip();
if (mSettings.isInternal()) {
- Utils.Stats.onNonSeparator((char)primaryCode, x, y);
+ LatinImeLoggerUtils.onNonSeparator((char)primaryCode, x, y);
}
}
@@ -2135,7 +2137,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
setPunctuationSuggestions();
}
if (mSettings.isInternal()) {
- Utils.Stats.onSeparator((char)primaryCode, x, y);
+ LatinImeLoggerUtils.onSeparator((char)primaryCode, x, y);
}
mKeyboardSwitcher.updateShiftState();
@@ -2324,7 +2326,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
+ "is empty? Impossible! I must commit suicide.");
}
if (mSettings.isInternal()) {
- Stats.onAutoCorrection(typedWord, autoCorrection, separatorString, mWordComposer);
+ LatinImeLoggerUtils.onAutoCorrection(
+ typedWord, autoCorrection, separatorString, mWordComposer);
}
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
final SuggestedWords suggestedWords = mSuggestedWords;
@@ -2428,7 +2431,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
&& !AutoCorrection.isValidWord(mSuggest, suggestion, true);
if (mSettings.isInternal()) {
- Stats.onSeparator((char)Constants.CODE_SPACE,
+ LatinImeLoggerUtils.onSeparator((char)Constants.CODE_SPACE,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
}
if (showingAddToDictionaryHint && mIsUserDictionaryAvailable) {
@@ -2514,7 +2517,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// If we don't know the cursor location, return.
if (mLastSelectionStart < 0) return;
if (!mConnection.isCursorTouchingWord(mSettings.getCurrent())) return;
- final Range range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(),
+ final TextRange range = mConnection.getWordRangeAtCursor(mSettings.getWordSeparators(),
0 /* additionalPrecedingWordsCount */);
if (null == range) return; // Happens if we don't have an input connection at all
// If for some strange reason (editor bug or so) we measure the text before the cursor as
@@ -2535,6 +2538,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
mWordComposer.setComposingWord(typedWord, mKeyboardSwitcher.getKeyboard());
+ // TODO: this is in chars but the callee expects code points!
mWordComposer.setCursorPositionWithinWord(numberOfCharsInWordBeforeCursor);
mConnection.setComposingRegion(
mLastSelectionStart - numberOfCharsInWordBeforeCursor,
@@ -2631,7 +2635,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
mConnection.commitText(originallyTypedWord + mLastComposedWord.mSeparatorString, 1);
if (mSettings.isInternal()) {
- Stats.onSeparator(mLastComposedWord.mSeparatorString,
+ LatinImeLoggerUtils.onSeparator(mLastComposedWord.mSeparatorString,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
}
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
@@ -2673,15 +2677,22 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
}
- // Callback called by PointerTracker through the KeyboardActionListener. This is called when a
- // key is depressed; release matching call is onReleaseKey below.
+ // Callback of the {@link KeyboardActionListener}. This is called when a key is depressed;
+ // release matching call is {@link #onReleaseKey(int,boolean)} below.
@Override
public void onPressKey(final int primaryCode, final boolean isSinglePointer) {
mKeyboardSwitcher.onPressKey(primaryCode, isSinglePointer);
+ final MainKeyboardView mKeyboardView = mKeyboardSwitcher.getMainKeyboardView();
+ final boolean noFeedback = (mKeyboardView != null && mKeyboardView.isInSlidingKeyInput())
+ || (primaryCode == Constants.CODE_DELETE && !mConnection.canDeleteCharacters());
+ if (!noFeedback) {
+ AudioAndHapticFeedbackManager.getInstance().hapticAndAudioFeedback(
+ primaryCode, mKeyboardView);
+ }
}
- // Callback by PointerTracker through the KeyboardActionListener. This is called when a key
- // is released; press matching call is onPressKey above.
+ // Callback of the {@link KeyboardActionListener}. This is called when a key is released;
+ // press matching call is {@link #onPressKey(int,boolean)} above.
@Override
public void onReleaseKey(final int primaryCode, final boolean withSliding) {
mKeyboardSwitcher.onReleaseKey(primaryCode, withSliding);
@@ -2778,7 +2789,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final CharSequence[] items = new CharSequence[] {
// TODO: Should use new string "Select active input modes".
getString(R.string.language_selection_title),
- getString(Utils.getAcitivityTitleResId(this, SettingsActivity.class)),
+ getString(ApplicationUtils.getAcitivityTitleResId(this, SettingsActivity.class)),
};
final DialogInterface.OnClickListener listener = new DialogInterface.OnClickListener() {
@Override
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 6b22cb12e..461de53ad 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -17,9 +17,7 @@
package com.android.inputmethod.latin;
import android.inputmethodservice.InputMethodService;
-import android.text.Spanned;
import android.text.TextUtils;
-import android.text.style.SuggestionSpan;
import android.util.Log;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
@@ -32,9 +30,9 @@ import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.utils.CapsModeUtils;
import com.android.inputmethod.latin.utils.DebugLogUtils;
import com.android.inputmethod.latin.utils.StringUtils;
+import com.android.inputmethod.latin.utils.TextRange;
import com.android.inputmethod.research.ResearchLogger;
-import java.util.Arrays;
import java.util.Locale;
import java.util.regex.Pattern;
@@ -193,6 +191,10 @@ public final class RichInputConnection {
return mIC.getSelectedText(flags);
}
+ public boolean canDeleteCharacters() {
+ return mCurrentCursorPosition > 0;
+ }
+
/**
* Gets the caps modes we should be in after this specific string.
*
@@ -441,100 +443,6 @@ public final class RichInputConnection {
return getNthPreviousWord(prev, sentenceSeperators, n);
}
- /**
- * Represents a range of text, relative to the current cursor position.
- */
- public static final class Range {
- private final CharSequence mTextAtCursor;
- private final int mWordAtCursorStartIndex;
- private final int mWordAtCursorEndIndex;
- private final int mCursorIndex;
-
- public final CharSequence mWord;
-
- public int getNumberOfCharsInWordBeforeCursor() {
- return mCursorIndex - mWordAtCursorStartIndex;
- }
-
- public int getNumberOfCharsInWordAfterCursor() {
- return mWordAtCursorEndIndex - mCursorIndex;
- }
-
- /**
- * Gets the suggestion spans that are put squarely on the word, with the exact start
- * and end of the span matching the boundaries of the word.
- * @return the list of spans.
- */
- public SuggestionSpan[] getSuggestionSpansAtWord() {
- if (!(mTextAtCursor instanceof Spanned && mWord instanceof Spanned)) {
- return new SuggestionSpan[0];
- }
- final Spanned text = (Spanned)mTextAtCursor;
- // Note: it's fine to pass indices negative or greater than the length of the string
- // to the #getSpans() method. The reason we need to get from -1 to +1 is that, the
- // spans were cut at the cursor position, and #getSpans(start, end) does not return
- // spans that end at `start' or begin at `end'. Consider the following case:
- // this| is (The | symbolizes the cursor position
- // ---- ---
- // In this case, the cursor is in position 4, so the 0~7 span has been split into
- // a 0~4 part and a 4~7 part.
- // If we called #getSpans(0, 4) in this case, we would only get the part from 0 to 4
- // of the span, and not the part from 4 to 7, so we would not realize the span actually
- // extends from 0 to 7. But if we call #getSpans(-1, 5) we'll get both the 0~4 and
- // the 4~7 spans and we can merge them accordingly.
- // Any span starting more than 1 char away from the word boundaries in any direction
- // does not touch the word, so we don't need to consider it. That's why requesting
- // -1 ~ +1 is enough.
- // Of course this is only relevant if the cursor is at one end of the word. If it's
- // in the middle, the -1 and +1 are not necessary, but they are harmless.
- final SuggestionSpan[] spans = text.getSpans(mWordAtCursorStartIndex - 1,
- mWordAtCursorEndIndex + 1, SuggestionSpan.class);
- int readIndex = 0;
- int writeIndex = 0;
- for (; readIndex < spans.length; ++readIndex) {
- final SuggestionSpan span = spans[readIndex];
- // The span may be null, as we null them when we find duplicates. Cf a few lines
- // down.
- if (null == span) continue;
- // Tentative span start and end. This may be modified later if we realize the
- // same span is also applied to other parts of the string.
- int spanStart = text.getSpanStart(span);
- int spanEnd = text.getSpanEnd(span);
- for (int i = readIndex + 1; i < spans.length; ++i) {
- if (span.equals(spans[i])) {
- // We found the same span somewhere else. Read the new extent of this
- // span, and adjust our values accordingly.
- spanStart = Math.min(spanStart, text.getSpanStart(spans[i]));
- spanEnd = Math.max(spanEnd, text.getSpanEnd(spans[i]));
- // ...and mark the span as processed.
- spans[i] = null;
- }
- }
- if (spanStart == mWordAtCursorStartIndex && spanEnd == mWordAtCursorEndIndex) {
- // If the span does not start and stop here, we ignore it. It probably extends
- // past the start or end of the word, as happens in missing space correction
- // or EasyEditSpans put by voice input.
- spans[writeIndex++] = spans[readIndex];
- }
- }
- return writeIndex == readIndex ? spans : Arrays.copyOfRange(spans, 0, writeIndex);
- }
-
- public Range(final CharSequence textAtCursor, final int wordAtCursorStartIndex,
- final int wordAtCursorEndIndex, final int cursorIndex) {
- if (wordAtCursorStartIndex < 0 || cursorIndex < wordAtCursorStartIndex
- || cursorIndex > wordAtCursorEndIndex
- || wordAtCursorEndIndex > textAtCursor.length()) {
- throw new IndexOutOfBoundsException();
- }
- mTextAtCursor = textAtCursor;
- mWordAtCursorStartIndex = wordAtCursorStartIndex;
- mWordAtCursorEndIndex = wordAtCursorEndIndex;
- mCursorIndex = cursorIndex;
- mWord = mTextAtCursor.subSequence(mWordAtCursorStartIndex, mWordAtCursorEndIndex);
- }
- }
-
private static boolean isSeparator(int code, String sep) {
return sep.indexOf(code) != -1;
}
@@ -581,7 +489,7 @@ public final class RichInputConnection {
*/
public CharSequence getWordAtCursor(String separators) {
// getWordRangeAtCursor returns null if the connection is null
- Range r = getWordRangeAtCursor(separators, 0);
+ TextRange r = getWordRangeAtCursor(separators, 0);
return (r == null) ? null : r.mWord;
}
@@ -593,7 +501,8 @@ public final class RichInputConnection {
* be included in the returned range
* @return a range containing the text surrounding the cursor
*/
- public Range getWordRangeAtCursor(final String sep, final int additionalPrecedingWordsCount) {
+ public TextRange getWordRangeAtCursor(final String sep,
+ final int additionalPrecedingWordsCount) {
mIC = mParent.getCurrentInputConnection();
if (mIC == null || sep == null) {
return null;
@@ -643,7 +552,7 @@ public final class RichInputConnection {
}
}
- return new Range(TextUtils.concat(before, after), startIndexInBefore,
+ return new TextRange(TextUtils.concat(before, after), startIndexInBefore,
before.length() + endIndexInAfter, before.length());
}
diff --git a/java/src/com/android/inputmethod/latin/SettingsFragment.java b/java/src/com/android/inputmethod/latin/SettingsFragment.java
index f52e56441..8c41cf8b9 100644
--- a/java/src/com/android/inputmethod/latin/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/SettingsFragment.java
@@ -42,8 +42,8 @@ import com.android.inputmethod.latin.setup.LauncherIconVisibilityManager;
import com.android.inputmethod.latin.userdictionary.UserDictionaryList;
import com.android.inputmethod.latin.userdictionary.UserDictionarySettings;
import com.android.inputmethod.latin.utils.AdditionalFeaturesSettingUtils;
+import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.FeedbackUtils;
-import com.android.inputmethod.latin.utils.Utils;
import com.android.inputmethod.research.ResearchLogger;
import com.android.inputmethodcommon.InputMethodSettingsFragment;
@@ -90,7 +90,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
preferenceScreen.setTitle(
- Utils.getAcitivityTitleResId(getActivity(), SettingsActivity.class));
+ ApplicationUtils.getAcitivityTitleResId(getActivity(), SettingsActivity.class));
}
final Resources res = getResources();
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 5b47dda0d..22beaefee 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -75,6 +75,21 @@ public final class SuggestedWords {
return mSuggestedWordInfoList.get(index);
}
+ public String getDebugString(final int pos) {
+ if (!LatinImeLogger.sDBG) {
+ return null;
+ }
+ final SuggestedWordInfo wordInfo = getInfo(pos);
+ if (wordInfo == null) {
+ return null;
+ }
+ final String debugString = wordInfo.getDebugString();
+ if (TextUtils.isEmpty(debugString)) {
+ return null;
+ }
+ return debugString;
+ }
+
public boolean willAutoCorrect() {
return mWillAutoCorrect;
}
diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
index ba84c1ad3..ab8f34893 100644
--- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java
@@ -240,7 +240,6 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
private void addWords(final Cursor cursor) {
final boolean hasShortcutColumn = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
- clearFusionDictionary();
if (cursor == null) return;
if (cursor.moveToFirst()) {
final int indexWord = cursor.getColumnIndex(Words.WORD);
@@ -267,4 +266,9 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary {
protected boolean hasContentChanged() {
return true;
}
+
+ @Override
+ protected boolean needsToReloadBeforeWriting() {
+ return true;
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
index ca2d8840b..8c668b810 100644
--- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java
@@ -320,7 +320,11 @@ public final class UserHistoryDictionary extends ExpandableDictionary {
mUserHistoryDictionary.mBigramListLock.unlock();
}
} else if (mUserHistoryDictionary.mBigramListLock.tryLock()) {
- doWriteTaskLocked();
+ try {
+ doWriteTaskLocked();
+ } finally {
+ mUserHistoryDictionary.mBigramListLock.unlock();
+ }
}
return null;
}
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index e078f03f4..2babe8b0c 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -192,6 +192,40 @@ public final class WordComposer {
return mCursorPositionWithinWord != mCodePointSize;
}
+ /**
+ * When the cursor is moved by the user, we need to update its position.
+ * If it falls inside the currently composing word, we don't reset the composition, and
+ * only update the cursor position.
+ *
+ * @param expectedMoveAmount How many java chars to move the cursor. Negative values move
+ * the cursor backward, positive values move the cursor forward.
+ * @return true if the cursor is still inside the composing word, false otherwise.
+ */
+ public boolean moveCursorByAndReturnIfInsideComposingWord(final int expectedMoveAmount) {
+ int actualMoveAmountWithinWord = 0;
+ int cursorPos = mCursorPositionWithinWord;
+ if (expectedMoveAmount >= 0) {
+ // Moving the cursor forward for the expected amount or until the end of the word has
+ // been reached, whichever comes first.
+ while (actualMoveAmountWithinWord < expectedMoveAmount && cursorPos < mCodePointSize) {
+ actualMoveAmountWithinWord += Character.charCount(mPrimaryKeyCodes[cursorPos]);
+ ++cursorPos;
+ }
+ } else {
+ // Moving the cursor backward for the expected amount or until the start of the word
+ // has been reached, whichever comes first.
+ while (actualMoveAmountWithinWord > expectedMoveAmount && cursorPos > 0) {
+ --cursorPos;
+ actualMoveAmountWithinWord -= Character.charCount(mPrimaryKeyCodes[cursorPos]);
+ }
+ }
+ // If the actual and expected amounts differ, we crossed the start or the end of the word
+ // so the result would not be inside the composing word.
+ if (actualMoveAmountWithinWord != expectedMoveAmount) return false;
+ mCursorPositionWithinWord = cursorPos;
+ return true;
+ }
+
public void setBatchInputPointers(final InputPointers batchPointers) {
mInputPointers.set(batchPointers);
mIsBatchMode = true;
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java
index da5812603..999ca775b 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/SpellCheckerSettingsFragment.java
@@ -21,7 +21,7 @@ import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
import com.android.inputmethod.latin.R;
-import com.android.inputmethod.latin.utils.Utils;
+import com.android.inputmethod.latin.utils.ApplicationUtils;
/**
* Preference screen.
@@ -39,7 +39,7 @@ public final class SpellCheckerSettingsFragment extends PreferenceFragment {
addPreferencesFromResource(R.xml.spell_checker_settings);
final PreferenceScreen preferenceScreen = getPreferenceScreen();
if (preferenceScreen != null) {
- preferenceScreen.setTitle(Utils.getAcitivityTitleResId(
+ preferenceScreen.setTitle(ApplicationUtils.getAcitivityTitleResId(
getActivity(), SpellCheckerSettingsActivity.class));
}
}
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index 2218b3bc6..e97069dff 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -24,14 +24,13 @@ import android.graphics.drawable.Drawable;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
import com.android.inputmethod.keyboard.KeyboardActionListener;
-import com.android.inputmethod.keyboard.TypefaceUtils;
import com.android.inputmethod.keyboard.internal.KeyboardBuilder;
import com.android.inputmethod.keyboard.internal.KeyboardIconsSet;
import com.android.inputmethod.keyboard.internal.KeyboardParams;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.utils.Utils;
+import com.android.inputmethod.latin.utils.TypefaceUtils;
public final class MoreSuggestions extends Keyboard {
public static final int SUGGESTION_CODE_BASE = 1024;
@@ -207,7 +206,7 @@ public final class MoreSuggestions extends Keyboard {
final int y = params.getY(index);
final int width = params.getWidth(index);
final String word = mSuggestedWords.getWord(index);
- final String info = Utils.getDebugInfo(mSuggestedWords, index);
+ final String info = mSuggestedWords.getDebugString(index);
final int indexInMoreSuggestions = index + SUGGESTION_CODE_BASE;
final Key key = new Key(
params, word, info, KeyboardIconsSet.ICON_UNDEFINED, indexInMoreSuggestions,
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index 9565f63f7..ce340b666 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -45,13 +45,12 @@ import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
-import com.android.inputmethod.keyboard.ViewLayoutUtils;
import com.android.inputmethod.latin.AutoCorrection;
import com.android.inputmethod.latin.LatinImeLogger;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.utils.ResourceUtils;
-import com.android.inputmethod.latin.utils.Utils;
+import com.android.inputmethod.latin.utils.ViewLayoutUtils;
import java.util.ArrayList;
@@ -446,7 +445,7 @@ final class SuggestionStripLayoutHelper {
wordView.setTextColor(getSuggestionTextColor(positionInStrip, suggestedWords));
if (SuggestionStripView.DBG) {
mDebugInfoViews.get(positionInStrip).setText(
- Utils.getDebugInfo(suggestedWords, indexInSuggestedWords));
+ suggestedWords.getDebugString(indexInSuggestedWords));
}
}
}
diff --git a/java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java b/java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java
new file mode 100644
index 000000000..08a2a8c5a
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/ApplicationUtils.java
@@ -0,0 +1,65 @@
+/*
+ * 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.utils;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.Log;
+
+public final class ApplicationUtils {
+ private static final String TAG = ApplicationUtils.class.getSimpleName();
+
+ private ApplicationUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ public static int getAcitivityTitleResId(final Context context,
+ final Class<? extends Activity> cls) {
+ final ComponentName cn = new ComponentName(context, cls);
+ try {
+ final ActivityInfo ai = context.getPackageManager().getActivityInfo(cn, 0);
+ if (ai != null) {
+ return ai.labelRes;
+ }
+ } catch (final NameNotFoundException e) {
+ Log.e(TAG, "Failed to get settings activity title res id.", e);
+ }
+ return 0;
+ }
+
+ /**
+ * A utility method to get the application's PackageInfo.versionName
+ * @return the application's PackageInfo.versionName
+ */
+ public static String getVersionName(final Context context) {
+ try {
+ if (context == null) {
+ return "";
+ }
+ final String packageName = context.getPackageName();
+ final PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
+ return info.versionName;
+ } catch (final NameNotFoundException e) {
+ Log.e(TAG, "Could not find version info.", e);
+ }
+ return "";
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
index b3d37d78c..34eccd65b 100644
--- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -20,7 +20,6 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
-import android.text.format.DateUtils;
import android.util.Log;
import com.android.inputmethod.latin.AssetFileAddress;
@@ -35,6 +34,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;
+import java.util.concurrent.TimeUnit;
/**
* This class encapsulates the logic for the Latin-IME side of dictionary information management.
@@ -74,8 +74,8 @@ public class DictionaryInfoUtils {
values.put(LOCALE_COLUMN, mLocale.toString());
values.put(DESCRIPTION_COLUMN, mDescription);
values.put(LOCAL_FILENAME_COLUMN, mFileAddress.mFilename);
- values.put(DATE_COLUMN,
- new File(mFileAddress.mFilename).lastModified() / DateUtils.SECOND_IN_MILLIS);
+ values.put(DATE_COLUMN, TimeUnit.MILLISECONDS.toSeconds(
+ new File(mFileAddress.mFilename).lastModified()));
values.put(FILESIZE_COLUMN, mFileAddress.mLength);
values.put(VERSION_COLUMN, mVersion);
return values;
diff --git a/java/src/com/android/inputmethod/latin/utils/LatinImeLoggerUtils.java b/java/src/com/android/inputmethod/latin/utils/LatinImeLoggerUtils.java
new file mode 100644
index 000000000..e958a7e71
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/LatinImeLoggerUtils.java
@@ -0,0 +1,77 @@
+/*
+ * 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.utils;
+
+import android.text.TextUtils;
+
+import com.android.inputmethod.latin.Constants;
+import com.android.inputmethod.latin.LatinImeLogger;
+import com.android.inputmethod.latin.WordComposer;
+
+public final class LatinImeLoggerUtils {
+ private LatinImeLoggerUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ public static void onNonSeparator(final char code, final int x, final int y) {
+ UserLogRingCharBuffer.getInstance().push(code, x, y);
+ LatinImeLogger.logOnInputChar();
+ }
+
+ public static void onSeparator(final int code, final int x, final int y) {
+ // Helper method to log a single code point separator
+ // TODO: cache this mapping of a code point to a string in a sparse array in StringUtils
+ onSeparator(new String(new int[]{code}, 0, 1), x, y);
+ }
+
+ public static void onSeparator(final String separator, final int x, final int y) {
+ final int length = separator.length();
+ for (int i = 0; i < length; i = Character.offsetByCodePoints(separator, i, 1)) {
+ int codePoint = Character.codePointAt(separator, i);
+ // TODO: accept code points
+ UserLogRingCharBuffer.getInstance().push((char)codePoint, x, y);
+ }
+ LatinImeLogger.logOnInputSeparator();
+ }
+
+ public static void onAutoCorrection(final String typedWord, final String correctedWord,
+ final String separatorString, final WordComposer wordComposer) {
+ final boolean isBatchMode = wordComposer.isBatchMode();
+ if (!isBatchMode && TextUtils.isEmpty(typedWord)) {
+ return;
+ }
+ // TODO: this fails when the separator is more than 1 code point long, but
+ // the backend can't handle it yet. The only case when this happens is with
+ // smileys and other multi-character keys.
+ final int codePoint = TextUtils.isEmpty(separatorString) ? Constants.NOT_A_CODE
+ : separatorString.codePointAt(0);
+ if (!isBatchMode) {
+ LatinImeLogger.logOnAutoCorrectionForTyping(typedWord, correctedWord, codePoint);
+ } else {
+ if (!TextUtils.isEmpty(correctedWord)) {
+ // We must make sure that InputPointer contains only the relative timestamps,
+ // not actual timestamps.
+ LatinImeLogger.logOnAutoCorrectionForGeometric(
+ "", correctedWord, codePoint, wordComposer.getInputPointers());
+ }
+ }
+ }
+
+ public static void onAutoCorrectionCancellation() {
+ LatinImeLogger.logOnAutoCorrectionCancelled();
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/TextRange.java b/java/src/com/android/inputmethod/latin/utils/TextRange.java
new file mode 100644
index 000000000..5793e4170
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/TextRange.java
@@ -0,0 +1,116 @@
+/*
+ * 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.utils;
+
+import android.text.Spanned;
+import android.text.style.SuggestionSpan;
+
+import java.util.Arrays;
+
+/**
+ * Represents a range of text, relative to the current cursor position.
+ */
+public final class TextRange {
+ private final CharSequence mTextAtCursor;
+ private final int mWordAtCursorStartIndex;
+ private final int mWordAtCursorEndIndex;
+ private final int mCursorIndex;
+
+ public final CharSequence mWord;
+
+ public int getNumberOfCharsInWordBeforeCursor() {
+ return mCursorIndex - mWordAtCursorStartIndex;
+ }
+
+ public int getNumberOfCharsInWordAfterCursor() {
+ return mWordAtCursorEndIndex - mCursorIndex;
+ }
+
+ /**
+ * Gets the suggestion spans that are put squarely on the word, with the exact start
+ * and end of the span matching the boundaries of the word.
+ * @return the list of spans.
+ */
+ public SuggestionSpan[] getSuggestionSpansAtWord() {
+ if (!(mTextAtCursor instanceof Spanned && mWord instanceof Spanned)) {
+ return new SuggestionSpan[0];
+ }
+ final Spanned text = (Spanned)mTextAtCursor;
+ // Note: it's fine to pass indices negative or greater than the length of the string
+ // to the #getSpans() method. The reason we need to get from -1 to +1 is that, the
+ // spans were cut at the cursor position, and #getSpans(start, end) does not return
+ // spans that end at `start' or begin at `end'. Consider the following case:
+ // this| is (The | symbolizes the cursor position
+ // ---- ---
+ // In this case, the cursor is in position 4, so the 0~7 span has been split into
+ // a 0~4 part and a 4~7 part.
+ // If we called #getSpans(0, 4) in this case, we would only get the part from 0 to 4
+ // of the span, and not the part from 4 to 7, so we would not realize the span actually
+ // extends from 0 to 7. But if we call #getSpans(-1, 5) we'll get both the 0~4 and
+ // the 4~7 spans and we can merge them accordingly.
+ // Any span starting more than 1 char away from the word boundaries in any direction
+ // does not touch the word, so we don't need to consider it. That's why requesting
+ // -1 ~ +1 is enough.
+ // Of course this is only relevant if the cursor is at one end of the word. If it's
+ // in the middle, the -1 and +1 are not necessary, but they are harmless.
+ final SuggestionSpan[] spans = text.getSpans(mWordAtCursorStartIndex - 1,
+ mWordAtCursorEndIndex + 1, SuggestionSpan.class);
+ int readIndex = 0;
+ int writeIndex = 0;
+ for (; readIndex < spans.length; ++readIndex) {
+ final SuggestionSpan span = spans[readIndex];
+ // The span may be null, as we null them when we find duplicates. Cf a few lines
+ // down.
+ if (null == span) continue;
+ // Tentative span start and end. This may be modified later if we realize the
+ // same span is also applied to other parts of the string.
+ int spanStart = text.getSpanStart(span);
+ int spanEnd = text.getSpanEnd(span);
+ for (int i = readIndex + 1; i < spans.length; ++i) {
+ if (span.equals(spans[i])) {
+ // We found the same span somewhere else. Read the new extent of this
+ // span, and adjust our values accordingly.
+ spanStart = Math.min(spanStart, text.getSpanStart(spans[i]));
+ spanEnd = Math.max(spanEnd, text.getSpanEnd(spans[i]));
+ // ...and mark the span as processed.
+ spans[i] = null;
+ }
+ }
+ if (spanStart == mWordAtCursorStartIndex && spanEnd == mWordAtCursorEndIndex) {
+ // If the span does not start and stop here, we ignore it. It probably extends
+ // past the start or end of the word, as happens in missing space correction
+ // or EasyEditSpans put by voice input.
+ spans[writeIndex++] = spans[readIndex];
+ }
+ }
+ return writeIndex == readIndex ? spans : Arrays.copyOfRange(spans, 0, writeIndex);
+ }
+
+ public TextRange(final CharSequence textAtCursor, final int wordAtCursorStartIndex,
+ final int wordAtCursorEndIndex, final int cursorIndex) {
+ if (wordAtCursorStartIndex < 0 || cursorIndex < wordAtCursorStartIndex
+ || cursorIndex > wordAtCursorEndIndex
+ || wordAtCursorEndIndex > textAtCursor.length()) {
+ throw new IndexOutOfBoundsException();
+ }
+ mTextAtCursor = textAtCursor;
+ mWordAtCursorStartIndex = wordAtCursorStartIndex;
+ mWordAtCursorEndIndex = wordAtCursorEndIndex;
+ mCursorIndex = cursorIndex;
+ mWord = mTextAtCursor.subSequence(mWordAtCursorStartIndex, mWordAtCursorEndIndex);
+ }
+} \ No newline at end of file
diff --git a/java/src/com/android/inputmethod/keyboard/TypefaceUtils.java b/java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java
index c3b952037..544e4d201 100644
--- a/java/src/com/android/inputmethod/keyboard/TypefaceUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/TypefaceUtils.java
@@ -14,15 +14,13 @@
* limitations under the License.
*/
-package com.android.inputmethod.keyboard;
+package com.android.inputmethod.latin.utils;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.SparseArray;
-import com.android.inputmethod.latin.utils.CollectionUtils;
-
public final class TypefaceUtils {
private TypefaceUtils() {
// This utility class is not publicly instantiable.
diff --git a/java/src/com/android/inputmethod/latin/utils/UsabilityStudyLogUtils.java b/java/src/com/android/inputmethod/latin/utils/UsabilityStudyLogUtils.java
new file mode 100644
index 000000000..ef9cacf61
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/utils/UsabilityStudyLogUtils.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.utils;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.inputmethodservice.InputMethodService;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.util.Log;
+
+import com.android.inputmethod.latin.LatinImeLogger;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.channels.FileChannel;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+public final class UsabilityStudyLogUtils {
+ // TODO: remove code duplication with ResearchLog class
+ private static final String USABILITY_TAG = UsabilityStudyLogUtils.class.getSimpleName();
+ private static final String FILENAME = "log.txt";
+ private final Handler mLoggingHandler;
+ private File mFile;
+ private File mDirectory;
+ private InputMethodService mIms;
+ private PrintWriter mWriter;
+ private final Date mDate;
+ private final SimpleDateFormat mDateFormat;
+
+ private UsabilityStudyLogUtils() {
+ mDate = new Date();
+ mDateFormat = new SimpleDateFormat("yyyyMMdd-HHmmss.SSSZ", Locale.US);
+
+ HandlerThread handlerThread = new HandlerThread("UsabilityStudyLogUtils logging task",
+ Process.THREAD_PRIORITY_BACKGROUND);
+ handlerThread.start();
+ mLoggingHandler = new Handler(handlerThread.getLooper());
+ }
+
+ // Initialization-on-demand holder
+ private static final class OnDemandInitializationHolder {
+ public static final UsabilityStudyLogUtils sInstance = new UsabilityStudyLogUtils();
+ }
+
+ public static UsabilityStudyLogUtils getInstance() {
+ return OnDemandInitializationHolder.sInstance;
+ }
+
+ public void init(final InputMethodService ims) {
+ mIms = ims;
+ mDirectory = ims.getFilesDir();
+ }
+
+ private void createLogFileIfNotExist() {
+ if ((mFile == null || !mFile.exists())
+ && (mDirectory != null && mDirectory.exists())) {
+ try {
+ mWriter = getPrintWriter(mDirectory, FILENAME, false);
+ } catch (final IOException e) {
+ Log.e(USABILITY_TAG, "Can't create log file.");
+ }
+ }
+ }
+
+ public static void writeBackSpace(final int x, final int y) {
+ UsabilityStudyLogUtils.getInstance().write("<backspace>\t" + x + "\t" + y);
+ }
+
+ public static void writeChar(final char c, final int x, final int y) {
+ String inputChar = String.valueOf(c);
+ switch (c) {
+ case '\n':
+ inputChar = "<enter>";
+ break;
+ case '\t':
+ inputChar = "<tab>";
+ break;
+ case ' ':
+ inputChar = "<space>";
+ break;
+ }
+ UsabilityStudyLogUtils.getInstance().write(inputChar + "\t" + x + "\t" + y);
+ LatinImeLogger.onPrintAllUsabilityStudyLogs();
+ }
+
+ public void write(final String log) {
+ mLoggingHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ createLogFileIfNotExist();
+ final long currentTime = System.currentTimeMillis();
+ mDate.setTime(currentTime);
+
+ final String printString = String.format(Locale.US, "%s\t%d\t%s\n",
+ mDateFormat.format(mDate), currentTime, log);
+ if (LatinImeLogger.sDBG) {
+ Log.d(USABILITY_TAG, "Write: " + log);
+ }
+ mWriter.print(printString);
+ }
+ });
+ }
+
+ private synchronized String getBufferedLogs() {
+ mWriter.flush();
+ final StringBuilder sb = new StringBuilder();
+ final BufferedReader br = getBufferedReader();
+ String line;
+ try {
+ while ((line = br.readLine()) != null) {
+ sb.append('\n');
+ sb.append(line);
+ }
+ } catch (final IOException e) {
+ Log.e(USABILITY_TAG, "Can't read log file.");
+ } finally {
+ if (LatinImeLogger.sDBG) {
+ Log.d(USABILITY_TAG, "Got all buffered logs\n" + sb.toString());
+ }
+ try {
+ br.close();
+ } catch (final IOException e) {
+ // ignore.
+ }
+ }
+ return sb.toString();
+ }
+
+ public void emailResearcherLogsAll() {
+ mLoggingHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ final Date date = new Date();
+ date.setTime(System.currentTimeMillis());
+ final String currentDateTimeString =
+ new SimpleDateFormat("yyyyMMdd-HHmmssZ", Locale.US).format(date);
+ if (mFile == null) {
+ Log.w(USABILITY_TAG, "No internal log file found.");
+ return;
+ }
+ if (mIms.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ != PackageManager.PERMISSION_GRANTED) {
+ Log.w(USABILITY_TAG, "Doesn't have the permission WRITE_EXTERNAL_STORAGE");
+ return;
+ }
+ mWriter.flush();
+ final String destPath = Environment.getExternalStorageDirectory()
+ + "/research-" + currentDateTimeString + ".log";
+ final File destFile = new File(destPath);
+ try {
+ final FileInputStream srcStream = new FileInputStream(mFile);
+ final FileOutputStream destStream = new FileOutputStream(destFile);
+ final FileChannel src = srcStream.getChannel();
+ final FileChannel dest = destStream.getChannel();
+ src.transferTo(0, src.size(), dest);
+ src.close();
+ srcStream.close();
+ dest.close();
+ destStream.close();
+ } catch (final FileNotFoundException e1) {
+ Log.w(USABILITY_TAG, e1);
+ return;
+ } catch (final IOException e2) {
+ Log.w(USABILITY_TAG, e2);
+ return;
+ }
+ if (destFile == null || !destFile.exists()) {
+ Log.w(USABILITY_TAG, "Dest file doesn't exist.");
+ return;
+ }
+ final Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (LatinImeLogger.sDBG) {
+ Log.d(USABILITY_TAG, "Destination file URI is " + destFile.toURI());
+ }
+ intent.setType("text/plain");
+ intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + destPath));
+ intent.putExtra(Intent.EXTRA_SUBJECT,
+ "[Research Logs] " + currentDateTimeString);
+ mIms.startActivity(intent);
+ }
+ });
+ }
+
+ public void printAll() {
+ mLoggingHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mIms.getCurrentInputConnection().commitText(getBufferedLogs(), 0);
+ }
+ });
+ }
+
+ public void clearAll() {
+ mLoggingHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mFile != null && mFile.exists()) {
+ if (LatinImeLogger.sDBG) {
+ Log.d(USABILITY_TAG, "Delete log file.");
+ }
+ mFile.delete();
+ mWriter.close();
+ }
+ }
+ });
+ }
+
+ private BufferedReader getBufferedReader() {
+ createLogFileIfNotExist();
+ try {
+ return new BufferedReader(new FileReader(mFile));
+ } catch (final FileNotFoundException e) {
+ return null;
+ }
+ }
+
+ private PrintWriter getPrintWriter(final File dir, final String filename,
+ final boolean renew) throws IOException {
+ mFile = new File(dir, filename);
+ if (mFile.exists()) {
+ if (renew) {
+ mFile.delete();
+ }
+ }
+ return new PrintWriter(new FileOutputStream(mFile), true /* autoFlush */);
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java b/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
index 9f842f976..713a45bda 100644
--- a/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/UserHistoryForgettingCurveUtils.java
@@ -16,9 +16,10 @@
package com.android.inputmethod.latin.utils;
-import android.text.format.DateUtils;
import android.util.Log;
+import java.util.concurrent.TimeUnit;
+
public final class UserHistoryForgettingCurveUtils {
private static final String TAG = UserHistoryForgettingCurveUtils.class.getSimpleName();
private static final boolean DEBUG = false;
@@ -27,8 +28,8 @@ public final class UserHistoryForgettingCurveUtils {
private static final int FC_LEVEL_MAX = 3;
/* package */ static final int ELAPSED_TIME_MAX = 15;
private static final int ELAPSED_TIME_INTERVAL_HOURS = 6;
- private static final long ELAPSED_TIME_INTERVAL_MILLIS = ELAPSED_TIME_INTERVAL_HOURS
- * DateUtils.HOUR_IN_MILLIS;
+ private static final long ELAPSED_TIME_INTERVAL_MILLIS =
+ TimeUnit.HOURS.toMillis(ELAPSED_TIME_INTERVAL_HOURS);
private static final int HALF_LIFE_HOURS = 48;
private static final int MAX_PUSH_ELAPSED = (FC_LEVEL_MAX + 1) * (ELAPSED_TIME_MAX + 1);
diff --git a/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java b/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java
index 3e67e8216..a2c6c4524 100644
--- a/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java
+++ b/java/src/com/android/inputmethod/latin/utils/UserLogRingCharBuffer.java
@@ -20,7 +20,6 @@ import android.inputmethodservice.InputMethodService;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.Settings;
-import com.android.inputmethod.latin.utils.Utils.UsabilityStudyLogUtils;
public final class UserLogRingCharBuffer {
public /* for test */ static final int BUFSIZE = 20;
diff --git a/java/src/com/android/inputmethod/latin/utils/Utils.java b/java/src/com/android/inputmethod/latin/utils/Utils.java
deleted file mode 100644
index c4e18ed7e..000000000
--- a/java/src/com/android/inputmethod/latin/utils/Utils.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.latin.utils;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.inputmethodservice.InputMethodService;
-import android.net.Uri;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Process;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.LatinImeLogger;
-import com.android.inputmethod.latin.SuggestedWords;
-import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
-import com.android.inputmethod.latin.WordComposer;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.channels.FileChannel;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-
-// TODO: Come up with a more descriptive class name
-public final class Utils {
- private static final String TAG = Utils.class.getSimpleName();
-
- private Utils() {
- // This utility class is not publicly instantiable.
- }
-
- // TODO: Make this an external class
- public static final class UsabilityStudyLogUtils {
- // TODO: remove code duplication with ResearchLog class
- private static final String USABILITY_TAG = UsabilityStudyLogUtils.class.getSimpleName();
- private static final String FILENAME = "log.txt";
- private final Handler mLoggingHandler;
- private File mFile;
- private File mDirectory;
- private InputMethodService mIms;
- private PrintWriter mWriter;
- private final Date mDate;
- private final SimpleDateFormat mDateFormat;
-
- private UsabilityStudyLogUtils() {
- mDate = new Date();
- mDateFormat = new SimpleDateFormat("yyyyMMdd-HHmmss.SSSZ", Locale.US);
-
- HandlerThread handlerThread = new HandlerThread("UsabilityStudyLogUtils logging task",
- Process.THREAD_PRIORITY_BACKGROUND);
- handlerThread.start();
- mLoggingHandler = new Handler(handlerThread.getLooper());
- }
-
- // Initialization-on-demand holder
- private static final class OnDemandInitializationHolder {
- public static final UsabilityStudyLogUtils sInstance = new UsabilityStudyLogUtils();
- }
-
- public static UsabilityStudyLogUtils getInstance() {
- return OnDemandInitializationHolder.sInstance;
- }
-
- public void init(final InputMethodService ims) {
- mIms = ims;
- mDirectory = ims.getFilesDir();
- }
-
- private void createLogFileIfNotExist() {
- if ((mFile == null || !mFile.exists())
- && (mDirectory != null && mDirectory.exists())) {
- try {
- mWriter = getPrintWriter(mDirectory, FILENAME, false);
- } catch (final IOException e) {
- Log.e(USABILITY_TAG, "Can't create log file.");
- }
- }
- }
-
- public static void writeBackSpace(final int x, final int y) {
- UsabilityStudyLogUtils.getInstance().write("<backspace>\t" + x + "\t" + y);
- }
-
- public static void writeChar(final char c, final int x, final int y) {
- String inputChar = String.valueOf(c);
- switch (c) {
- case '\n':
- inputChar = "<enter>";
- break;
- case '\t':
- inputChar = "<tab>";
- break;
- case ' ':
- inputChar = "<space>";
- break;
- }
- UsabilityStudyLogUtils.getInstance().write(inputChar + "\t" + x + "\t" + y);
- LatinImeLogger.onPrintAllUsabilityStudyLogs();
- }
-
- public void write(final String log) {
- mLoggingHandler.post(new Runnable() {
- @Override
- public void run() {
- createLogFileIfNotExist();
- final long currentTime = System.currentTimeMillis();
- mDate.setTime(currentTime);
-
- final String printString = String.format(Locale.US, "%s\t%d\t%s\n",
- mDateFormat.format(mDate), currentTime, log);
- if (LatinImeLogger.sDBG) {
- Log.d(USABILITY_TAG, "Write: " + log);
- }
- mWriter.print(printString);
- }
- });
- }
-
- private synchronized String getBufferedLogs() {
- mWriter.flush();
- final StringBuilder sb = new StringBuilder();
- final BufferedReader br = getBufferedReader();
- String line;
- try {
- while ((line = br.readLine()) != null) {
- sb.append('\n');
- sb.append(line);
- }
- } catch (final IOException e) {
- Log.e(USABILITY_TAG, "Can't read log file.");
- } finally {
- if (LatinImeLogger.sDBG) {
- Log.d(USABILITY_TAG, "Got all buffered logs\n" + sb.toString());
- }
- try {
- br.close();
- } catch (final IOException e) {
- // ignore.
- }
- }
- return sb.toString();
- }
-
- public void emailResearcherLogsAll() {
- mLoggingHandler.post(new Runnable() {
- @Override
- public void run() {
- final Date date = new Date();
- date.setTime(System.currentTimeMillis());
- final String currentDateTimeString =
- new SimpleDateFormat("yyyyMMdd-HHmmssZ", Locale.US).format(date);
- if (mFile == null) {
- Log.w(USABILITY_TAG, "No internal log file found.");
- return;
- }
- if (mIms.checkCallingOrSelfPermission(
- android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
- != PackageManager.PERMISSION_GRANTED) {
- Log.w(USABILITY_TAG, "Doesn't have the permission WRITE_EXTERNAL_STORAGE");
- return;
- }
- mWriter.flush();
- final String destPath = Environment.getExternalStorageDirectory()
- + "/research-" + currentDateTimeString + ".log";
- final File destFile = new File(destPath);
- try {
- final FileInputStream srcStream = new FileInputStream(mFile);
- final FileOutputStream destStream = new FileOutputStream(destFile);
- final FileChannel src = srcStream.getChannel();
- final FileChannel dest = destStream.getChannel();
- src.transferTo(0, src.size(), dest);
- src.close();
- srcStream.close();
- dest.close();
- destStream.close();
- } catch (final FileNotFoundException e1) {
- Log.w(USABILITY_TAG, e1);
- return;
- } catch (final IOException e2) {
- Log.w(USABILITY_TAG, e2);
- return;
- }
- if (destFile == null || !destFile.exists()) {
- Log.w(USABILITY_TAG, "Dest file doesn't exist.");
- return;
- }
- final Intent intent = new Intent(Intent.ACTION_SEND);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- if (LatinImeLogger.sDBG) {
- Log.d(USABILITY_TAG, "Destination file URI is " + destFile.toURI());
- }
- intent.setType("text/plain");
- intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + destPath));
- intent.putExtra(Intent.EXTRA_SUBJECT,
- "[Research Logs] " + currentDateTimeString);
- mIms.startActivity(intent);
- }
- });
- }
-
- public void printAll() {
- mLoggingHandler.post(new Runnable() {
- @Override
- public void run() {
- mIms.getCurrentInputConnection().commitText(getBufferedLogs(), 0);
- }
- });
- }
-
- public void clearAll() {
- mLoggingHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mFile != null && mFile.exists()) {
- if (LatinImeLogger.sDBG) {
- Log.d(USABILITY_TAG, "Delete log file.");
- }
- mFile.delete();
- mWriter.close();
- }
- }
- });
- }
-
- private BufferedReader getBufferedReader() {
- createLogFileIfNotExist();
- try {
- return new BufferedReader(new FileReader(mFile));
- } catch (final FileNotFoundException e) {
- return null;
- }
- }
-
- private PrintWriter getPrintWriter(final File dir, final String filename,
- final boolean renew) throws IOException {
- mFile = new File(dir, filename);
- if (mFile.exists()) {
- if (renew) {
- mFile.delete();
- }
- }
- return new PrintWriter(new FileOutputStream(mFile), true /* autoFlush */);
- }
- }
-
- // TODO: Make this an external class
- public static final class Stats {
- public static void onNonSeparator(final char code, final int x, final int y) {
- UserLogRingCharBuffer.getInstance().push(code, x, y);
- LatinImeLogger.logOnInputChar();
- }
-
- public static void onSeparator(final int code, final int x, final int y) {
- // Helper method to log a single code point separator
- // TODO: cache this mapping of a code point to a string in a sparse array in StringUtils
- onSeparator(new String(new int[]{code}, 0, 1), x, y);
- }
-
- public static void onSeparator(final String separator, final int x, final int y) {
- final int length = separator.length();
- for (int i = 0; i < length; i = Character.offsetByCodePoints(separator, i, 1)) {
- int codePoint = Character.codePointAt(separator, i);
- // TODO: accept code points
- UserLogRingCharBuffer.getInstance().push((char)codePoint, x, y);
- }
- LatinImeLogger.logOnInputSeparator();
- }
-
- public static void onAutoCorrection(final String typedWord, final String correctedWord,
- final String separatorString, final WordComposer wordComposer) {
- final boolean isBatchMode = wordComposer.isBatchMode();
- if (!isBatchMode && TextUtils.isEmpty(typedWord)) {
- return;
- }
- // TODO: this fails when the separator is more than 1 code point long, but
- // the backend can't handle it yet. The only case when this happens is with
- // smileys and other multi-character keys.
- final int codePoint = TextUtils.isEmpty(separatorString) ? Constants.NOT_A_CODE
- : separatorString.codePointAt(0);
- if (!isBatchMode) {
- LatinImeLogger.logOnAutoCorrectionForTyping(typedWord, correctedWord, codePoint);
- } else {
- if (!TextUtils.isEmpty(correctedWord)) {
- // We must make sure that InputPointer contains only the relative timestamps,
- // not actual timestamps.
- LatinImeLogger.logOnAutoCorrectionForGeometric(
- "", correctedWord, codePoint, wordComposer.getInputPointers());
- }
- }
- }
-
- public static void onAutoCorrectionCancellation() {
- LatinImeLogger.logOnAutoCorrectionCancelled();
- }
- }
-
- public static String getDebugInfo(final SuggestedWords suggestions, final int pos) {
- if (!LatinImeLogger.sDBG) {
- return null;
- }
- final SuggestedWordInfo wordInfo = suggestions.getInfo(pos);
- if (wordInfo == null) {
- return null;
- }
- final String info = wordInfo.getDebugString();
- if (TextUtils.isEmpty(info)) {
- return null;
- }
- return info;
- }
-
- public static int getAcitivityTitleResId(final Context context,
- final Class<? extends Activity> cls) {
- final ComponentName cn = new ComponentName(context, cls);
- try {
- final ActivityInfo ai = context.getPackageManager().getActivityInfo(cn, 0);
- if (ai != null) {
- return ai.labelRes;
- }
- } catch (final NameNotFoundException e) {
- Log.e(TAG, "Failed to get settings activity title res id.", e);
- }
- return 0;
- }
-
- /**
- * A utility method to get the application's PackageInfo.versionName
- * @return the application's PackageInfo.versionName
- */
- public static String getVersionName(final Context context) {
- try {
- if (context == null) {
- return "";
- }
- final String packageName = context.getPackageName();
- final PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
- return info.versionName;
- } catch (final NameNotFoundException e) {
- Log.e(TAG, "Could not find version info.", e);
- }
- return "";
- }
-}
diff --git a/java/src/com/android/inputmethod/keyboard/ViewLayoutUtils.java b/java/src/com/android/inputmethod/latin/utils/ViewLayoutUtils.java
index dc12fa468..f9d853493 100644
--- a/java/src/com/android/inputmethod/keyboard/ViewLayoutUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/ViewLayoutUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.inputmethod.keyboard;
+package com.android.inputmethod.latin.utils;
import android.view.View;
import android.view.ViewGroup;
@@ -27,7 +27,8 @@ public final class ViewLayoutUtils {
// This utility class is not publicly instantiable.
}
- public static MarginLayoutParams newLayoutParam(ViewGroup placer, int width, int height) {
+ public static MarginLayoutParams newLayoutParam(final ViewGroup placer, final int width,
+ final int height) {
if (placer instanceof FrameLayout) {
return new FrameLayout.LayoutParams(width, height);
} else if (placer instanceof RelativeLayout) {
@@ -40,7 +41,8 @@ public final class ViewLayoutUtils {
}
}
- public static void placeViewAt(View view, int x, int y, int w, int h) {
+ public static void placeViewAt(final View view, final int x, final int y, final int w,
+ final int h) {
final ViewGroup.LayoutParams lp = view.getLayoutParams();
if (lp instanceof MarginLayoutParams) {
final MarginLayoutParams marginLayoutParams = (MarginLayoutParams)lp;
diff --git a/java/src/com/android/inputmethod/research/ResearchLog.java b/java/src/com/android/inputmethod/research/ResearchLog.java
index 88207c024..46e620ae5 100644
--- a/java/src/com/android/inputmethod/research/ResearchLog.java
+++ b/java/src/com/android/inputmethod/research/ResearchLog.java
@@ -55,7 +55,7 @@ public class ResearchLog {
private static final String TAG = ResearchLog.class.getSimpleName();
private static final boolean DEBUG = false
&& ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS_DEBUG;
- private static final long FLUSH_DELAY_IN_MS = 1000 * 5;
+ private static final long FLUSH_DELAY_IN_MS = TimeUnit.SECONDS.toMillis(5);
/* package */ final ScheduledExecutorService mExecutor;
/* package */ final File mFile;
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index ecf809242..ed047e13a 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -37,7 +37,6 @@ import android.os.IBinder;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.text.TextUtils;
-import android.text.format.DateUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -57,11 +56,11 @@ import com.android.inputmethod.latin.Dictionary;
import com.android.inputmethod.latin.LatinIME;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputConnection;
-import com.android.inputmethod.latin.RichInputConnection.Range;
import com.android.inputmethod.latin.Suggest;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.utils.InputTypeUtils;
+import com.android.inputmethod.latin.utils.TextRange;
import com.android.inputmethod.research.MotionEventReader.ReplayData;
import com.android.inputmethod.research.ui.SplashScreen;
@@ -75,6 +74,7 @@ import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
+import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
// TODO: Add a unit test for every "logging" method (i.e. that is called from the IME and calls
@@ -137,10 +137,10 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private static final int MAX_INPUTVIEW_LENGTH_TO_CAPTURE = 8192; // must be >=1
private static final String PREF_RESEARCH_SAVED_CHANNEL = "pref_research_saved_channel";
- private static final long RESEARCHLOG_CLOSE_TIMEOUT_IN_MS = 5 * 1000;
- private static final long RESEARCHLOG_ABORT_TIMEOUT_IN_MS = 5 * 1000;
- private static final long DURATION_BETWEEN_DIR_CLEANUP_IN_MS = DateUtils.DAY_IN_MILLIS;
- private static final long MAX_LOGFILE_AGE_IN_MS = 4 * DateUtils.DAY_IN_MILLIS;
+ private static final long RESEARCHLOG_CLOSE_TIMEOUT_IN_MS = TimeUnit.SECONDS.toMillis(5);
+ private static final long RESEARCHLOG_ABORT_TIMEOUT_IN_MS = TimeUnit.SECONDS.toMillis(5);
+ private static final long DURATION_BETWEEN_DIR_CLEANUP_IN_MS = TimeUnit.DAYS.toMillis(1);
+ private static final long MAX_LOGFILE_AGE_IN_MS = TimeUnit.DAYS.toMillis(4);
private static final ResearchLogger sInstance = new ResearchLogger();
private static String sAccountType = null;
@@ -195,7 +195,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
// not performed on text that the user types into the feedback dialog.
private boolean mInFeedbackDialog = false;
private Handler mUserRecordingTimeoutHandler;
- private static final long USER_RECORDING_TIMEOUT_MS = 30L * DateUtils.SECOND_IN_MILLIS;
+ private static final long USER_RECORDING_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(30);
// Stores a temporary LogUnit while generating a phantom space. Needed because phantom spaces
// are issued out-of-order, immediately before the characters generated by other operations that
@@ -542,8 +542,8 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
toast.show();
boolean isLogDeleted = abort();
final long currentTime = System.currentTimeMillis();
- final long resumeTime = currentTime + 1000 * 60 *
- SUSPEND_DURATION_IN_MINUTES;
+ final long resumeTime = currentTime
+ + TimeUnit.MINUTES.toMillis(SUSPEND_DURATION_IN_MINUTES);
suspendLoggingUntil(resumeTime);
toast.cancel();
Toast.makeText(latinIME, R.string.research_notify_logging_suspended,
@@ -635,7 +635,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
mMotionEventReader.readMotionEventData(mUserRecordingFile);
mReplayer.replay(replayData, null);
}
- }, 1000);
+ }, TimeUnit.SECONDS.toMillis(1));
}
if (FEEDBACK_DIALOG_SHOULD_PRESERVE_TEXT_FIELD) {
@@ -1220,7 +1220,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
final RichInputConnection connection) {
String word = "";
if (connection != null) {
- Range range = connection.getWordRangeAtCursor(WHITESPACE_SEPARATORS, 1);
+ TextRange range = connection.getWordRangeAtCursor(WHITESPACE_SEPARATORS, 1);
if (range != null) {
word = range.mWord.toString();
}
diff --git a/java/src/com/android/inputmethod/research/Statistics.java b/java/src/com/android/inputmethod/research/Statistics.java
index e573ca012..fd323a104 100644
--- a/java/src/com/android/inputmethod/research/Statistics.java
+++ b/java/src/com/android/inputmethod/research/Statistics.java
@@ -21,6 +21,8 @@ import android.util.Log;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.define.ProductionFlag;
+import java.util.concurrent.TimeUnit;
+
public class Statistics {
private static final String TAG = Statistics.class.getSimpleName();
private static final boolean DEBUG = false
@@ -102,8 +104,8 @@ public class Statistics {
// To account for the interruptions when the user's attention is directed elsewhere, times
// longer than MIN_TYPING_INTERMISSION are not counted when estimating this statistic.
- public static final int MIN_TYPING_INTERMISSION = 2 * 1000; // in milliseconds
- public static final int MIN_DELETION_INTERMISSION = 10 * 1000; // in milliseconds
+ public static final long MIN_TYPING_INTERMISSION = TimeUnit.SECONDS.toMillis(2);
+ public static final long MIN_DELETION_INTERMISSION = TimeUnit.SECONDS.toMillis(10);
// The last time that a tap was performed
private long mLastTapTime;
diff --git a/java/src/com/android/inputmethod/research/UploaderService.java b/java/src/com/android/inputmethod/research/UploaderService.java
index 8bd46c19e..fd3f2f60e 100644
--- a/java/src/com/android/inputmethod/research/UploaderService.java
+++ b/java/src/com/android/inputmethod/research/UploaderService.java
@@ -34,7 +34,6 @@ public final class UploaderService extends IntentService {
public static final long RUN_INTERVAL = AlarmManager.INTERVAL_HOUR;
public static final String EXTRA_UPLOAD_UNCONDITIONALLY = UploaderService.class.getName()
+ ".extra.UPLOAD_UNCONDITIONALLY";
- protected static final int TIMEOUT_IN_MS = 1000 * 4;
public UploaderService() {
super("Research Uploader Service");
diff --git a/native/jni/Android.mk b/native/jni/Android.mk
index f89eea735..d78da969b 100644
--- a/native/jni/Android.mk
+++ b/native/jni/Android.mk
@@ -79,8 +79,9 @@ LATIN_IME_CORE_SRC_FILES := \
typing_traversal.cpp \
typing_weighting.cpp) \
$(addprefix utils/, \
+ autocorrection_threshold_utils.cpp \
char_utils.cpp \
- autocorrection_threshold_utils.cpp)
+ log_utils.cpp)
LOCAL_SRC_FILES := \
$(LATIN_IME_JNI_SRC_FILES) \
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index a93bbeb8c..6e1b80ee0 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -93,8 +93,8 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jclass clazz, jstring s
AKLOGE("DICT: dictionary format is unknown, bad magic number");
releaseDictBuf(static_cast<const char *>(dictBuf) - offset, adjDictSize, fd);
} else {
- dictionary = new Dictionary(
- dictBuf, static_cast<int>(dictSize), fd, offset, updatableMmap);
+ dictionary = new Dictionary(env, dictBuf, static_cast<int>(dictSize), fd, offset,
+ updatableMmap);
}
PROF_END(66);
PROF_CLOSE;
@@ -201,7 +201,7 @@ static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz, j
static jint latinime_BinaryDictionary_getProbability(JNIEnv *env, jclass clazz, jlong dict,
jintArray word) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
- if (!dictionary) return 0;
+ if (!dictionary) return NOT_A_PROBABILITY;
const jsize wordLength = env->GetArrayLength(word);
int codePoints[wordLength];
env->GetIntArrayRegion(word, 0, wordLength, codePoints);
diff --git a/native/jni/src/defines.h b/native/jni/src/defines.h
index cb6681456..607a74400 100644
--- a/native/jni/src/defines.h
+++ b/native/jni/src/defines.h
@@ -35,46 +35,74 @@
// Must be equal to ProximityInfo.MAX_PROXIMITY_CHARS_SIZE in Java
#define MAX_PROXIMITY_CHARS_SIZE 16
#define ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE 2
+#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
-#if defined(FLAG_DO_PROFILE) || defined(FLAG_DBG)
-#include <android/log.h>
-#ifndef LOG_TAG
-#define LOG_TAG "LatinIME: "
-#endif // LOG_TAG
-#define AKLOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__)
-#define AKLOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##__VA_ARGS__)
-
-#define DUMP_RESULT(words, frequencies) do { dumpResult(words, frequencies); } while (0)
-#define DUMP_WORD(word, length) do { dumpWord(word, length); } while (0)
-#define INTS_TO_CHARS(input, length, output) do { \
- intArrayToCharArray(input, length, output); } while (0)
-
-// TODO: Support full UTF-8 conversion
-AK_FORCE_INLINE static int intArrayToCharArray(const int *source, const int sourceSize,
- char *dest) {
+AK_FORCE_INLINE static int intArrayToCharArray(const int *const source, const int sourceSize,
+ char *dest, const int destSize) {
+ // We want to always terminate with a 0 char, so stop one short of the length to make
+ // sure there is room.
+ const int destLimit = destSize - 1;
int si = 0;
int di = 0;
- while (si < sourceSize && di < MAX_WORD_LENGTH - 1 && 0 != source[si]) {
+ while (si < sourceSize && di < destLimit && 0 != source[si]) {
const int codePoint = source[si++];
- if (codePoint < 0x7F) {
+ if (codePoint < 0x7F) { // One byte
dest[di++] = codePoint;
- } else if (codePoint < 0x7FF) {
+ } else if (codePoint < 0x7FF) { // Two bytes
+ if (di + 1 >= destLimit) break;
dest[di++] = 0xC0 + (codePoint >> 6);
dest[di++] = 0x80 + (codePoint & 0x3F);
- } else if (codePoint < 0xFFFF) {
+ } else if (codePoint < 0xFFFF) { // Three bytes
+ if (di + 2 >= destLimit) break;
dest[di++] = 0xE0 + (codePoint >> 12);
- dest[di++] = 0x80 + ((codePoint & 0xFC0) >> 6);
+ dest[di++] = 0x80 + ((codePoint >> 6) & 0x3F);
+ dest[di++] = 0x80 + (codePoint & 0x3F);
+ } else if (codePoint <= 0x1FFFFF) { // Four bytes
+ if (di + 3 >= destLimit) break;
+ dest[di++] = 0xF0 + (codePoint >> 18);
+ dest[di++] = 0x80 + ((codePoint >> 12) & 0x3F);
+ dest[di++] = 0x80 + ((codePoint >> 6) & 0x3F);
dest[di++] = 0x80 + (codePoint & 0x3F);
+ } else if (codePoint <= 0x3FFFFFF) { // Five bytes
+ if (di + 4 >= destLimit) break;
+ dest[di++] = 0xF8 + (codePoint >> 24);
+ dest[di++] = 0x80 + ((codePoint >> 18) & 0x3F);
+ dest[di++] = 0x80 + ((codePoint >> 12) & 0x3F);
+ dest[di++] = 0x80 + ((codePoint >> 6) & 0x3F);
+ dest[di++] = codePoint & 0x3F;
+ } else if (codePoint <= 0x7FFFFFFF) { // Six bytes
+ if (di + 5 >= destLimit) break;
+ dest[di++] = 0xFC + (codePoint >> 30);
+ dest[di++] = 0x80 + ((codePoint >> 24) & 0x3F);
+ dest[di++] = 0x80 + ((codePoint >> 18) & 0x3F);
+ dest[di++] = 0x80 + ((codePoint >> 12) & 0x3F);
+ dest[di++] = 0x80 + ((codePoint >> 6) & 0x3F);
+ dest[di++] = codePoint & 0x3F;
+ } else {
+ // Not a code point... skip.
}
}
dest[di] = 0;
return di;
}
+#if defined(FLAG_DO_PROFILE) || defined(FLAG_DBG)
+#include <android/log.h>
+#ifndef LOG_TAG
+#define LOG_TAG "LatinIME: "
+#endif // LOG_TAG
+#define AKLOGE(fmt, ...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##__VA_ARGS__)
+#define AKLOGI(fmt, ...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##__VA_ARGS__)
+
+#define DUMP_RESULT(words, frequencies) do { dumpResult(words, frequencies); } while (0)
+#define DUMP_WORD(word, length) do { dumpWord(word, length); } while (0)
+#define INTS_TO_CHARS(input, length, output, outlength) do { \
+ intArrayToCharArray(input, length, output, outlength); } while (0)
+
static inline void dumpWordInfo(const int *word, const int length, const int rank,
const int probability) {
static char charBuf[50];
- const int N = intArrayToCharArray(word, length, charBuf);
+ const int N = intArrayToCharArray(word, length, charBuf, NELEMS(charBuf));
if (N > 1) {
AKLOGI("%2d [ %s ] (%d)", rank, charBuf, probability);
}
@@ -90,7 +118,7 @@ static inline void dumpResult(const int *outWords, const int *frequencies) {
static AK_FORCE_INLINE void dumpWord(const int *word, const int length) {
static char charBuf[50];
- const int N = intArrayToCharArray(word, length, charBuf);
+ const int N = intArrayToCharArray(word, length, charBuf, NELEMS(charBuf));
if (N > 1) {
AKLOGI("[ %s ]", charBuf);
}
@@ -304,8 +332,6 @@ static inline void prof_out(void) {
template<typename T> AK_FORCE_INLINE const T &min(const T &a, const T &b) { return a < b ? a : b; }
template<typename T> AK_FORCE_INLINE const T &max(const T &a, const T &b) { return a > b ? a : b; }
-#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
-
// DEBUG
#define INPUTLENGTH_FOR_DEBUG (-1)
#define MIN_OUTPUT_INDEX_FOR_DEBUG (-1)
diff --git a/native/jni/src/suggest/core/dicnode/dic_node.h b/native/jni/src/suggest/core/dicnode/dic_node.h
index 52db8e9c7..973da67e4 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node.h
@@ -28,15 +28,16 @@
#if DEBUG_DICT
#define LOGI_SHOW_ADD_COST_PROP \
do { char charBuf[50]; \
- INTS_TO_CHARS(getOutputWordBuf(), getNodeCodePointCount(), charBuf); \
+ INTS_TO_CHARS(getOutputWordBuf(), getNodeCodePointCount(), charBuf, NELEMS(charBuf)); \
AKLOGI("%20s, \"%c\", size = %03d, total = %03d, index(0) = %02d, dist = %.4f, %s,,", \
__FUNCTION__, getNodeCodePoint(), inputSize, getTotalInputIndex(), \
getInputIndex(0), getNormalizedCompoundDistance(), charBuf); } while (0)
#define DUMP_WORD_AND_SCORE(header) \
do { char charBuf[50]; char prevWordCharBuf[50]; \
- INTS_TO_CHARS(getOutputWordBuf(), getNodeCodePointCount(), charBuf); \
+ INTS_TO_CHARS(getOutputWordBuf(), getNodeCodePointCount(), charBuf, NELEMS(charBuf)); \
INTS_TO_CHARS(mDicNodeState.mDicNodeStatePrevWord.mPrevWord, \
- mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(), prevWordCharBuf); \
+ mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength(), prevWordCharBuf, \
+ NELEMS(prevWordCharBuf)); \
AKLOGI("#%8s, %5f, %5f, %5f, %5f, %s, %s, %d,,", header, \
getSpatialDistanceForScoring(), getLanguageDistanceForScoring(), \
getNormalizedCompoundDistance(), getRawLength(), prevWordCharBuf, charBuf, \
@@ -111,32 +112,23 @@ class DicNode {
mIsUsed = true;
mIsCachedForNextSuggestion = false;
mDicNodeProperties.init(
- NOT_A_DICT_POS, 0 /* flags */, rootGroupPos, NOT_A_DICT_POS /* attributesPos */,
+ NOT_A_DICT_POS, rootGroupPos, NOT_A_DICT_POS /* attributesPos */,
NOT_A_CODE_POINT /* nodeCodePoint */, NOT_A_PROBABILITY /* probability */,
- false /* isTerminal */, true /* hasChildren */, 0 /* depth */,
- 0 /* terminalDepth */);
+ false /* isTerminal */, true /* hasChildren */,
+ false /* isBlacklistedOrNotAWord */, 0 /* depth */, 0 /* terminalDepth */);
mDicNodeState.init(prevWordNodePos);
PROF_NODE_RESET(mProfiler);
}
- void initAsPassingChild(DicNode *parentNode) {
- mIsUsed = true;
- mIsCachedForNextSuggestion = parentNode->mIsCachedForNextSuggestion;
- const int c = parentNode->getNodeTypedCodePoint();
- mDicNodeProperties.init(&parentNode->mDicNodeProperties, c);
- mDicNodeState.init(&parentNode->mDicNodeState);
- PROF_NODE_COPY(&parentNode->mProfiler, mProfiler);
- }
-
// Init for root with previous word
void initAsRootWithPreviousWord(DicNode *dicNode, const int rootGroupPos) {
mIsUsed = true;
mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion;
mDicNodeProperties.init(
- NOT_A_DICT_POS, 0 /* flags */, rootGroupPos, NOT_A_DICT_POS /* attributesPos */,
+ NOT_A_DICT_POS, rootGroupPos, NOT_A_DICT_POS /* attributesPos */,
NOT_A_CODE_POINT /* nodeCodePoint */, NOT_A_PROBABILITY /* probability */,
- false /* isTerminal */, true /* hasChildren */, 0 /* depth */,
- 0 /* terminalDepth */);
+ false /* isTerminal */, true /* hasChildren */,
+ false /* isBlacklistedOrNotAWord */, 0 /* depth */, 0 /* terminalDepth */);
// TODO: Move to dicNodeState?
mDicNodeState.mDicNodeStateOutput.init(); // reset for next word
mDicNodeState.mDicNodeStateInput.init(
@@ -156,18 +148,27 @@ class DicNode {
PROF_NODE_COPY(&dicNode->mProfiler, mProfiler);
}
- // TODO: minimize arguments by looking binary_format
- void initAsChild(DicNode *dicNode, const int pos, const uint8_t flags, const int childrenPos,
+ void initAsPassingChild(DicNode *parentNode) {
+ mIsUsed = true;
+ mIsCachedForNextSuggestion = parentNode->mIsCachedForNextSuggestion;
+ const int c = parentNode->getNodeTypedCodePoint();
+ mDicNodeProperties.init(&parentNode->mDicNodeProperties, c);
+ mDicNodeState.init(&parentNode->mDicNodeState);
+ PROF_NODE_COPY(&parentNode->mProfiler, mProfiler);
+ }
+
+ void initAsChild(DicNode *dicNode, const int pos, const int childrenPos,
const int attributesPos, const int probability, const bool isTerminal,
- const bool hasChildren, const uint16_t mergedNodeCodePointCount,
- const int *const mergedNodeCodePoints) {
+ const bool hasChildren, const bool isBlacklistedOrNotAWord,
+ const uint16_t mergedNodeCodePointCount, const int *const mergedNodeCodePoints) {
mIsUsed = true;
uint16_t newDepth = static_cast<uint16_t>(dicNode->getNodeCodePointCount() + 1);
mIsCachedForNextSuggestion = dicNode->mIsCachedForNextSuggestion;
const uint16_t newLeavingDepth = static_cast<uint16_t>(
dicNode->mDicNodeProperties.getLeavingDepth() + mergedNodeCodePointCount);
- mDicNodeProperties.init(pos, flags, childrenPos, attributesPos, mergedNodeCodePoints[0],
- probability, isTerminal, hasChildren, newDepth, newLeavingDepth);
+ mDicNodeProperties.init(pos, childrenPos, attributesPos, mergedNodeCodePoints[0],
+ probability, isTerminal, hasChildren, isBlacklistedOrNotAWord, newDepth,
+ newLeavingDepth);
mDicNodeState.init(&dicNode->mDicNodeState, mergedNodeCodePointCount,
mergedNodeCodePoints);
PROF_NODE_COPY(&dicNode->mProfiler, mProfiler);
@@ -215,7 +216,7 @@ class DicNode {
}
bool isImpossibleBigramWord() const {
- if (mDicNodeProperties.hasBlacklistedOrNotAWordFlag()) {
+ if (isBlacklistedOrNotAWord()) {
return true;
}
const int prevWordLen = mDicNodeState.mDicNodeStatePrevWord.getPrevWordLength()
@@ -462,8 +463,8 @@ class DicNode {
return mDicNodeState.mDicNodeStateScoring.isExactMatch();
}
- uint8_t getFlags() const {
- return mDicNodeProperties.getFlags();
+ bool isBlacklistedOrNotAWord() const {
+ return mDicNodeProperties.isBlacklistedOrNotAWord();
}
int getAttributesPos() const {
@@ -503,6 +504,12 @@ class DicNode {
if (!right->isUsed()) {
return false;
}
+ // Promote exact matches to prevent them from being pruned.
+ const bool leftExactMatch = isExactMatch();
+ const bool rightExactMatch = right->isExactMatch();
+ if (leftExactMatch != rightExactMatch) {
+ return leftExactMatch;
+ }
const float diff =
right->getNormalizedCompoundDistance() - getNormalizedCompoundDistance();
static const float MIN_DIFF = 0.000001f;
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_properties.h b/native/jni/src/suggest/core/dicnode/dic_node_properties.h
index 7e8aa4979..d98000d83 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_properties.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node_properties.h
@@ -20,7 +20,6 @@
#include <stdint.h>
#include "defines.h"
-#include "suggest/core/dictionary/binary_format.h"
namespace latinime {
@@ -32,24 +31,25 @@ namespace latinime {
class DicNodeProperties {
public:
AK_FORCE_INLINE DicNodeProperties()
- : mPos(0), mFlags(0), mChildrenPos(0), mAttributesPos(0), mProbability(0),
- mNodeCodePoint(0), mDepth(0), mLeavingDepth(0), mIsTerminal(false),
- mHasChildren(false) {}
+ : mPos(0), mChildrenPos(0), mAttributesPos(0), mProbability(0),
+ mNodeCodePoint(0), mIsTerminal(false), mHasChildren(false),
+ mIsBlacklistedOrNotAWord(false), mDepth(0), mLeavingDepth(0) {}
virtual ~DicNodeProperties() {}
// Should be called only once per DicNode is initialized.
- void init(const int pos, const uint8_t flags, const int childrenPos, const int attributesPos,
+ void init(const int pos, const int childrenPos, const int attributesPos,
const int nodeCodePoint, const int probability, const bool isTerminal,
- const bool hasChildren, const uint16_t depth, const uint16_t leavingDepth) {
+ const bool hasChildren, const bool isBlacklistedOrNotAWord,
+ const uint16_t depth, const uint16_t leavingDepth) {
mPos = pos;
- mFlags = flags;
mChildrenPos = childrenPos;
mAttributesPos = attributesPos;
mNodeCodePoint = nodeCodePoint;
mProbability = probability;
mIsTerminal = isTerminal;
mHasChildren = hasChildren;
+ mIsBlacklistedOrNotAWord = isBlacklistedOrNotAWord;
mDepth = depth;
mLeavingDepth = leavingDepth;
}
@@ -57,13 +57,13 @@ class DicNodeProperties {
// Init for copy
void init(const DicNodeProperties *const nodeProp) {
mPos = nodeProp->mPos;
- mFlags = nodeProp->mFlags;
mChildrenPos = nodeProp->mChildrenPos;
mAttributesPos = nodeProp->mAttributesPos;
mNodeCodePoint = nodeProp->mNodeCodePoint;
mProbability = nodeProp->mProbability;
mIsTerminal = nodeProp->mIsTerminal;
mHasChildren = nodeProp->mHasChildren;
+ mIsBlacklistedOrNotAWord = nodeProp->mIsBlacklistedOrNotAWord;
mDepth = nodeProp->mDepth;
mLeavingDepth = nodeProp->mLeavingDepth;
}
@@ -71,13 +71,13 @@ class DicNodeProperties {
// Init as passing child
void init(const DicNodeProperties *const nodeProp, const int codePoint) {
mPos = nodeProp->mPos;
- mFlags = nodeProp->mFlags;
mChildrenPos = nodeProp->mChildrenPos;
mAttributesPos = nodeProp->mAttributesPos;
mNodeCodePoint = codePoint; // Overwrite the node char of a passing child
mProbability = nodeProp->mProbability;
mIsTerminal = nodeProp->mIsTerminal;
mHasChildren = nodeProp->mHasChildren;
+ mIsBlacklistedOrNotAWord = nodeProp->mIsBlacklistedOrNotAWord;
mDepth = nodeProp->mDepth + 1; // Increment the depth of a passing child
mLeavingDepth = nodeProp->mLeavingDepth;
}
@@ -86,10 +86,6 @@ class DicNodeProperties {
return mPos;
}
- uint8_t getFlags() const {
- return mFlags;
- }
-
int getChildrenPos() const {
return mChildrenPos;
}
@@ -123,8 +119,8 @@ class DicNodeProperties {
return mHasChildren || mDepth != mLeavingDepth;
}
- bool hasBlacklistedOrNotAWordFlag() const {
- return BinaryFormat::hasBlacklistedOrNotAWordFlag(mFlags);
+ bool isBlacklistedOrNotAWord() const {
+ return mIsBlacklistedOrNotAWord;
}
private:
@@ -132,15 +128,15 @@ class DicNodeProperties {
// Use a default copy constructor and an assign operator because shallow copies are ok
// for this class
int mPos;
- uint8_t mFlags;
int mChildrenPos;
int mAttributesPos;
int mProbability;
int mNodeCodePoint;
- uint16_t mDepth;
- uint16_t mLeavingDepth;
bool mIsTerminal;
bool mHasChildren;
+ bool mIsBlacklistedOrNotAWord;
+ uint16_t mDepth;
+ uint16_t mLeavingDepth;
};
} // namespace latinime
#endif // LATINIME_DIC_NODE_PROPERTIES_H
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_proximity_filter.h b/native/jni/src/suggest/core/dicnode/dic_node_proximity_filter.h
new file mode 100644
index 000000000..1a39f2ef3
--- /dev/null
+++ b/native/jni/src/suggest/core/dicnode/dic_node_proximity_filter.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef LATINIME_DIC_NODE_PROXIMITY_FILTER_H
+#define LATINIME_DIC_NODE_PROXIMITY_FILTER_H
+
+#include "defines.h"
+#include "suggest/core/layout/proximity_info_state.h"
+#include "suggest/core/layout/proximity_info_utils.h"
+#include "suggest/core/policy/dictionary_structure_policy.h"
+
+namespace latinime {
+
+class DicNodeProximityFilter : public DictionaryStructurePolicy::NodeFilter {
+ public:
+ DicNodeProximityFilter(const ProximityInfoState *const pInfoState,
+ const int pointIndex, const bool exactOnly)
+ : mProximityInfoState(pInfoState), mPointIndex(pointIndex), mExactOnly(exactOnly) {}
+
+ bool isFilteredOut(const int codePoint) const {
+ return !isProximityCodePoint(codePoint);
+ }
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(DicNodeProximityFilter);
+
+ const ProximityInfoState *const mProximityInfoState;
+ const int mPointIndex;
+ const bool mExactOnly;
+
+ // TODO: Move to proximity info state
+ bool isProximityCodePoint(const int codePoint) const {
+ if (!mProximityInfoState) {
+ return true;
+ }
+ if (mExactOnly) {
+ return mProximityInfoState->getPrimaryCodePointAt(mPointIndex) == codePoint;
+ }
+ const ProximityType matchedId = mProximityInfoState->getProximityType(
+ mPointIndex, codePoint, true /* checkProximityChars */);
+ return ProximityInfoUtils::isMatchOrProximityChar(matchedId);
+ }
+};
+} // namespace latinime
+#endif // LATINIME_DIC_NODE_PROXIMITY_FILTER_H
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
index 9bf7eceb5..6c7f6667a 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
+++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.cpp
@@ -14,18 +14,17 @@
* limitations under the License.
*/
+#include "suggest/core/dicnode/dic_node_utils.h"
+
#include <cstring>
-#include <vector>
#include "suggest/core/dicnode/dic_node.h"
-#include "suggest/core/dicnode/dic_node_utils.h"
+#include "suggest/core/dicnode/dic_node_proximity_filter.h"
#include "suggest/core/dicnode/dic_node_vector.h"
#include "suggest/core/dictionary/binary_dictionary_info.h"
#include "suggest/core/dictionary/binary_format.h"
#include "suggest/core/dictionary/multi_bigram_map.h"
#include "suggest/core/dictionary/probability_utils.h"
-#include "suggest/core/layout/proximity_info.h"
-#include "suggest/core/layout/proximity_info_state.h"
#include "suggest/core/policy/dictionary_structure_policy.h"
#include "utils/char_utils.h"
@@ -57,21 +56,20 @@ namespace latinime {
///////////////////////////////////
/* static */ void DicNodeUtils::createAndGetPassingChildNode(DicNode *dicNode,
- const ProximityInfoState *pInfoState, const int pointIndex, const bool exactOnly,
+ const DicNodeProximityFilter *const childrenFilter,
DicNodeVector *childDicNodes) {
// Passing multiple chars node. No need to traverse child
const int codePoint = dicNode->getNodeTypedCodePoint();
const int baseLowerCaseCodePoint = CharUtils::toBaseLowerCase(codePoint);
- const bool isMatch = isMatchedNodeCodePoint(pInfoState, pointIndex, exactOnly, codePoint);
- if (isMatch || CharUtils::isIntentionalOmissionCodePoint(baseLowerCaseCodePoint)) {
+ if (!childrenFilter->isFilteredOut(codePoint)
+ || CharUtils::isIntentionalOmissionCodePoint(baseLowerCaseCodePoint)) {
childDicNodes->pushPassingChild(dicNode);
}
}
/* static */ int DicNodeUtils::createAndGetLeavingChildNode(DicNode *dicNode, int pos,
const BinaryDictionaryInfo *const binaryDictionaryInfo,
- const ProximityInfoState *pInfoState, const int pointIndex, const bool exactOnly,
- const std::vector<int> *const codePointsFilter, const ProximityInfo *const pInfo,
+ const DicNodeProximityFilter *const childrenFilter,
DicNodeVector *childDicNodes) {
int nextPos = pos;
const uint8_t flags = BinaryFormat::getFlagsAndForwardPointer(
@@ -80,6 +78,7 @@ namespace latinime {
const bool isTerminal = (0 != (BinaryFormat::FLAG_IS_TERMINAL & flags));
const bool hasChildren = BinaryFormat::hasChildrenInFlags(flags);
const bool hasShortcuts = (0 != (BinaryFormat::FLAG_HAS_SHORTCUT_TARGETS & flags));
+ const bool isBlacklistedOrNotAWord = BinaryFormat::hasBlacklistedOrNotAWordFlag(flags);
int codePoint = BinaryFormat::getCodePointAndForwardPointer(
binaryDictionaryInfo->getDictRoot(), &pos);
@@ -110,50 +109,18 @@ namespace latinime {
const int siblingPos = BinaryFormat::skipChildrenPosAndAttributes(
binaryDictionaryInfo->getDictRoot(), flags, pos);
- if (isDicNodeFilteredOut(mergedNodeCodePoints[0], pInfo, codePointsFilter)) {
- return siblingPos;
- }
- if (!isMatchedNodeCodePoint(pInfoState, pointIndex, exactOnly, mergedNodeCodePoints[0])) {
+ if (childrenFilter->isFilteredOut(mergedNodeCodePoints[0])) {
return siblingPos;
}
- childDicNodes->pushLeavingChild(dicNode, nextPos, flags, childrenPos, attributesPos,
- probability, isTerminal, hasChildren, mergedNodeCodePointCount, mergedNodeCodePoints);
+ childDicNodes->pushLeavingChild(dicNode, nextPos, childrenPos, attributesPos,
+ probability, isTerminal, hasChildren, isBlacklistedOrNotAWord,
+ mergedNodeCodePointCount, mergedNodeCodePoints);
return siblingPos;
}
-/* static */ bool DicNodeUtils::isDicNodeFilteredOut(const int nodeCodePoint,
- const ProximityInfo *const pInfo, const std::vector<int> *const codePointsFilter) {
- const int filterSize = codePointsFilter ? codePointsFilter->size() : 0;
- if (filterSize <= 0) {
- return false;
- }
- if (pInfo && (pInfo->getKeyIndexOf(nodeCodePoint) == NOT_AN_INDEX
- || CharUtils::isIntentionalOmissionCodePoint(nodeCodePoint))) {
- // If normalized nodeCodePoint is not on the keyboard or skippable, this child is never
- // filtered.
- return false;
- }
- const int lowerCodePoint = CharUtils::toLowerCase(nodeCodePoint);
- const int baseLowerCodePoint = CharUtils::toBaseCodePoint(lowerCodePoint);
- // TODO: Avoid linear search
- for (int i = 0; i < filterSize; ++i) {
- // Checking if a normalized code point is in filter characters when pInfo is not
- // null. When pInfo is null, nodeCodePoint is used to check filtering without
- // normalizing.
- if ((pInfo && ((*codePointsFilter)[i] == lowerCodePoint
- || (*codePointsFilter)[i] == baseLowerCodePoint))
- || (!pInfo && (*codePointsFilter)[i] == nodeCodePoint)) {
- return false;
- }
- }
- return true;
-}
-
/* static */ void DicNodeUtils::createAndGetAllLeavingChildNodes(DicNode *dicNode,
const BinaryDictionaryInfo *const binaryDictionaryInfo,
- const ProximityInfoState *pInfoState, const int pointIndex, const bool exactOnly,
- const std::vector<int> *const codePointsFilter, const ProximityInfo *const pInfo,
- DicNodeVector *childDicNodes) {
+ const DicNodeProximityFilter *const childrenFilter, DicNodeVector *childDicNodes) {
if (!dicNode->hasChildren()) {
return;
}
@@ -161,14 +128,8 @@ namespace latinime {
const int childCount = BinaryFormat::getGroupCountAndForwardPointer(
binaryDictionaryInfo->getDictRoot(), &nextPos);
for (int i = 0; i < childCount; i++) {
- const int filterSize = codePointsFilter ? codePointsFilter->size() : 0;
nextPos = createAndGetLeavingChildNode(dicNode, nextPos, binaryDictionaryInfo,
- pInfoState, pointIndex, exactOnly, codePointsFilter, pInfo,
- childDicNodes);
- if (!pInfo && filterSize > 0 && childDicNodes->exceeds(filterSize)) {
- // All code points have been found.
- break;
- }
+ childrenFilter, childDicNodes);
}
}
@@ -184,13 +145,12 @@ namespace latinime {
if (dicNode->isTotalInputSizeExceedingLimit()) {
return;
}
+ const DicNodeProximityFilter childrenFilter(pInfoState, pointIndex, exactOnly);
if (!dicNode->isLeavingNode()) {
- DicNodeUtils::createAndGetPassingChildNode(dicNode, pInfoState, pointIndex, exactOnly,
- childDicNodes);
+ DicNodeUtils::createAndGetPassingChildNode(dicNode, &childrenFilter, childDicNodes);
} else {
DicNodeUtils::createAndGetAllLeavingChildNodes(
- dicNode, binaryDictionaryInfo, pInfoState, pointIndex, exactOnly,
- 0 /* codePointsFilter */, 0 /* pInfo */, childDicNodes);
+ dicNode, binaryDictionaryInfo, &childrenFilter, childDicNodes);
}
}
@@ -230,23 +190,6 @@ namespace latinime {
return ProbabilityUtils::backoff(unigramProbability);
}
-///////////////////////////////////////
-// Bigram / Unigram dictionary utils //
-///////////////////////////////////////
-
-/* static */ bool DicNodeUtils::isMatchedNodeCodePoint(const ProximityInfoState *pInfoState,
- const int pointIndex, const bool exactOnly, const int nodeCodePoint) {
- if (!pInfoState) {
- return true;
- }
- if (exactOnly) {
- return pInfoState->getPrimaryCodePointAt(pointIndex) == nodeCodePoint;
- }
- const ProximityType matchedId = pInfoState->getProximityType(pointIndex, nodeCodePoint,
- true /* checkProximityChars */);
- return isProximityChar(matchedId);
-}
-
////////////////
// Char utils //
////////////////
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_utils.h b/native/jni/src/suggest/core/dicnode/dic_node_utils.h
index d526975ce..7b567b582 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_utils.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node_utils.h
@@ -18,7 +18,6 @@
#define LATINIME_DIC_NODE_UTILS_H
#include <stdint.h>
-#include <vector>
#include "defines.h"
@@ -26,8 +25,8 @@ namespace latinime {
class BinaryDictionaryInfo;
class DicNode;
+class DicNodeProximityFilter;
class DicNodeVector;
-class ProximityInfo;
class ProximityInfoState;
class MultiBigramMap;
@@ -44,19 +43,12 @@ class DicNodeUtils {
const BinaryDictionaryInfo *const binaryDictionaryInfo, DicNodeVector *childDicNodes);
static float getBigramNodeImprobability(const BinaryDictionaryInfo *const binaryDictionaryInfo,
const DicNode *const node, MultiBigramMap *const multiBigramMap);
- static bool isDicNodeFilteredOut(const int nodeCodePoint, const ProximityInfo *const pInfo,
- const std::vector<int> *const codePointsFilter);
// TODO: Move to private
static void getProximityChildDicNodes(DicNode *dicNode,
const BinaryDictionaryInfo *const binaryDictionaryInfo,
const ProximityInfoState *pInfoState, const int pointIndex, bool exactOnly,
DicNodeVector *childDicNodes);
- // TODO: Move to proximity info
- static bool isProximityChar(ProximityType type) {
- return type == MATCH_CHAR || type == PROXIMITY_CHAR || type == ADDITIONAL_PROXIMITY_CHAR;
- }
-
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(DicNodeUtils);
// Max number of bigrams to look up
@@ -64,22 +56,14 @@ class DicNodeUtils {
static int getBigramNodeProbability(const BinaryDictionaryInfo *const binaryDictionaryInfo,
const DicNode *const node, MultiBigramMap *multiBigramMap);
- static void createAndGetPassingChildNode(DicNode *dicNode, const ProximityInfoState *pInfoState,
- const int pointIndex, const bool exactOnly, DicNodeVector *childDicNodes);
+ static void createAndGetPassingChildNode(DicNode *dicNode,
+ const DicNodeProximityFilter *const childrenFilter, DicNodeVector *childDicNodes);
static void createAndGetAllLeavingChildNodes(DicNode *dicNode,
const BinaryDictionaryInfo *const binaryDictionaryInfo,
- const ProximityInfoState *pInfoState, const int pointIndex, const bool exactOnly,
- const std::vector<int> *const codePointsFilter,
- const ProximityInfo *const pInfo, DicNodeVector *childDicNodes);
+ const DicNodeProximityFilter *const childrenFilter, DicNodeVector *childDicNodes);
static int createAndGetLeavingChildNode(DicNode *dicNode, int pos,
const BinaryDictionaryInfo *const binaryDictionaryInfo,
- const ProximityInfoState *pInfoState, const int pointIndex,
- const bool exactOnly, const std::vector<int> *const codePointsFilter,
- const ProximityInfo *const pInfo, DicNodeVector *childDicNodes);
-
- // TODO: Move to proximity info
- static bool isMatchedNodeCodePoint(const ProximityInfoState *pInfoState, const int pointIndex,
- const bool exactOnly, const int nodeCodePoint);
+ const DicNodeProximityFilter *const childrenFilter, DicNodeVector *childDicNodes);
};
} // namespace latinime
#endif // LATINIME_DIC_NODE_UTILS_H
diff --git a/native/jni/src/suggest/core/dicnode/dic_node_vector.h b/native/jni/src/suggest/core/dicnode/dic_node_vector.h
index 9641cc19c..5ac4eeaf4 100644
--- a/native/jni/src/suggest/core/dicnode/dic_node_vector.h
+++ b/native/jni/src/suggest/core/dicnode/dic_node_vector.h
@@ -62,14 +62,15 @@ class DicNodeVector {
mDicNodes.back().initAsPassingChild(dicNode);
}
- void pushLeavingChild(DicNode *dicNode, const int pos, const uint8_t flags,
- const int childrenPos, const int attributesPos, const int probability,
- const bool isTerminal, const bool hasChildren, const uint16_t mergedNodeCodePointCount,
- const int *const mergedNodeCodePoints) {
+ void pushLeavingChild(DicNode *dicNode, const int pos, const int childrenPos,
+ const int attributesPos, const int probability, const bool isTerminal,
+ const bool hasChildren, const bool isBlacklistedOrNotAWord,
+ const uint16_t mergedNodeCodePointCount, const int *const mergedNodeCodePoints) {
ASSERT(!mLock);
mDicNodes.push_back(mEmptyNode);
- mDicNodes.back().initAsChild(dicNode, pos, flags, childrenPos, attributesPos, probability,
- isTerminal, hasChildren, mergedNodeCodePointCount, mergedNodeCodePoints);
+ mDicNodes.back().initAsChild(dicNode, pos, childrenPos, attributesPos, probability,
+ isTerminal, hasChildren, isBlacklistedOrNotAWord, mergedNodeCodePointCount,
+ mergedNodeCodePoints);
}
DicNode *operator[](const int id) {
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_format_utils.cpp b/native/jni/src/suggest/core/dictionary/binary_dictionary_format_utils.cpp
index bbb4ca3f0..5d14a0554 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_format_utils.cpp
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_format_utils.cpp
@@ -27,17 +27,13 @@ const int BinaryDictionaryFormatUtils::DICTIONARY_MINIMUM_SIZE = 4;
/**
* Format versions
*/
-// Originally, format version 1 had a 16-bit magic number, then the version number `01'
-// then options that must be 0. Hence the first 32-bits of the format are always as follow
-// and it's okay to consider them a magic number as a whole.
-const uint32_t BinaryDictionaryFormatUtils::FORMAT_VERSION_1_MAGIC_NUMBER = 0x78B10100;
// The versions of Latin IME that only handle format version 1 only test for the magic
// number, so we had to change it so that version 2 files would be rejected by older
// implementations. On this occasion, we made the magic number 32 bits long.
-const uint32_t BinaryDictionaryFormatUtils::FORMAT_VERSION_2_MAGIC_NUMBER = 0x9BC13AFE;
+const uint32_t BinaryDictionaryFormatUtils::HEADER_VERSION_2_MAGIC_NUMBER = 0x9BC13AFE;
// Magic number (4 bytes), version (2 bytes), options (2 bytes), header size (4 bytes) = 12
-const int BinaryDictionaryFormatUtils::FORMAT_VERSION_2_MINIMUM_SIZE = 12;
+const int BinaryDictionaryFormatUtils::HEADER_VERSION_2_MINIMUM_SIZE = 12;
/* static */ BinaryDictionaryFormatUtils::FORMAT_VERSION
BinaryDictionaryFormatUtils::detectFormatVersion(const uint8_t *const dict,
@@ -50,31 +46,28 @@ const int BinaryDictionaryFormatUtils::FORMAT_VERSION_2_MINIMUM_SIZE = 12;
}
const uint32_t magicNumber = ByteArrayUtils::readUint32(dict, 0);
switch (magicNumber) {
- case FORMAT_VERSION_1_MAGIC_NUMBER:
- // Format 1 header is exactly 5 bytes long and looks like:
- // Magic number (2 bytes) 0x78 0xB1
- // Version number (1 byte) 0x01
- // Options (2 bytes) must be 0x00 0x00
- return VERSION_1;
- case FORMAT_VERSION_2_MAGIC_NUMBER:
- // Version 2 dictionaries are at least 12 bytes long.
- // If this dictionary has the version 2 magic number but is less than 12 bytes long,
- // then it's an unknown format and we need to avoid confidently reading the next bytes.
- if (dictSize < FORMAT_VERSION_2_MINIMUM_SIZE) {
+ case HEADER_VERSION_2_MAGIC_NUMBER:
+ // Version 2 header are at least 12 bytes long.
+ // If this header has the version 2 magic number but is less than 12 bytes long,
+ // then it's an unknown format and we need to avoid confidently reading the next bytes.
+ if (dictSize < HEADER_VERSION_2_MINIMUM_SIZE) {
+ return UNKNOWN_VERSION;
+ }
+ // Version 2 header is as follows:
+ // Magic number (4 bytes) 0x9B 0xC1 0x3A 0xFE
+ // Version number (2 bytes)
+ // Options (2 bytes)
+ // Header size (4 bytes) : integer, big endian
+ if (ByteArrayUtils::readUint16(dict, 4) == 2) {
+ return VERSION_2;
+ } else if (ByteArrayUtils::readUint16(dict, 4) == 3) {
+ // TODO: Support version 3 dictionary.
+ return UNKNOWN_VERSION;
+ } else {
+ return UNKNOWN_VERSION;
+ }
+ default:
return UNKNOWN_VERSION;
- }
- // Format 2 header is as follows:
- // Magic number (4 bytes) 0x9B 0xC1 0x3A 0xFE
- // Version number (2 bytes) 0x00 0x02
- // Options (2 bytes)
- // Header size (4 bytes) : integer, big endian
- if (ByteArrayUtils::readUint16(dict, 4) == 2) {
- return VERSION_2;
- } else {
- return UNKNOWN_VERSION;
- }
- default:
- return UNKNOWN_VERSION;
}
}
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_format_utils.h b/native/jni/src/suggest/core/dictionary/binary_dictionary_format_utils.h
index 33618b9f0..830684c70 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_format_utils.h
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_format_utils.h
@@ -33,10 +33,9 @@ namespace latinime {
*/
class BinaryDictionaryFormatUtils {
public:
- // TODO: Remove obsolete version logic
enum FORMAT_VERSION {
- VERSION_1,
VERSION_2,
+ VERSION_3,
UNKNOWN_VERSION
};
@@ -46,9 +45,8 @@ class BinaryDictionaryFormatUtils {
DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryDictionaryFormatUtils);
static const int DICTIONARY_MINIMUM_SIZE;
- static const uint32_t FORMAT_VERSION_1_MAGIC_NUMBER;
- static const uint32_t FORMAT_VERSION_2_MAGIC_NUMBER;
- static const int FORMAT_VERSION_2_MINIMUM_SIZE;
+ static const uint32_t HEADER_VERSION_2_MAGIC_NUMBER;
+ static const int HEADER_VERSION_2_MINIMUM_SIZE;
};
} // namespace latinime
#endif /* LATINIME_BINARY_DICTIONARY_FORMAT_UTILS_H */
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_header.h b/native/jni/src/suggest/core/dictionary/binary_dictionary_header.h
index 6dba0b266..240512bce 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_header.h
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_header.h
@@ -53,6 +53,20 @@ class BinaryDictionaryHeader {
return mMultiWordCostMultiplier;
}
+ AK_FORCE_INLINE void readHeaderValueOrQuestionMark(const char *const key,
+ int *outValue, int outValueSize) const {
+ if (outValueSize <= 0) return;
+ if (outValueSize == 1) {
+ outValue[0] = '\0';
+ return;
+ }
+ if (!BinaryDictionaryHeaderReadingUtils::readHeaderValue(mBinaryDictionaryInfo,
+ key, outValue, outValueSize)) {
+ outValue[0] = '?';
+ outValue[1] = '\0';
+ }
+ }
+
private:
DISALLOW_COPY_AND_ASSIGN(BinaryDictionaryHeader);
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_header_reading_utils.cpp b/native/jni/src/suggest/core/dictionary/binary_dictionary_header_reading_utils.cpp
index 2c9593144..a57b0f859 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_header_reading_utils.cpp
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_header_reading_utils.cpp
@@ -26,12 +26,10 @@ namespace latinime {
const int BinaryDictionaryHeaderReadingUtils::MAX_OPTION_KEY_LENGTH = 256;
-const int BinaryDictionaryHeaderReadingUtils::FORMAT_VERSION_1_HEADER_SIZE = 5;
-
-const int BinaryDictionaryHeaderReadingUtils::VERSION_2_MAGIC_NUMBER_SIZE = 4;
-const int BinaryDictionaryHeaderReadingUtils::VERSION_2_DICTIONARY_VERSION_SIZE = 2;
-const int BinaryDictionaryHeaderReadingUtils::VERSION_2_DICTIONARY_FLAG_SIZE = 2;
-const int BinaryDictionaryHeaderReadingUtils::VERSION_2_DICTIONARY_HEADER_SIZE_SIZE = 4;
+const int BinaryDictionaryHeaderReadingUtils::VERSION_2_HEADER_MAGIC_NUMBER_SIZE = 4;
+const int BinaryDictionaryHeaderReadingUtils::VERSION_2_HEADER_DICTIONARY_VERSION_SIZE = 2;
+const int BinaryDictionaryHeaderReadingUtils::VERSION_2_HEADER_FLAG_SIZE = 2;
+const int BinaryDictionaryHeaderReadingUtils::VERSION_2_HEADER_SIZE_FIELD_SIZE = 4;
const BinaryDictionaryHeaderReadingUtils::DictionaryFlags
BinaryDictionaryHeaderReadingUtils::NO_FLAGS = 0;
@@ -47,15 +45,13 @@ const BinaryDictionaryHeaderReadingUtils::DictionaryFlags
/* static */ int BinaryDictionaryHeaderReadingUtils::getHeaderSize(
const BinaryDictionaryInfo *const binaryDictionaryInfo) {
- switch (binaryDictionaryInfo->getFormat()) {
- case BinaryDictionaryFormatUtils::VERSION_1:
- return FORMAT_VERSION_1_HEADER_SIZE;
- case BinaryDictionaryFormatUtils::VERSION_2:
+ switch (getHeaderVersion(binaryDictionaryInfo->getFormat())) {
+ case HEADER_VERSION_2:
// See the format of the header in the comment in
// BinaryDictionaryFormatUtils::detectFormatVersion()
return ByteArrayUtils::readUint32(binaryDictionaryInfo->getDictBuf(),
- VERSION_2_MAGIC_NUMBER_SIZE + VERSION_2_DICTIONARY_VERSION_SIZE
- + VERSION_2_DICTIONARY_FLAG_SIZE);
+ VERSION_2_HEADER_MAGIC_NUMBER_SIZE + VERSION_2_HEADER_DICTIONARY_VERSION_SIZE
+ + VERSION_2_HEADER_FLAG_SIZE);
default:
return S_INT_MAX;
}
@@ -64,12 +60,10 @@ const BinaryDictionaryHeaderReadingUtils::DictionaryFlags
/* static */ BinaryDictionaryHeaderReadingUtils::DictionaryFlags
BinaryDictionaryHeaderReadingUtils::getFlags(
const BinaryDictionaryInfo *const binaryDictionaryInfo) {
- switch (binaryDictionaryInfo->getFormat()) {
- case BinaryDictionaryFormatUtils::VERSION_1:
- return NO_FLAGS;
- case BinaryDictionaryFormatUtils::VERSION_2:
+ switch (getHeaderVersion(binaryDictionaryInfo->getFormat())) {
+ case HEADER_VERSION_2:
return ByteArrayUtils::readUint16(binaryDictionaryInfo->getDictBuf(),
- VERSION_2_MAGIC_NUMBER_SIZE + VERSION_2_DICTIONARY_VERSION_SIZE);
+ VERSION_2_HEADER_MAGIC_NUMBER_SIZE + VERSION_2_HEADER_DICTIONARY_VERSION_SIZE);
default:
return NO_FLAGS;
}
@@ -79,17 +73,23 @@ const BinaryDictionaryHeaderReadingUtils::DictionaryFlags
/* static */ bool BinaryDictionaryHeaderReadingUtils::readHeaderValue(
const BinaryDictionaryInfo *const binaryDictionaryInfo,
const char *const key, int *outValue, const int outValueSize) {
- if (outValueSize <= 0 || !hasHeaderAttributes(binaryDictionaryInfo->getFormat())) {
+ if (outValueSize <= 0) {
return false;
}
const int headerSize = getHeaderSize(binaryDictionaryInfo);
int pos = getHeaderOptionsPosition(binaryDictionaryInfo->getFormat());
+ if (pos == NOT_A_DICT_POS) {
+ // The header doesn't have header options.
+ return false;
+ }
while (pos < headerSize) {
if(ByteArrayUtils::compareStringInBufferWithCharArray(
binaryDictionaryInfo->getDictBuf(), key, headerSize - pos, &pos) == 0) {
// The key was found.
- ByteArrayUtils::readStringAndAdvancePosition(
+ const int length = ByteArrayUtils::readStringAndAdvancePosition(
binaryDictionaryInfo->getDictBuf(), outValueSize, outValue, &pos);
+ // Add a 0 terminator to the string.
+ outValue[length < outValueSize ? length : outValueSize - 1] = '\0';
return true;
}
ByteArrayUtils::advancePositionToBehindString(
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_header_reading_utils.h b/native/jni/src/suggest/core/dictionary/binary_dictionary_header_reading_utils.h
index 49ed2b9cc..61748227e 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_header_reading_utils.h
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_header_reading_utils.h
@@ -48,27 +48,15 @@ class BinaryDictionaryHeaderReadingUtils {
return (flags & FRENCH_LIGATURE_PROCESSING_FLAG) != 0;
}
- static AK_FORCE_INLINE bool hasHeaderAttributes(
- const BinaryDictionaryFormatUtils::FORMAT_VERSION format) {
- // Only format 2 and above have header attributes as {key,value} string pairs.
- switch (format) {
- case BinaryDictionaryFormatUtils::VERSION_2:
- return true;
- break;
- default:
- return false;
- }
- }
-
static AK_FORCE_INLINE int getHeaderOptionsPosition(
- const BinaryDictionaryFormatUtils::FORMAT_VERSION format) {
- switch (format) {
- case BinaryDictionaryFormatUtils::VERSION_2:
- return VERSION_2_MAGIC_NUMBER_SIZE + VERSION_2_DICTIONARY_VERSION_SIZE
- + VERSION_2_DICTIONARY_FLAG_SIZE + VERSION_2_DICTIONARY_HEADER_SIZE_SIZE;
+ const BinaryDictionaryFormatUtils::FORMAT_VERSION dictionaryFormat) {
+ switch (getHeaderVersion(dictionaryFormat)) {
+ case HEADER_VERSION_2:
+ return VERSION_2_HEADER_MAGIC_NUMBER_SIZE + VERSION_2_HEADER_DICTIONARY_VERSION_SIZE
+ + VERSION_2_HEADER_FLAG_SIZE + VERSION_2_HEADER_SIZE_FIELD_SIZE;
break;
default:
- return 0;
+ return NOT_A_DICT_POS;
}
}
@@ -82,12 +70,15 @@ class BinaryDictionaryHeaderReadingUtils {
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BinaryDictionaryHeaderReadingUtils);
- static const int FORMAT_VERSION_1_HEADER_SIZE;
+ enum HEADER_VERSION {
+ HEADER_VERSION_2,
+ UNKNOWN_HEADER_VERSION
+ };
- static const int VERSION_2_MAGIC_NUMBER_SIZE;
- static const int VERSION_2_DICTIONARY_VERSION_SIZE;
- static const int VERSION_2_DICTIONARY_FLAG_SIZE;
- static const int VERSION_2_DICTIONARY_HEADER_SIZE_SIZE;
+ static const int VERSION_2_HEADER_MAGIC_NUMBER_SIZE;
+ static const int VERSION_2_HEADER_DICTIONARY_VERSION_SIZE;
+ static const int VERSION_2_HEADER_FLAG_SIZE;
+ static const int VERSION_2_HEADER_SIZE_FIELD_SIZE;
static const DictionaryFlags NO_FLAGS;
// Flags for special processing
@@ -97,6 +88,18 @@ class BinaryDictionaryHeaderReadingUtils {
static const DictionaryFlags SUPPORTS_DYNAMIC_UPDATE_FLAG;
static const DictionaryFlags FRENCH_LIGATURE_PROCESSING_FLAG;
static const DictionaryFlags CONTAINS_BIGRAMS_FLAG;
+
+ static HEADER_VERSION getHeaderVersion(
+ const BinaryDictionaryFormatUtils::FORMAT_VERSION formatVersion) {
+ switch(formatVersion) {
+ case BinaryDictionaryFormatUtils::VERSION_2:
+ // Fall through
+ case BinaryDictionaryFormatUtils::VERSION_3:
+ return HEADER_VERSION_2;
+ default:
+ return UNKNOWN_HEADER_VERSION;
+ }
+ }
};
}
#endif /* LATINIME_DICTIONARY_HEADER_READING_UTILS_H */
diff --git a/native/jni/src/suggest/core/dictionary/binary_dictionary_info.h b/native/jni/src/suggest/core/dictionary/binary_dictionary_info.h
index 7cb31440a..cbea18f90 100644
--- a/native/jni/src/suggest/core/dictionary/binary_dictionary_info.h
+++ b/native/jni/src/suggest/core/dictionary/binary_dictionary_info.h
@@ -20,23 +20,27 @@
#include <stdint.h>
#include "defines.h"
+#include "jni.h"
#include "suggest/core/dictionary/binary_dictionary_format_utils.h"
#include "suggest/core/dictionary/binary_dictionary_header.h"
#include "suggest/policyimpl/dictionary/dictionary_structure_policy_factory.h"
+#include "utils/log_utils.h"
namespace latinime {
class BinaryDictionaryInfo {
public:
- BinaryDictionaryInfo(const uint8_t *const dictBuf, const int dictSize, const int mmapFd,
- const int dictBufOffset, const bool isUpdatable)
+ AK_FORCE_INLINE BinaryDictionaryInfo(JNIEnv *env, const uint8_t *const dictBuf,
+ const int dictSize, const int mmapFd, const int dictBufOffset, const bool isUpdatable)
: mDictBuf(dictBuf), mDictSize(dictSize), mMmapFd(mmapFd),
mDictBufOffset(dictBufOffset), mIsUpdatable(isUpdatable),
mDictionaryFormat(BinaryDictionaryFormatUtils::detectFormatVersion(
mDictBuf, mDictSize)),
mDictionaryHeader(this), mDictRoot(mDictBuf + mDictionaryHeader.getSize()),
mStructurePolicy(DictionaryStructurePolicyFactory::getDictionaryStructurePolicy(
- mDictionaryFormat)) {}
+ mDictionaryFormat)) {
+ logDictionaryInfo(env);
+ }
AK_FORCE_INLINE const uint8_t *getDictBuf() const {
return mDictBuf;
@@ -88,6 +92,33 @@ class BinaryDictionaryInfo {
const BinaryDictionaryHeader mDictionaryHeader;
const uint8_t *const mDictRoot;
const DictionaryStructurePolicy *const mStructurePolicy;
+
+ AK_FORCE_INLINE void logDictionaryInfo(JNIEnv *const env) const {
+ const int BUFFER_SIZE = 16;
+ int dictionaryIdCodePointBuffer[BUFFER_SIZE];
+ int versionStringCodePointBuffer[BUFFER_SIZE];
+ int dateStringCodePointBuffer[BUFFER_SIZE];
+ mDictionaryHeader.readHeaderValueOrQuestionMark("dictionary",
+ dictionaryIdCodePointBuffer, BUFFER_SIZE);
+ mDictionaryHeader.readHeaderValueOrQuestionMark("version",
+ versionStringCodePointBuffer, BUFFER_SIZE);
+ mDictionaryHeader.readHeaderValueOrQuestionMark("date",
+ dateStringCodePointBuffer, BUFFER_SIZE);
+
+ char dictionaryIdCharBuffer[BUFFER_SIZE];
+ char versionStringCharBuffer[BUFFER_SIZE];
+ char dateStringCharBuffer[BUFFER_SIZE];
+ intArrayToCharArray(dictionaryIdCodePointBuffer, BUFFER_SIZE,
+ dictionaryIdCharBuffer, BUFFER_SIZE);
+ intArrayToCharArray(versionStringCodePointBuffer, BUFFER_SIZE,
+ versionStringCharBuffer, BUFFER_SIZE);
+ intArrayToCharArray(dateStringCodePointBuffer, BUFFER_SIZE,
+ dateStringCharBuffer, BUFFER_SIZE);
+
+ LogUtils::logToJava(env,
+ "Dictionary info: dictionary = %s ; version = %s ; date = %s ; filesize = %i",
+ dictionaryIdCharBuffer, versionStringCharBuffer, dateStringCharBuffer, mDictSize);
+ }
};
}
#endif /* LATINIME_BINARY_DICTIONARY_INFO_H */
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index 675b54972..f520a75b1 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -22,6 +22,7 @@
#include <stdint.h>
#include "defines.h"
+#include "jni.h"
#include "suggest/core/dictionary/bigram_dictionary.h"
#include "suggest/core/dictionary/binary_format.h"
#include "suggest/core/session/dic_traverse_session.h"
@@ -32,8 +33,9 @@
namespace latinime {
-Dictionary::Dictionary(void *dict, int dictSize, int mmapFd, int dictBufOffset, bool isUpdatable)
- : mBinaryDictionaryInfo(static_cast<const uint8_t *>(dict), dictSize, mmapFd,
+Dictionary::Dictionary(JNIEnv *env, void *dict, int dictSize, int mmapFd,
+ int dictBufOffset, bool isUpdatable)
+ : mBinaryDictionaryInfo(env, static_cast<const uint8_t *>(dict), dictSize, mmapFd,
dictBufOffset, isUpdatable),
mBigramDictionary(new BigramDictionary(&mBinaryDictionaryInfo)),
mGestureSuggest(new Suggest(GestureSuggestPolicyFactory::getGestureSuggestPolicy())),
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index 94579c200..1bf24a85b 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include "defines.h"
+#include "jni.h"
#include "suggest/core/dictionary/binary_dictionary_info.h"
namespace latinime {
@@ -52,7 +53,8 @@ class Dictionary {
static const int KIND_FLAG_POSSIBLY_OFFENSIVE = 0x80000000;
static const int KIND_FLAG_EXACT_MATCH = 0x40000000;
- Dictionary(void *dict, int dictSize, int mmapFd, int dictBufOffset, bool isUpdatable);
+ Dictionary(JNIEnv *env, void *dict, int dictSize, int mmapFd, int dictBufOffset,
+ bool isUpdatable);
int getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints,
diff --git a/native/jni/src/suggest/core/dictionary/terminal_attributes.h b/native/jni/src/suggest/core/dictionary/terminal_attributes.h
index cec47081e..0da6504eb 100644
--- a/native/jni/src/suggest/core/dictionary/terminal_attributes.h
+++ b/native/jni/src/suggest/core/dictionary/terminal_attributes.h
@@ -21,7 +21,6 @@
#include "suggest/core/dictionary/binary_dictionary_info.h"
#include "suggest/core/dictionary/binary_dictionary_terminal_attributes_reading_utils.h"
-#include "suggest/core/dictionary/binary_format.h"
namespace latinime {
@@ -71,28 +70,23 @@ class TerminalAttributes {
};
TerminalAttributes(const BinaryDictionaryInfo *const binaryDictionaryInfo,
- const uint8_t nodeFlags, const int shortcutPos)
- : mBinaryDictionaryInfo(binaryDictionaryInfo),
- mNodeFlags(nodeFlags), mShortcutListSizePos(shortcutPos) {}
+ const int shortcutPos)
+ : mBinaryDictionaryInfo(binaryDictionaryInfo), mShortcutListSizePos(shortcutPos) {}
inline ShortcutIterator getShortcutIterator() const {
- // The size of the shortcuts is stored here so that the whole shortcut chunk can be
- // skipped quickly, so we ignore it.
int shortcutPos = mShortcutListSizePos;
- BinaryDictionaryTerminalAttributesReadingUtils::getShortcutListSizeAndForwardPointer(
- mBinaryDictionaryInfo, &shortcutPos);
- const bool hasShortcutList = 0 != (mNodeFlags & BinaryFormat::FLAG_HAS_SHORTCUT_TARGETS);
+ const bool hasShortcutList = shortcutPos != NOT_A_DICT_POS;
+ if (hasShortcutList) {
+ BinaryDictionaryTerminalAttributesReadingUtils::getShortcutListSizeAndForwardPointer(
+ mBinaryDictionaryInfo, &shortcutPos);
+ }
+ // shortcutPos is never used if hasShortcutList is false.
return ShortcutIterator(mBinaryDictionaryInfo, shortcutPos, hasShortcutList);
}
- bool isBlacklistedOrNotAWord() const {
- return BinaryFormat::hasBlacklistedOrNotAWordFlag(mNodeFlags);
- }
-
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(TerminalAttributes);
const BinaryDictionaryInfo *const mBinaryDictionaryInfo;
- const uint8_t mNodeFlags;
const int mShortcutListSizePos;
};
} // namespace latinime
diff --git a/native/jni/src/suggest/core/layout/proximity_info_utils.h b/native/jni/src/suggest/core/layout/proximity_info_utils.h
index 54f7539d1..0e28560fc 100644
--- a/native/jni/src/suggest/core/layout/proximity_info_utils.h
+++ b/native/jni/src/suggest/core/layout/proximity_info_utils.h
@@ -117,6 +117,10 @@ class ProximityInfoUtils {
return getSquaredDistanceFloat(x, y, projectionX, projectionY);
}
+ static AK_FORCE_INLINE bool isMatchOrProximityChar(const ProximityType type) {
+ return type == MATCH_CHAR || type == PROXIMITY_CHAR || type == ADDITIONAL_PROXIMITY_CHAR;
+ }
+
// Normal distribution N(u, sigma^2).
struct NormalDistribution {
public:
diff --git a/native/jni/src/suggest/core/policy/traversal.h b/native/jni/src/suggest/core/policy/traversal.h
index c6f66f231..f26d7149e 100644
--- a/native/jni/src/suggest/core/policy/traversal.h
+++ b/native/jni/src/suggest/core/policy/traversal.h
@@ -45,7 +45,7 @@ class Traversal {
const DicNode *const dicNode) const = 0;
virtual bool needsToTraverseAllUserInput() const = 0;
virtual float getMaxSpatialDistance() const = 0;
- virtual bool allowPartialCommit() const = 0;
+ virtual bool autoCorrectsToMultiWordSuggestionIfTop() const = 0;
virtual int getDefaultExpandDicNodeSize() const = 0;
virtual int getMaxCacheSize() const = 0;
virtual bool isPossibleOmissionChildNode(const DicTraverseSession *const traverseSession,
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index 173a612be..c6da6f003 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -36,7 +36,6 @@ namespace latinime {
const int Suggest::MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT = 16;
const int Suggest::MIN_CONTINUOUS_SUGGESTION_INPUT_SIZE = 2;
const float Suggest::AUTOCORRECT_CLASSIFICATION_THRESHOLD = 0.33f;
-const int Suggest::FINAL_SCORE_PENALTY_FOR_NOT_BEST_EXACT_MATCHED_WORD = 1;
/**
* Returns a set of suggestions for the given input touch points. The commitPoint argument indicates
@@ -85,9 +84,9 @@ void Suggest::initializeSearch(DicTraverseSession *traverseSession, int commitPo
if (!traverseSession->getProximityInfoState(0)->isUsed()) {
return;
}
- if (TRAVERSAL->allowPartialCommit()) {
- commitPoint = 0;
- }
+
+ // Never auto partial commit for now.
+ commitPoint = 0;
if (traverseSession->getInputSize() > MIN_CONTINUOUS_SUGGESTION_INPUT_SIZE
&& traverseSession->isContinuousSuggestionPossible()) {
@@ -149,8 +148,17 @@ int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequen
&doubleLetterTerminalIndex, &doubleLetterLevel);
int maxScore = S_INT_MIN;
- int bestExactMatchedNodeTerminalIndex = -1;
- int bestExactMatchedNodeOutputWordIndex = -1;
+ // Force autocorrection for obvious long multi-word suggestions when the top suggestion is
+ // a long multiple words suggestion.
+ // TODO: Implement a smarter auto-commit method for handling multi-word suggestions.
+ // traverseSession->isPartiallyCommited() always returns false because we never auto partial
+ // commit for now.
+ const bool forceCommitMultiWords = (terminalSize > 0) ?
+ TRAVERSAL->autoCorrectsToMultiWordSuggestionIfTop()
+ && (traverseSession->isPartiallyCommited()
+ || (traverseSession->getInputSize()
+ >= MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT
+ && terminals[0].hasMultipleWords())) : false;
// Output suggestion results here
for (int terminalIndex = 0; terminalIndex < terminalSize && outputWordIndex < MAX_RESULTS;
++terminalIndex) {
@@ -162,8 +170,6 @@ int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequen
terminalIndex, doubleLetterTerminalIndex, doubleLetterLevel);
const float compoundDistance = terminalDicNode->getCompoundDistance(languageWeight)
+ doubleLetterCost;
- const TerminalAttributes terminalAttributes(traverseSession->getBinaryDictionaryInfo(),
- terminalDicNode->getFlags(), terminalDicNode->getAttributesPos());
const bool isPossiblyOffensiveWord = terminalDicNode->getProbability() <= 0;
const bool isExactMatch = terminalDicNode->isExactMatch();
const bool isFirstCharUppercase = terminalDicNode->isFirstCharUppercase();
@@ -176,60 +182,43 @@ int Suggest::outputSuggestions(DicTraverseSession *traverseSession, int *frequen
| (isSafeExactMatch ? Dictionary::KIND_FLAG_EXACT_MATCH : 0);
// Entries that are blacklisted or do not represent a word should not be output.
- const bool isValidWord = !terminalAttributes.isBlacklistedOrNotAWord();
+ const bool isValidWord = !terminalDicNode->isBlacklistedOrNotAWord();
// Increase output score of top typing suggestion to ensure autocorrection.
// TODO: Better integration with java side autocorrection logic.
- // Force autocorrection for obvious long multi-word suggestions.
- const bool isForceCommitMultiWords = TRAVERSAL->allowPartialCommit()
- && (traverseSession->isPartiallyCommited()
- || (traverseSession->getInputSize() >= MIN_LEN_FOR_MULTI_WORD_AUTOCORRECT
- && terminalDicNode->hasMultipleWords()));
-
const int finalScore = SCORING->calculateFinalScore(
compoundDistance, traverseSession->getInputSize(),
- isForceCommitMultiWords || (isValidWord && SCORING->doesAutoCorrectValidWord()));
+ terminalDicNode->isExactMatch()
+ || (forceCommitMultiWords && terminalDicNode->hasMultipleWords())
+ || (isValidWord && SCORING->doesAutoCorrectValidWord()));
maxScore = max(maxScore, finalScore);
- if (TRAVERSAL->allowPartialCommit()) {
- // Index for top typing suggestion should be 0.
- if (isValidWord && outputWordIndex == 0) {
- terminalDicNode->outputSpacePositionsResult(spaceIndices);
- }
+ // TODO: Implement a smarter auto-commit method for handling multi-word suggestions.
+ // Index for top typing suggestion should be 0.
+ if (isValidWord && outputWordIndex == 0) {
+ terminalDicNode->outputSpacePositionsResult(spaceIndices);
}
// Don't output invalid words. However, we still need to submit their shortcuts if any.
if (isValidWord) {
outputTypes[outputWordIndex] = Dictionary::KIND_CORRECTION | outputTypeFlags;
frequencies[outputWordIndex] = finalScore;
- if (isSafeExactMatch) {
- // Demote exact matches that are not the highest probable node among all exact
- // matches.
- const bool isBestTerminal = bestExactMatchedNodeTerminalIndex < 0
- || terminals[bestExactMatchedNodeTerminalIndex].getProbability()
- < terminalDicNode->getProbability();
- const int outputWordIndexToBeDemoted = isBestTerminal ?
- bestExactMatchedNodeOutputWordIndex : outputWordIndex;
- if (outputWordIndexToBeDemoted >= 0) {
- frequencies[outputWordIndexToBeDemoted] -=
- FINAL_SCORE_PENALTY_FOR_NOT_BEST_EXACT_MATCHED_WORD;
- }
- if (isBestTerminal) {
- // Updates the best exact matched node index.
- bestExactMatchedNodeTerminalIndex = terminalIndex;
- // Updates the best exact matched output word index.
- bestExactMatchedNodeOutputWordIndex = outputWordIndex;
- }
- }
// Populate the outputChars array with the suggested word.
const int startIndex = outputWordIndex * MAX_WORD_LENGTH;
terminalDicNode->outputResult(&outputCodePoints[startIndex]);
++outputWordIndex;
}
- const bool sameAsTyped = TRAVERSAL->sameAsTyped(traverseSession, terminalDicNode);
- outputWordIndex = ShortcutUtils::outputShortcuts(&terminalAttributes, outputWordIndex,
- finalScore, outputCodePoints, frequencies, outputTypes, sameAsTyped);
+ if (!terminalDicNode->hasMultipleWords()) {
+ const TerminalAttributes terminalAttributes(traverseSession->getBinaryDictionaryInfo(),
+ terminalDicNode->getAttributesPos());
+ // Shortcut is not supported for multiple words suggestions.
+ // TODO: Check shortcuts during traversal for multiple words suggestions.
+ const bool sameAsTyped = TRAVERSAL->sameAsTyped(traverseSession, terminalDicNode);
+ outputWordIndex = ShortcutUtils::outputShortcuts(&terminalAttributes, outputWordIndex,
+ finalScore, outputCodePoints, frequencies, outputTypes, sameAsTyped);
+
+ }
DicNode::managedDelete(terminalDicNode);
}
diff --git a/native/jni/src/suggest/core/suggest.h b/native/jni/src/suggest/core/suggest.h
index 752bde9ac..875cbe4e0 100644
--- a/native/jni/src/suggest/core/suggest.h
+++ b/native/jni/src/suggest/core/suggest.h
@@ -82,8 +82,6 @@ class Suggest : public SuggestInterface {
// Threshold for autocorrection classifier
static const float AUTOCORRECT_CLASSIFICATION_THRESHOLD;
- // Final score penalty to exact match words that are not the most probable exact match.
- static const int FINAL_SCORE_PENALTY_FOR_NOT_BEST_EXACT_MATCHED_WORD;
const Traversal *const TRAVERSAL;
const Scoring *const SCORING;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_policy_factory.h b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_policy_factory.h
index 5070651cb..70dad67e8 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_policy_factory.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/dictionary_structure_policy_factory.h
@@ -30,10 +30,11 @@ class DictionaryStructurePolicyFactory {
static const DictionaryStructurePolicy *getDictionaryStructurePolicy(
const BinaryDictionaryFormatUtils::FORMAT_VERSION dictionaryFormat) {
switch (dictionaryFormat) {
- case BinaryDictionaryFormatUtils::VERSION_1:
- // Fall through
case BinaryDictionaryFormatUtils::VERSION_2:
return PatriciaTriePolicy::getInstance();
+ case BinaryDictionaryFormatUtils::VERSION_3:
+ // TODO: support version 3 dictionaries.
+ return 0;
default:
ASSERT(false);
return 0;
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
index 5ae396e64..ef144e00a 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
+++ b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
@@ -23,6 +23,7 @@
#include "suggest/core/dicnode/dic_node.h"
#include "suggest/core/dicnode/dic_node_vector.h"
#include "suggest/core/layout/proximity_info_state.h"
+#include "suggest/core/layout/proximity_info_utils.h"
#include "suggest/core/policy/traversal.h"
#include "suggest/core/session/dic_traverse_session.h"
#include "suggest/policyimpl/typing/scoring_params.h"
@@ -136,7 +137,7 @@ class TypingTraversal : public Traversal {
return ScoringParams::MAX_SPATIAL_DISTANCE;
}
- AK_FORCE_INLINE bool allowPartialCommit() const {
+ AK_FORCE_INLINE bool autoCorrectsToMultiWordSuggestionIfTop() const {
return true;
}
@@ -159,7 +160,7 @@ class TypingTraversal : public Traversal {
const DicNode *const dicNode) const {
const ProximityType proximityType =
getProximityType(traverseSession, parentDicNode, dicNode);
- if (!DicNodeUtils::isProximityChar(proximityType)) {
+ if (!ProximityInfoUtils::isMatchOrProximityChar(proximityType)) {
return false;
}
return true;
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
index e098f353e..830aa80de 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
+++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.h
@@ -169,12 +169,7 @@ class TypingWeighting : public Weighting {
float getTerminalLanguageCost(const DicTraverseSession *const traverseSession,
const DicNode *const dicNode, const float dicNodeLanguageImprobability) const {
- // We promote exact matches here to prevent them from being pruned. The final score of
- // exact match nodes might be demoted later in Suggest::outputSuggestions if there are
- // multiple exact matches.
- const float languageImprobability = (dicNode->isExactMatch()) ?
- 0.0f : dicNodeLanguageImprobability;
- return languageImprobability * ScoringParams::DISTANCE_WEIGHT_LANGUAGE;
+ return dicNodeLanguageImprobability * ScoringParams::DISTANCE_WEIGHT_LANGUAGE;
}
AK_FORCE_INLINE bool needsToNormalizeCompoundDistance() const {
diff --git a/native/jni/src/utils/log_utils.cpp b/native/jni/src/utils/log_utils.cpp
new file mode 100644
index 000000000..5ab2b2862
--- /dev/null
+++ b/native/jni/src/utils/log_utils.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#include "log_utils.h"
+
+#include <cstdio>
+#include <stdarg.h>
+
+#include "defines.h"
+
+namespace latinime {
+ /* static */ void LogUtils::logToJava(JNIEnv *const env, const char *const format, ...) {
+ static const char *TAG = "LatinIME:LogUtils";
+ const jclass androidUtilLogClass = env->FindClass("android/util/Log");
+ if (!androidUtilLogClass) {
+ // If we can't find the class, we are probably in off-device testing, and
+ // it's expected. Regardless, logging is not essential to functionality, so
+ // we should just return. However, FindClass has thrown an exception behind
+ // our back and there is no way to prevent it from doing that, so we clear
+ // the exception before we return.
+ env->ExceptionClear();
+ return;
+ }
+ const jmethodID logDotIMethodId = env->GetStaticMethodID(androidUtilLogClass, "i",
+ "(Ljava/lang/String;Ljava/lang/String;)I");
+ if (!logDotIMethodId) {
+ env->ExceptionClear();
+ if (androidUtilLogClass) env->DeleteLocalRef(androidUtilLogClass);
+ return;
+ }
+ const jstring javaTag = env->NewStringUTF(TAG);
+
+ static const int DEFAULT_LINE_SIZE = 128;
+ char fixedSizeCString[DEFAULT_LINE_SIZE];
+ va_list argList;
+ va_start(argList, format);
+ // Get the necessary size. Add 1 for the 0 terminator.
+ const int size = vsnprintf(fixedSizeCString, DEFAULT_LINE_SIZE, format, argList) + 1;
+ va_end(argList);
+
+ jstring javaString;
+ if (size <= DEFAULT_LINE_SIZE) {
+ // The buffer was large enough.
+ javaString = env->NewStringUTF(fixedSizeCString);
+ } else {
+ // The buffer was not large enough.
+ va_start(argList, format);
+ char variableSizeCString[size];
+ vsnprintf(variableSizeCString, size, format, argList);
+ va_end(argList);
+ javaString = env->NewStringUTF(variableSizeCString);
+ }
+
+ env->CallStaticIntMethod(androidUtilLogClass, logDotIMethodId, javaTag, javaString);
+ if (javaString) env->DeleteLocalRef(javaString);
+ if (javaTag) env->DeleteLocalRef(javaTag);
+ if (androidUtilLogClass) env->DeleteLocalRef(androidUtilLogClass);
+ }
+}
diff --git a/native/jni/src/utils/log_utils.h b/native/jni/src/utils/log_utils.h
new file mode 100644
index 000000000..6ac16d91a
--- /dev/null
+++ b/native/jni/src/utils/log_utils.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifndef LATINIME_LOG_UTILS_H
+#define LATINIME_LOG_UTILS_H
+
+#include "defines.h"
+#include "jni.h"
+
+namespace latinime {
+
+class LogUtils {
+ public:
+ static void logToJava(JNIEnv *const env, const char *const format, ...)
+#ifdef __GNUC__
+ __attribute__ ((format (printf, 2, 3)))
+#endif // __GNUC__
+ ;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LogUtils);
+};
+} // namespace latinime
+#endif // LATINIME_LOG_UTILS_H
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java
index b193e66dc..9ad81c01d 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateMultiTouchTests.java
@@ -60,7 +60,7 @@ public class KeyboardStateMultiTouchTests extends KeyboardStateTestsBase {
// Chording input in shift locked.
public void testChordingShiftLocked() {
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press shift key and hold, enter into choring shift state.
@@ -119,7 +119,7 @@ public class KeyboardStateMultiTouchTests extends KeyboardStateTestsBase {
// Load keyboard
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -137,7 +137,7 @@ public class KeyboardStateMultiTouchTests extends KeyboardStateTestsBase {
// Load keyboard
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -196,7 +196,7 @@ public class KeyboardStateMultiTouchTests extends KeyboardStateTestsBase {
// Load keyboard
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -216,7 +216,7 @@ public class KeyboardStateMultiTouchTests extends KeyboardStateTestsBase {
// Load keyboard
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -397,29 +397,29 @@ public class KeyboardStateMultiTouchTests extends KeyboardStateTestsBase {
public void testLongPressShiftAndChording() {
// Long press shift key, enter maybe shift locked.
- longPressKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+ longPressShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
// Press/release letter key, remain in manual shifted.
chordingPressAndReleaseKey('A', ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
// Release shift key, back to alphabet (not shift locked).
releaseKey(CODE_SHIFT, ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Long press shift key, enter maybe alphabet.
- longPressKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCK_SHIFTED);
+ longPressShiftKey(ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCK_SHIFTED);
// Press/release letter key, remain in manual shifted.
chordingPressAndReleaseKey('A', ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCK_SHIFTED);
// Release shift key, back to shift locked (not alphabet).
releaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCKED);
// Long press shift key, enter alphabet
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCK_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCK_SHIFTED,
ALPHABET_UNSHIFTED);
// Press/release shift key, enter alphabet shifted.
pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
// Long press shift key, enter maybe alphabet.
- longPressKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+ longPressShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
// Press/release letter key, remain in manual shifted.
chordingPressAndReleaseKey('A', ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
// Release shift key, back to alphabet shifted (not alphabet).
@@ -430,7 +430,7 @@ public class KeyboardStateMultiTouchTests extends KeyboardStateTestsBase {
// Load keyboard, should be in automatic shifted.
loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED);
// Long press shift key, enter maybe shift locked.
- longPressKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
+ longPressShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
// Press/release letter key, remain in manual shifted.
chordingPressAndReleaseKey('A', ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
// Release shift key, back to alphabet (not shift locked).
@@ -449,7 +449,7 @@ public class KeyboardStateMultiTouchTests extends KeyboardStateTestsBase {
// releaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED);
//
// // Long press shift key, enter alphabet shift locked.
-// longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+// longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
// ALPHABET_SHIFT_LOCKED);
// // First shift key tap.
// pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
index d5b9d1dfd..c7ac76d93 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateSingleTouchTests.java
@@ -91,7 +91,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Switching between alphabet shift locked and symbols.
public void testAlphabetShiftLockedAndSymbols() {
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
@@ -133,7 +133,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Automatic switch back to alphabet shift locked test by space key.
public void testSwitchBackBySpaceShiftLocked() {
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
@@ -196,13 +196,13 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Load keyboard, should be in alphabet.
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release shift key, back to alphabet.
pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release letter key, remain in shift locked.
pressAndReleaseKey('A', ALPHABET_SHIFT_LOCKED, ALPHABET_SHIFT_LOCKED);
@@ -212,16 +212,16 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Long press shift key, back to alphabet.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCK_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCK_SHIFTED,
ALPHABET_UNSHIFTED);
// Press/release shift key, enter alphabet shifted.
pressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release shift key, back to alphabet.
pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED);
@@ -231,7 +231,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Load keyboard, should be in automatic shifted.
loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release shift key, back to alphabet.
pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED);
@@ -293,12 +293,12 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
updateShiftState(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Update shift state, remained in alphabet shift locked.
updateShiftState(ALPHABET_SHIFT_LOCKED);
// Long press shift key, back to alphabet.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCK_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCK_SHIFTED,
ALPHABET_UNSHIFTED);
// Press/release "?123" key, enter into symbols.
@@ -326,12 +326,12 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
updateShiftState(ALPHABET_AUTOMATIC_SHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Update shift state, remained in alphabet shift locked (not automatic shifted).
updateShiftState(ALPHABET_SHIFT_LOCKED);
// Long press shift key, back to alphabet.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCK_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_SHIFT_LOCK_SHIFTED,
ALPHABET_UNSHIFTED);
// Load keyboard, should be in automatic shifted.
@@ -383,7 +383,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Alphabet shift locked -> shift key + letter -> alphabet shift locked.
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press and slide from "123?" key, enter symbols.
pressAndSlideFromKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -441,7 +441,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Alphabet shift locked -> shift key + letter -> cancel -> alphabet shift locked.
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press and slide from "123?" key, enter symbols.
pressAndSlideFromKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -500,7 +500,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Load keyboard
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -517,7 +517,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Load keyboard
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -574,7 +574,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Load keyboard
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -592,7 +592,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Load keyboard
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -651,7 +651,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Load keyboard
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -670,7 +670,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Load keyboard
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -733,7 +733,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Load keyboard
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -753,7 +753,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Load keyboard
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release "?123" key, enter into symbols.
pressAndReleaseKey(CODE_SYMBOL, SYMBOLS_UNSHIFTED, SYMBOLS_UNSHIFTED);
@@ -777,7 +777,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
loadKeyboard(ALPHABET_UNSHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Change focus to new text field.
loadKeyboard(ALPHABET_UNSHIFTED);
@@ -808,7 +808,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED);
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Change focus to new text field.
loadKeyboard(ALPHABET_AUTOMATIC_SHIFTED);
@@ -852,7 +852,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
// Alphabet shift locked -> rotate -> alphabet shift locked.
// Long press shift key, enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Rotate device, remain in alphabet shift locked.
rotateDevice(ALPHABET_SHIFT_LOCKED);
@@ -936,7 +936,7 @@ public class KeyboardStateSingleTouchTests extends KeyboardStateTestsBase {
secondPressAndReleaseKey('J', ALPHABET_MANUAL_SHIFTED, ALPHABET_UNSHIFTED);
// Long press shift key to enter alphabet shift locked.
- longPressAndReleaseKey(CODE_SHIFT, ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
+ longPressAndReleaseShiftKey(ALPHABET_MANUAL_SHIFTED, ALPHABET_MANUAL_SHIFTED,
ALPHABET_SHIFT_LOCKED);
// Press/release shift key
pressAndReleaseKey(CODE_SHIFT, ALPHABET_SHIFT_LOCK_SHIFTED, ALPHABET_UNSHIFTED);
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java
index 6991d05fa..3ffd0a96a 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java
@@ -34,6 +34,11 @@ public class KeyboardStateTestsBase extends AndroidTestCase
loadKeyboard(ALPHABET_UNSHIFTED);
}
+ /**
+ * Set auto caps mode.
+ *
+ * @param autoCaps the auto cap mode.
+ */
public void setAutoCapsMode(final int autoCaps) {
mSwitcher.setAutoCapsMode(autoCaps);
}
@@ -44,17 +49,32 @@ public class KeyboardStateTestsBase extends AndroidTestCase
expected == actual);
}
+ /**
+ * Emulate update keyboard shift state.
+ *
+ * @param afterUpdate the keyboard state after updating the keyboard shift state.
+ */
public void updateShiftState(final int afterUpdate) {
mSwitcher.updateShiftState();
assertLayout("afterUpdate", afterUpdate, mSwitcher.getLayoutId());
}
+ /**
+ * Emulate load default keyboard.
+ *
+ * @param afterLoad the keyboard state after loading default keyboard.
+ */
public void loadKeyboard(final int afterLoad) {
mSwitcher.loadKeyboard();
mSwitcher.updateShiftState();
assertLayout("afterLoad", afterLoad, mSwitcher.getLayoutId());
}
+ /**
+ * Emulate rotate device.
+ *
+ * @param afterRotate the keyboard state after rotating device.
+ */
public void rotateDevice(final int afterRotate) {
mSwitcher.saveKeyboardState();
mSwitcher.loadKeyboard();
@@ -67,45 +87,97 @@ public class KeyboardStateTestsBase extends AndroidTestCase
assertLayout("afterPress", afterPress, mSwitcher.getLayoutId());
}
+ /**
+ * Emulate key press.
+ *
+ * @param code the key code to press.
+ * @param afterPress the keyboard state after pressing the key.
+ */
public void pressKey(final int code, final int afterPress) {
mSwitcher.expireDoubleTapTimeout();
pressKeyWithoutTimerExpire(code, true, afterPress);
}
+ /**
+ * Emulate key release and register.
+ *
+ * @param code the key code to release and register
+ * @param afterRelease the keyboard state after releasing the key.
+ */
public void releaseKey(final int code, final int afterRelease) {
mSwitcher.onCodeInput(code);
mSwitcher.onReleaseKey(code, NOT_SLIDING);
assertLayout("afterRelease", afterRelease, mSwitcher.getLayoutId());
}
+ /**
+ * Emulate key press and release.
+ *
+ * @param code the key code to press and release.
+ * @param afterPress the keyboard state after pressing the key.
+ * @param afterRelease the keyboard state after releasing the key.
+ */
public void pressAndReleaseKey(final int code, final int afterPress, final int afterRelease) {
pressKey(code, afterPress);
releaseKey(code, afterRelease);
}
+ /**
+ * Emulate chording key press.
+ *
+ * @param code the chording key code.
+ * @param afterPress the keyboard state after pressing chording key.
+ */
public void chordingPressKey(final int code, final int afterPress) {
mSwitcher.expireDoubleTapTimeout();
pressKeyWithoutTimerExpire(code, false, afterPress);
}
+ /**
+ * Emulate chording key release.
+ *
+ * @param code the cording key code.
+ * @param afterRelease the keyboard state after releasing chording key.
+ */
public void chordingReleaseKey(final int code, final int afterRelease) {
mSwitcher.onCodeInput(code);
mSwitcher.onReleaseKey(code, NOT_SLIDING);
assertLayout("afterRelease", afterRelease, mSwitcher.getLayoutId());
}
+ /**
+ * Emulate chording key press and release.
+ *
+ * @param code the chording key code.
+ * @param afterPress the keyboard state after pressing chording key.
+ * @param afterRelease the keyboard state after releasing chording key.
+ */
public void chordingPressAndReleaseKey(final int code, final int afterPress,
final int afterRelease) {
chordingPressKey(code, afterPress);
chordingReleaseKey(code, afterRelease);
}
+ /**
+ * Emulate start of the sliding key input.
+ *
+ * @param code the key code to start sliding.
+ * @param afterPress the keyboard state after pressing the key.
+ * @param afterSlide the keyboard state after releasing the key with sliding input.
+ */
public void pressAndSlideFromKey(final int code, final int afterPress, final int afterSlide) {
pressKey(code, afterPress);
mSwitcher.onReleaseKey(code, SLIDING);
assertLayout("afterSlide", afterSlide, mSwitcher.getLayoutId());
}
+ /**
+ * Emulate end of the sliding key input.
+ *
+ * @param code the key code to stop sliding.
+ * @param afterPress the keyboard state after pressing the key.
+ * @param afterSlide the keyboard state after releasing the key and stop sliding.
+ */
public void stopSlidingOnKey(final int code, final int afterPress, final int afterSlide) {
pressKey(code, afterPress);
mSwitcher.onCodeInput(code);
@@ -114,32 +186,67 @@ public class KeyboardStateTestsBase extends AndroidTestCase
assertLayout("afterSlide", afterSlide, mSwitcher.getLayoutId());
}
+ /**
+ * Emulate cancel the sliding key input.
+ *
+ * @param afterCancelSliding the keyboard state after canceling sliding input.
+ */
public void stopSlidingAndCancel(final int afterCancelSliding) {
mSwitcher.onFinishSlidingInput();
assertLayout("afterCancelSliding", afterCancelSliding, mSwitcher.getLayoutId());
}
- public void longPressKey(final int code, final int afterPress, final int afterLongPress) {
- pressKey(code, afterPress);
+ /**
+ * Emulate long press shift key.
+ *
+ * @param afterPress the keyboard state after pressing shift key.
+ * @param afterLongPress the keyboard state after long press fired.
+ */
+ public void longPressShiftKey(final int afterPress, final int afterLongPress) {
// Long press shift key will register {@link Constants#CODE_CAPS_LOCK}. See
// {@link R.xml#key_styles_common} and its baseForShiftKeyStyle. We thus emulate the
- // behavior here.
- final int longPressCode = code == CODE_SHIFT ? Constants.CODE_CAPSLOCK : code;
- mSwitcher.onCodeInput(longPressCode);
+ // behavior that is implemented in {@link MainKeyboardView#onLongPress(PointerTracker)}.
+ pressKey(Constants.CODE_SHIFT, afterPress);
+ mSwitcher.onPressKey(Constants.CODE_CAPSLOCK, true /* isSinglePointer */);
+ mSwitcher.onCodeInput(Constants.CODE_CAPSLOCK);
assertLayout("afterLongPress", afterLongPress, mSwitcher.getLayoutId());
}
- public void longPressAndReleaseKey(final int code, final int afterPress,
- final int afterLongPress, final int afterRelease) {
- longPressKey(code, afterPress, afterLongPress);
- releaseKey(code, afterRelease);
- }
-
- public void secondPressKey(int code, int afterPress) {
+ /**
+ * Emulate long press shift key and release.
+ *
+ * @param afterPress the keyboard state after pressing shift key.
+ * @param afterLongPress the keyboard state after long press fired.
+ * @param afterRelease the keyboard state after shift key is released.
+ */
+ public void longPressAndReleaseShiftKey(final int afterPress, final int afterLongPress,
+ final int afterRelease) {
+ // Long press shift key will register {@link Constants#CODE_CAPS_LOCK}. See
+ // {@link R.xml#key_styles_common} and its baseForShiftKeyStyle. We thus emulate the
+ // behavior that is implemented in {@link MainKeyboardView#onLongPress(PointerTracker)}.
+ longPressShiftKey(afterPress, afterLongPress);
+ releaseKey(Constants.CODE_CAPSLOCK, afterRelease);
+ }
+
+ /**
+ * Emulate the second press of the double tap.
+ *
+ * @param code the key code to double tap.
+ * @param afterPress the keyboard state after pressing the second tap.
+ */
+ public void secondPressKey(final int code, final int afterPress) {
pressKeyWithoutTimerExpire(code, true, afterPress);
}
- public void secondPressAndReleaseKey(int code, int afterPress, int afterRelease) {
+ /**
+ * Emulate the second tap of the double tap.
+ *
+ * @param code the key code to double tap.
+ * @param afterPress the keyboard state after pressing the second tap.
+ * @param afterRelease the keyboard state after releasing the second tap.
+ */
+ public void secondPressAndReleaseKey(final int code, final int afterPress,
+ final int afterRelease) {
secondPressKey(code, afterPress);
releaseKey(code, afterRelease);
}
diff --git a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java
index 0e077bbbe..c0dd9933c 100644
--- a/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java
+++ b/tests/src/com/android/inputmethod/latin/RichInputConnectionAndTextRangeTests.java
@@ -16,6 +16,8 @@
package com.android.inputmethod.latin;
+import com.android.inputmethod.latin.utils.TextRange;
+
import android.inputmethodservice.InputMethodService;
import android.os.Parcel;
import android.test.AndroidTestCase;
@@ -30,8 +32,6 @@ import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputConnectionWrapper;
-import com.android.inputmethod.latin.RichInputConnection.Range;
-
import java.util.Locale;
@SmallTest
@@ -169,7 +169,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
mockInputMethodService.setInputConnection(new MockConnection("word wo", "rd", et));
et.startOffset = 0;
et.selectionStart = 7;
- Range r;
+ TextRange r;
ic.beginBatchEdit();
// basic case
@@ -241,7 +241,7 @@ public class RichInputConnectionAndTextRangeTests extends AndroidTestCase {
text.setSpan(new SuggestionSpan(Locale.ENGLISH, SUGGESTIONS1, 0 /* flags */),
10 /* start */, 16 /* end */, 0 /* flags */);
mockInputMethodService.setInputConnection(new MockConnection(text, cursorPos));
- Range r;
+ TextRange r;
SuggestionSpan[] suggestions;
r = ic.getWordRangeAtCursor(" ", 0);
diff --git a/tests/src/com/android/inputmethod/latin/WordComposerTests.java b/tests/src/com/android/inputmethod/latin/WordComposerTests.java
new file mode 100644
index 000000000..1434c6b63
--- /dev/null
+++ b/tests/src/com/android/inputmethod/latin/WordComposerTests.java
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Unit tests for WordComposer.
+ */
+@SmallTest
+public class WordComposerTests extends AndroidTestCase {
+ public void testMoveCursor() {
+ final WordComposer wc = new WordComposer();
+ final String STR_WITHIN_BMP = "abcdef";
+ wc.setComposingWord(STR_WITHIN_BMP, null);
+ assertEquals(wc.size(),
+ STR_WITHIN_BMP.codePointCount(0, STR_WITHIN_BMP.length()));
+ assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
+ wc.setCursorPositionWithinWord(2);
+ assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
+ // Move the cursor to after the 'd'
+ assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(2));
+ assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
+ // Move the cursor to after the 'e'
+ assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1));
+ assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
+ assertEquals(wc.size(), 6);
+ // Move the cursor to after the 'f'
+ assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1));
+ assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
+ // Move the cursor past the end of the word
+ assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(1));
+ assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(15));
+
+ // \uD861\uDED7 is 𨛗, a character outside the BMP
+ final String STR_WITH_SUPPLEMENTARY_CHAR = "abcde\uD861\uDED7fgh";
+ wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
+ assertEquals(wc.size(), STR_WITH_SUPPLEMENTARY_CHAR.codePointCount(0,
+ STR_WITH_SUPPLEMENTARY_CHAR.length()));
+ assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
+ wc.setCursorPositionWithinWord(3);
+ assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
+ assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(6));
+ assertTrue(wc.isCursorFrontOrMiddleOfComposingWord());
+ assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(1));
+ assertFalse(wc.isCursorFrontOrMiddleOfComposingWord());
+
+ wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
+ wc.setCursorPositionWithinWord(3);
+ assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7));
+
+ wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
+ wc.setCursorPositionWithinWord(3);
+ assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(7));
+
+ wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
+ wc.setCursorPositionWithinWord(3);
+ assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-3));
+ assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-1));
+
+ wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
+ wc.setCursorPositionWithinWord(3);
+ assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-9));
+
+ wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
+ assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(-10));
+
+ wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
+ assertFalse(wc.moveCursorByAndReturnIfInsideComposingWord(-11));
+
+ wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
+ assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0));
+
+ wc.setComposingWord(STR_WITH_SUPPLEMENTARY_CHAR, null);
+ wc.setCursorPositionWithinWord(2);
+ assertTrue(wc.moveCursorByAndReturnIfInsideComposingWord(0));
+ }
+}
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java
index cca81a0e0..55f163255 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOTests.java
@@ -51,7 +51,8 @@ import java.util.Set;
@LargeTest
public class BinaryDictIOTests extends AndroidTestCase {
private static final String TAG = BinaryDictIOTests.class.getSimpleName();
- private static final int MAX_UNIGRAMS = 100;
+ private static final int DEFAULT_MAX_UNIGRAMS = 100;
+ private static final int DEFAULT_CODE_POINT_SET_SIZE = 50;
private static final int UNIGRAM_FREQ = 10;
private static final int BIGRAM_FREQ = 50;
private static final int TOLERANCE_OF_BIGRAM_FREQ = 5;
@@ -73,13 +74,16 @@ public class BinaryDictIOTests extends AndroidTestCase {
new FormatSpec.FormatOptions(3, true /* supportsDynamicUpdate */);
public BinaryDictIOTests() {
- super();
+ this(System.currentTimeMillis(), DEFAULT_MAX_UNIGRAMS);
+ }
- final long time = System.currentTimeMillis();
- Log.e(TAG, "Testing dictionary: seed is " + time);
- final Random random = new Random(time);
+ public BinaryDictIOTests(final long seed, final int maxUnigrams) {
+ super();
+ Log.e(TAG, "Testing dictionary: seed is " + seed);
+ final Random random = new Random(seed);
sWords.clear();
- generateWords(MAX_UNIGRAMS, random);
+ final int[] codePointSet = generateCodePointSet(DEFAULT_CODE_POINT_SET_SIZE, random);
+ generateWords(maxUnigrams, random, codePointSet);
for (int i = 0; i < sWords.size(); ++i) {
sChainBigrams.put(i, new ArrayList<Integer>());
@@ -94,6 +98,23 @@ public class BinaryDictIOTests extends AndroidTestCase {
}
}
+ private int[] generateCodePointSet(final int codePointSetSize, final Random random) {
+ final int[] codePointSet = new int[codePointSetSize];
+ for (int i = codePointSet.length - 1; i >= 0; ) {
+ final int r = Math.abs(random.nextInt());
+ if (r < 0) continue;
+ // Don't insert 0~0x20, but insert any other code point.
+ // Code points are in the range 0~0x10FFFF.
+ final int candidateCodePoint = (int)(0x20 + r % (Character.MAX_CODE_POINT - 0x20));
+ // Code points between MIN_ and MAX_SURROGATE are not valid on their own.
+ if (candidateCodePoint >= Character.MIN_SURROGATE
+ && candidateCodePoint <= Character.MAX_SURROGATE) continue;
+ codePointSet[i] = candidateCodePoint;
+ --i;
+ }
+ return codePointSet;
+ }
+
// Utilities for test
/**
@@ -129,28 +150,29 @@ public class BinaryDictIOTests extends AndroidTestCase {
/**
* Generates a random word.
*/
- private String generateWord(final Random random) {
- StringBuilder builder = new StringBuilder("a");
- int count = random.nextInt() % 30; // Arbitrarily 30 chars max
- while (count > 0) {
- final long r = Math.abs(random.nextInt());
- if (r < 0) continue;
- // Don't insert 0~0x20, but insert any other code point.
- // Code points are in the range 0~0x10FFFF.
- final int candidateCodePoint = (int)(0x20 + r % (Character.MAX_CODE_POINT - 0x20));
- // Code points between MIN_ and MAX_SURROGATE are not valid on their own.
- if (candidateCodePoint >= Character.MIN_SURROGATE
- && candidateCodePoint <= Character.MAX_SURROGATE) continue;
- builder.appendCodePoint(candidateCodePoint);
- --count;
+ private String generateWord(final Random random, final int[] codePointSet) {
+ StringBuilder builder = new StringBuilder();
+ // 8 * 4 = 32 chars max, but we do it the following way so as to bias the random toward
+ // longer words. This should be closer to natural language, and more importantly, it will
+ // exercise the algorithms in dicttool much more.
+ final int count = 1 + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5)
+ + (Math.abs(random.nextInt()) % 5);
+ while (builder.length() < count) {
+ builder.appendCodePoint(codePointSet[Math.abs(random.nextInt()) % codePointSet.length]);
}
return builder.toString();
}
- private void generateWords(final int number, final Random random) {
+ private void generateWords(final int number, final Random random, final int[] codePointSet) {
final Set<String> wordSet = CollectionUtils.newHashSet();
while (wordSet.size() < number) {
- wordSet.add(generateWord(random));
+ wordSet.add(generateWord(random, codePointSet));
}
sWords.addAll(wordSet);
}
@@ -558,8 +580,9 @@ public class BinaryDictIOTests extends AndroidTestCase {
// Test a word that isn't contained within the dictionary.
final Random random = new Random((int)System.currentTimeMillis());
+ final int[] codePointSet = generateCodePointSet(DEFAULT_CODE_POINT_SET_SIZE, random);
for (int i = 0; i < 1000; ++i) {
- final String word = generateWord(random);
+ final String word = generateWord(random, codePointSet);
if (sWords.indexOf(word) != -1) continue;
runGetTerminalPosition(buffer, word, i, false);
}
diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
index d33142ce0..9331da44b 100644
--- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
+++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtilsTests.java
@@ -44,9 +44,10 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
private static final String TAG = BinaryDictIOUtilsTests.class.getSimpleName();
private static final FormatSpec.FormatOptions FORMAT_OPTIONS =
new FormatSpec.FormatOptions(3, true);
- private static final int MAX_UNIGRAMS = 1500;
private static final ArrayList<String> sWords = CollectionUtils.newArrayList();
+ public static final int DEFAULT_MAX_UNIGRAMS = 1500;
+ private final int mMaxUnigrams;
private static final String[] CHARACTERS = {
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
@@ -57,15 +58,17 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
};
public BinaryDictIOUtilsTests() {
- this(System.currentTimeMillis());
+ // 1500 is the default max unigrams
+ this(System.currentTimeMillis(), DEFAULT_MAX_UNIGRAMS);
}
- public BinaryDictIOUtilsTests(final long seed) {
+ public BinaryDictIOUtilsTests(final long seed, final int maxUnigrams) {
super();
- Log.d(TAG, "Seed for test is " + seed);
+ Log.d(TAG, "Seed for test is " + seed + ", maxUnigrams is " + maxUnigrams);
+ mMaxUnigrams = maxUnigrams;
final Random random = new Random(seed);
sWords.clear();
- for (int i = 0; i < MAX_UNIGRAMS; ++i) {
+ for (int i = 0; i < maxUnigrams; ++i) {
sWords.add(generateWord(random.nextInt()));
}
}
@@ -395,6 +398,6 @@ public class BinaryDictIOUtilsTests extends AndroidTestCase {
Log.d(TAG, "max = " + ((double)maxTimeToInsert/1000000) + " ms.");
Log.d(TAG, "min = " + ((double)minTimeToInsert/1000000) + " ms.");
- Log.d(TAG, "avg = " + ((double)sum/MAX_UNIGRAMS/1000000) + " ms.");
+ Log.d(TAG, "avg = " + ((double)sum/mMaxUnigrams/1000000) + " ms.");
}
}
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java
index 7b311c3ec..cacee5268 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Dicttool.java
@@ -72,15 +72,21 @@ public class Dicttool {
return command;
}
- private void execute(final String[] arguments) {
+ /**
+ * Executes the specified command with the specified arguments.
+ * @param arguments the arguments passed to dicttool.
+ * @return 0 for success, an error code otherwise (always 1 at the moment)
+ */
+ private int execute(final String[] arguments) {
final Command command = getCommand(arguments);
try {
command.run();
+ return 0;
} catch (Exception e) {
System.out.println("Exception while processing command "
+ command.getClass().getSimpleName() + " : " + e);
e.printStackTrace();
- return;
+ return 1;
}
}
@@ -89,6 +95,7 @@ public class Dicttool {
help();
return;
}
- new Dicttool().execute(arguments);
+ // Exit with the success/error code from #execute() as status.
+ System.exit(new Dicttool().execute(arguments));
}
}
diff --git a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java
index 827c5e3a9..972b6e7e6 100644
--- a/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java
+++ b/tools/dicttool/src/com/android/inputmethod/latin/dicttool/Test.java
@@ -16,36 +16,93 @@
package com.android.inputmethod.latin.dicttool;
+import com.android.inputmethod.latin.makedict.BinaryDictIOTests;
import com.android.inputmethod.latin.makedict.BinaryDictIOUtilsTests;
import com.android.inputmethod.latin.makedict.BinaryDictInputOutputTest;
import com.android.inputmethod.latin.makedict.FusionDictionaryTest;
-import com.android.inputmethod.latin.makedict.UnsupportedFormatException;
-import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
/**
* Dicttool command implementing self-tests.
*/
public class Test extends Dicttool.Command {
public static final String COMMAND = "test";
+ private long mSeed = System.currentTimeMillis();
+ private int mMaxUnigrams = BinaryDictIOUtilsTests.DEFAULT_MAX_UNIGRAMS;
+
+ private static final Class<?>[] sClassesToTest = {
+ BinaryDictOffdeviceUtilsTests.class,
+ FusionDictionaryTest.class,
+ BinaryDictInputOutputTest.class,
+ BinaryDictIOUtilsTests.class,
+ BinaryDictIOTests.class
+ };
+ private ArrayList<Method> mAllTestMethods = new ArrayList<Method>();
+ private ArrayList<String> mUsedTestMethods = new ArrayList<String>();
public Test() {
+ for (final Class<?> c : sClassesToTest) {
+ for (final Method m : c.getDeclaredMethods()) {
+ if (m.getName().startsWith("test") && Void.TYPE == m.getReturnType()
+ && 0 == m.getParameterTypes().length) {
+ mAllTestMethods.add(m);
+ }
+ }
+ }
}
@Override
public String getHelp() {
- return "test";
+ final StringBuilder s = new StringBuilder("test [-s seed] [-m maxUnigrams] [testName...]\n"
+ + "If seed is not specified, the current time is used.\nTest list is:\n");
+ for (final Method m : mAllTestMethods) {
+ s.append(" ");
+ s.append(m.getName());
+ s.append("\n");
+ }
+ return s.toString();
}
@Override
- public void run() throws IOException, UnsupportedFormatException {
- test();
+ public void run() throws IllegalAccessException, InstantiationException,
+ InvocationTargetException {
+ int i = 0;
+ while (i < mArgs.length) {
+ final String arg = mArgs[i++];
+ if ("-s".equals(arg)) {
+ mSeed = Long.parseLong(mArgs[i++]);
+ } else if ("-m".equals(arg)) {
+ mMaxUnigrams = Integer.parseInt(mArgs[i++]);
+ } else {
+ mUsedTestMethods.add(arg);
+ }
+ }
+ runChosenTests();
}
- private void test() throws IOException, UnsupportedFormatException {
- new BinaryDictOffdeviceUtilsTests().testGetRawDictWorks();
- new FusionDictionaryTest().testFusion();
- new BinaryDictInputOutputTest().testFlattenNodes();
- new BinaryDictIOUtilsTests().testRandomWords();
+ private void runChosenTests() throws IllegalAccessException, InstantiationException,
+ InvocationTargetException {
+ for (final Method m : mAllTestMethods) {
+ final Class<?> declaringClass = m.getDeclaringClass();
+ if (!mUsedTestMethods.isEmpty() && !mUsedTestMethods.contains(m.getName())) continue;
+ // Some of the test classes expose a two-argument constructor, taking a long as a
+ // seed for Random, and an int for a vocabulary size to test the dictionary with. They
+ // correspond respectively to the -s and -m numerical arguments to this command, which
+ // are stored in mSeed and mMaxUnigrams. If the two-arguments constructor is present,
+ // then invoke it; otherwise, invoke the default constructor.
+ Constructor<?> twoArgsConstructor = null;
+ try {
+ twoArgsConstructor = declaringClass.getDeclaredConstructor(Long.TYPE, Integer.TYPE);
+ } catch (NoSuchMethodException e) {
+ // No constructor with two args
+ }
+ final Object instance = null == twoArgsConstructor ? declaringClass.newInstance()
+ : twoArgsConstructor.newInstance(mSeed, mMaxUnigrams);
+ m.invoke(instance);
+ }
}
}
diff --git a/tools/maketext/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl b/tools/maketext/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl
index 2fc97b5c6..479a766fb 100644
--- a/tools/maketext/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl
+++ b/tools/maketext/res/com/android/inputmethod/keyboard/internal/KeyboardTextsSet.tmpl
@@ -20,7 +20,7 @@ import android.content.Context;
import android.content.res.Resources;
import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.latin.CollectionUtils;
+import com.android.inputmethod.latin.utils.CollectionUtils;
import java.util.HashMap;
diff --git a/tools/maketext/res/values-az/donottranslate-more-keys.xml b/tools/maketext/res/values-az/donottranslate-more-keys.xml
new file mode 100644
index 000000000..db1784c17
--- /dev/null
+++ b/tools/maketext/res/values-az/donottranslate-more-keys.xml
@@ -0,0 +1,59 @@
+<?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">
+ <!-- U+00E2: "â" LATIN SMALL LETTER A WITH CIRCUMFLEX -->
+ <string name="more_keys_for_a">&#x00E2;</string>
+ <!-- U+0259: "ə" LATIN SMALL LETTER SCHWA -->
+ <string name="more_keys_for_e">&#x0259;</string>
+ <!-- U+0131: "ı" LATIN SMALL LETTER DOTLESS I
+ U+00EE: "î" LATIN SMALL LETTER I WITH CIRCUMFLEX
+ U+00EF: "ï" LATIN SMALL LETTER I WITH DIAERESIS
+ U+00EC: "ì" LATIN SMALL LETTER I WITH GRAVE
+ U+00ED: "í" LATIN SMALL LETTER I WITH ACUTE
+ U+012F: "į" LATIN SMALL LETTER I WITH OGONEK
+ U+012B: "ī" LATIN SMALL LETTER I WITH MACRON -->
+ <string name="more_keys_for_i">&#x0131;,&#x00EE;,&#x00EF;,&#x00EC;,&#x00ED;,&#x012F;,&#x012B;</string>
+ <!-- U+00F6: "ö" LATIN SMALL LETTER O WITH DIAERESIS
+ U+00F4: "ô" LATIN SMALL LETTER O WITH CIRCUMFLEX
+ U+0153: "œ" LATIN SMALL LIGATURE OE
+ U+00F2: "ò" LATIN SMALL LETTER O WITH GRAVE
+ U+00F3: "ó" LATIN SMALL LETTER O WITH ACUTE
+ U+00F5: "õ" LATIN SMALL LETTER O WITH TILDE
+ U+00F8: "ø" LATIN SMALL LETTER O WITH STROKE
+ U+014D: "ō" LATIN SMALL LETTER O WITH MACRON -->
+ <string name="more_keys_for_o">&#x00F6;,&#x00F4;,&#x0153;,&#x00F2;,&#x00F3;,&#x00F5;,&#x00F8;,&#x014D;</string>
+ <!-- U+00FC: "ü" LATIN SMALL LETTER U WITH DIAERESIS
+ U+00FB: "û" LATIN SMALL LETTER U WITH CIRCUMFLEX
+ U+00F9: "ù" LATIN SMALL LETTER U WITH GRAVE
+ U+00FA: "ú" LATIN SMALL LETTER U WITH ACUTE
+ U+016B: "ū" LATIN SMALL LETTER U WITH MACRON -->
+ <string name="more_keys_for_u">&#x00FC;,&#x00FB;,&#x00F9;,&#x00FA;,&#x016B;</string>
+ <!-- U+015F: "ş" LATIN SMALL LETTER S WITH CEDILLA
+ U+00DF: "ß" LATIN SMALL LETTER SHARP S
+ U+015B: "ś" LATIN SMALL LETTER S WITH ACUTE
+ U+0161: "š" LATIN SMALL LETTER S WITH CARON -->
+ <string name="more_keys_for_s">&#x015F;,&#x00DF;,&#x015B;,&#x0161;</string>
+ <!-- U+011F: "ğ" LATIN SMALL LETTER G WITH BREVE -->
+ <string name="more_keys_for_g">&#x011F;</string>
+ <!-- U+00E7: "ç" LATIN SMALL LETTER C WITH CEDILLA
+ U+0107: "ć" LATIN SMALL LETTER C WITH ACUTE
+ U+010D: "č" LATIN SMALL LETTER C WITH CARON -->
+ <string name="more_keys_for_c">&#x00E7;,&#x0107;,&#x010D;</string>
+</resources>
diff --git a/tools/maketext/res/values-kk/donottranslate-more-keys.xml b/tools/maketext/res/values-kk/donottranslate-more-keys.xml
new file mode 100644
index 000000000..0e953ff21
--- /dev/null
+++ b/tools/maketext/res/values-kk/donottranslate-more-keys.xml
@@ -0,0 +1,57 @@
+<?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">
+ <!-- U+0449: "щ" CYRILLIC SMALL LETTER SHCHA -->
+ <string name="keylabel_for_east_slavic_row1_9">&#x0449;</string>
+ <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN -->
+ <string name="keylabel_for_east_slavic_row1_12">&#x044A;</string>
+ <!-- U+044B: "ы" CYRILLIC SMALL LETTER YERU -->
+ <string name="keylabel_for_east_slavic_row2_1">&#x044B;</string>
+ <!-- U+044D: "э" CYRILLIC SMALL LETTER E -->
+ <string name="keylabel_for_east_slavic_row2_11">&#x044D;</string>
+ <!-- U+0438: "и" CYRILLIC SMALL LETTER I -->
+ <string name="keylabel_for_east_slavic_row3_5">&#x0438;</string>
+ <!-- U+04AF: "ү" CYRILLIC SMALL LETTER STRAIGHT U
+ U+04B1: "ұ" CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE -->
+ <string name="more_keys_for_cyrillic_u">&#x04AF;,&#x04B1;</string>
+ <!-- U+049B: "қ" CYRILLIC SMALL LETTER KA WITH DESCENDER -->
+ <string name="more_keys_for_cyrillic_ka">&#x049B;</string>
+ <!-- U+0451: "ё" CYRILLIC SMALL LETTER IO -->
+ <string name="more_keys_for_cyrillic_ie">&#x0451;</string>
+ <!-- U+04A3: "ң" CYRILLIC SMALL LETTER EN WITH DESCENDER -->
+ <string name="more_keys_for_cyrillic_en">&#x04A3;</string>
+ <!-- U+0493: "ғ" CYRILLIC SMALL LETTER GHE WITH STROKE -->
+ <string name="more_keys_for_cyrillic_ghe">&#x0493;</string>
+ <!-- U+0456: "і" CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I -->
+ <string name="more_keys_for_east_slavic_row2_1">&#x0456;</string>
+ <!-- U+04D9: "ә" CYRILLIC SMALL LETTER SCHWA -->
+ <string name="more_keys_for_cyrillic_a">&#x04D9;</string>
+ <!-- U+04E9: "ө" CYRILLIC SMALL LETTER BARRED O -->
+ <string name="more_keys_for_cyrillic_o">&#x04E9;</string>
+ <!-- U+04BB: "һ" CYRILLIC SMALL LETTER SHHA -->
+ <string name="more_keys_for_east_slavic_row2_11">&#x04BB;</string>
+ <!-- U+044A: "ъ" CYRILLIC SMALL LETTER HARD SIGN -->
+ <string name="more_keys_for_cyrillic_soft_sign">&#x044A;</string>
+ <!-- Label for "switch to alphabetic" key.
+ U+0410: "А" CYRILLIC CAPITAL LETTER A
+ U+0411: "Б" CYRILLIC CAPITAL LETTER BE
+ U+0412: "В" CYRILLIC CAPITAL LETTER VE -->
+ <string name="label_to_alpha_key">&#x0410;&#x0411;&#x0412;</string>
+</resources>
diff --git a/tools/maketext/res/values/donottranslate-more-keys.xml b/tools/maketext/res/values/donottranslate-more-keys.xml
index c2b7513f3..b53a36917 100644
--- a/tools/maketext/res/values/donottranslate-more-keys.xml
+++ b/tools/maketext/res/values/donottranslate-more-keys.xml
@@ -49,11 +49,14 @@
<string name="keylabel_for_east_slavic_row2_11"></string>
<string name="keylabel_for_east_slavic_row3_5"></string>
<string name="more_keys_for_cyrillic_u"></string>
+ <string name="more_keys_for_cyrillic_ka"></string>
<string name="more_keys_for_cyrillic_en"></string>
<string name="more_keys_for_cyrillic_ghe"></string>
<string name="more_keys_for_east_slavic_row2_1"></string>
+ <string name="more_keys_for_cyrillic_a"></string>
<string name="more_keys_for_cyrillic_o"></string>
<string name="more_keys_for_cyrillic_soft_sign"></string>
+ <string name="more_keys_for_east_slavic_row2_11"></string>
<string name="keylabel_for_south_slavic_row1_6"></string>
<string name="keylabel_for_south_slavic_row2_11"></string>
<string name="keylabel_for_south_slavic_row3_1"></string>