aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java5
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/utils/StatsUtils.java6
-rw-r--r--java/AndroidManifest.xml2
-rw-r--r--java/res/values/attrs.xml4
-rw-r--r--java/res/values/keyboard-themes.xml4
-rw-r--r--java/res/xml-sw600dp-land/key_space_3kw.xml69
-rw-r--r--java/res/xml-sw600dp-land/row_qwerty4.xml74
-rw-r--r--java/res/xml-sw600dp-land/rows_qwerty.xml133
-rw-r--r--java/res/xml-sw600dp/key_space_3kw.xml67
-rw-r--r--java/res/xml-sw600dp/row_qwerty4.xml69
-rw-r--r--java/res/xml-sw600dp/rows_qwerty.xml135
-rw-r--r--java/res/xml/keyboard_layout_set_qwerty.xml3
-rw-r--r--java/res/xml/rowkeys_qwerty1.xml55
-rw-r--r--java/res/xml/rowkeys_qwerty1_left5.xml49
-rw-r--r--java/res/xml/rowkeys_qwerty1_right5.xml48
-rw-r--r--java/res/xml/rowkeys_qwerty2.xml32
-rw-r--r--java/res/xml/rowkeys_qwerty2_left5.xml38
-rw-r--r--java/res/xml/rowkeys_qwerty2_right4.xml36
-rw-r--r--java/res/xml/rowkeys_qwerty3.xml25
-rw-r--r--java/res/xml/rowkeys_qwerty3_left4.xml36
-rw-r--r--java/res/xml/rowkeys_qwerty3_right3.xml31
-rw-r--r--java/src/com/android/inputmethod/keyboard/Key.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardId.java16
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java8
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java13
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardTheme.java67
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java4
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitator.java264
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java2
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java18
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java2
-rw-r--r--java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java8
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java4
-rw-r--r--java/src/com/android/inputmethod/latin/WordComposer.java11
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java13
-rw-r--r--java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java30
-rw-r--r--java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java2
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java12
-rw-r--r--native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp48
-rw-r--r--native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h17
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary.cpp55
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary.h16
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary_utils.cpp19
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary_utils.h3
-rw-r--r--native/jni/src/suggest/core/session/dic_traverse_session.cpp4
-rw-r--r--native/jni/src/suggest/core/session/dic_traverse_session.h14
-rw-r--r--native/jni/src/suggest/core/session/prev_words_info.h36
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp25
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp29
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h10
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp4
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h8
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp105
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h37
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h12
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.cpp14
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h13
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h15
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp77
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h17
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/shortcut/shortcut_list_policy.h14
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp8
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h9
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.cpp14
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h7
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp25
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h3
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h5
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp1
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h1
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp14
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp111
-rw-r--r--native/jni/src/utils/byte_array_view.h7
-rw-r--r--native/jni/src/utils/int_array_view.h23
-rw-r--r--native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp8
-rw-r--r--native/jni/tests/utils/int_array_view_test.cpp33
-rw-r--r--tests/AndroidManifest.xml2
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java2
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java69
-rw-r--r--tests/src/com/android/inputmethod/latin/InputTestsBase.java3
-rw-r--r--tests/src/com/android/inputmethod/latin/utils/DistracterFilterTest.java2
81 files changed, 1618 insertions, 720 deletions
diff --git a/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java b/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
index c22c5770f..9d7258de7 100644
--- a/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
+++ b/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
@@ -45,4 +45,9 @@ public final class ProductionFlags {
* When {@code false}, the split keyboard is not yet ready to be enabled.
*/
public static final boolean IS_SPLIT_KEYBOARD_SUPPORTED = true;
+
+ /**
+ * When {@code false}, account sign-in in keyboard is not yet ready to be enabled.
+ */
+ public static final boolean ENABLE_ACCOUNT_SIGN_IN = false;
}
diff --git a/java-overridable/src/com/android/inputmethod/latin/utils/StatsUtils.java b/java-overridable/src/com/android/inputmethod/latin/utils/StatsUtils.java
index 38735eccb..2274852ce 100644
--- a/java-overridable/src/com/android/inputmethod/latin/utils/StatsUtils.java
+++ b/java-overridable/src/com/android/inputmethod/latin/utils/StatsUtils.java
@@ -20,6 +20,8 @@ import com.android.inputmethod.latin.RichInputMethodManager;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.settings.SettingsValues;
+import javax.annotation.Nullable;
+
public final class StatsUtils {
private StatsUtils() {
@@ -63,4 +65,8 @@ public final class StatsUtils {
public static void onStartInputView(int inputType, int displayOrientation, boolean restarting) {
}
+
+ public static void onAutoCorrection(final String typedWord, final String autoCorrectionWord,
+ final boolean isBatchInput, @Nullable final String dictionaryType) {
+ }
}
diff --git a/java/AndroidManifest.xml b/java/AndroidManifest.xml
index a1ffe5a93..054c415a4 100644
--- a/java/AndroidManifest.xml
+++ b/java/AndroidManifest.xml
@@ -18,7 +18,7 @@
coreApp="true"
package="com.android.inputmethod.latin">
- <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" />
+ <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index f1253b40c..8ee859bc7 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -483,6 +483,8 @@
<attr name="localeCode" format="string" />
<attr name="languageCode" format="string" />
<attr name="countryCode" format="string" />
+ <!-- Enable split keyboard layout. Disabled by default. -->
+ <attr name="isSplitLayout" format="boolean" />
</declare-styleable>
<declare-styleable name="Keyboard_KeyStyle">
@@ -514,6 +516,8 @@
<attr name="elementKeyboard" format="reference"/>
<!-- Enable proximity characters correction. Disabled by default. -->
<attr name="enableProximityCharsCorrection" format="boolean" />
+ <!-- Indicates if the keyboard layout supports being split or not. false by default -->
+ <attr name="supportsSplitLayout" format="boolean" />
</declare-styleable>
<declare-styleable name="KeyboardLayoutSet_Feature">
diff --git a/java/res/values/keyboard-themes.xml b/java/res/values/keyboard-themes.xml
index 9d772c4e7..b0bae9647 100644
--- a/java/res/values/keyboard-themes.xml
+++ b/java/res/values/keyboard-themes.xml
@@ -26,10 +26,10 @@
<item>@string/keyboard_theme_holo_blue</item>
</string-array>
<!-- An element must be a keyboard theme id of {@link KeyboardTheme#THEME_ID_*}. -->
- <string-array name="keyboard_theme_ids" translatable="false">
+ <integer-array name="keyboard_theme_ids" translatable="false">
<item>3</item>
<item>4</item>
<item>2</item>
<item>0</item>
- </string-array>
+ </integer-array>
</resources>
diff --git a/java/res/xml-sw600dp-land/key_space_3kw.xml b/java/res/xml-sw600dp-land/key_space_3kw.xml
new file mode 100644
index 000000000..47c4e4809
--- /dev/null
+++ b/java/res/xml-sw600dp-land/key_space_3kw.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <!-- TODO: Consolidate the layout specification between protrait and landscape.
+ Ideally just the keyWidth should be different -->
+ <switch>
+ <!-- fa: Perisan
+ kn: Kannada
+ ne: Nepali
+ te: Telugu -->
+ <case
+ latin:languageCode="fa|kn|ne|te"
+ latin:languageSwitchKeyEnabled="true"
+ >
+ <Key
+ latin:keyStyle="languageSwitchKeyStyle" />
+ <Key
+ latin:keyStyle="spaceKeyStyle"
+ latin:keyWidth="7.0%p" />
+ <Key
+ latin:keyStyle="zwnjKeyStyle" />
+ </case>
+ <case
+ latin:languageCode="fa|kn|ne|te"
+ latin:languageSwitchKeyEnabled="false"
+ >
+ <Key
+ latin:keyStyle="spaceKeyStyle"
+ latin:keyWidth="14.0%p" />
+ <Key
+ latin:keyStyle="zwnjKeyStyle" />
+ </case>
+ <case
+ latin:languageSwitchKeyEnabled="true"
+ >
+ <Key
+ latin:keyStyle="languageSwitchKeyStyle" />
+ <Key
+ latin:keyStyle="spaceKeyStyle"
+ latin:keyWidth="14.0%p" />
+ </case>
+ <!-- languageSwitchKeyEnabled="false" -->
+ <default>
+ <Key
+ latin:keyStyle="spaceKeyStyle"
+ latin:keyWidth="21.0%p" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml-sw600dp-land/row_qwerty4.xml b/java/res/xml-sw600dp-land/row_qwerty4.xml
new file mode 100644
index 000000000..0fdb5c6f5
--- /dev/null
+++ b/java/res/xml-sw600dp-land/row_qwerty4.xml
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <!-- Split the 4th row for split layouts -->
+ <case
+ latin:isSplitLayout="true"
+ >
+ <Row
+ latin:keyWidth="7.0%p"
+ latin:backgroundType="functional"
+ >
+ <Key
+ latin:keyStyle="toSymbolKeyStyle" />
+ <include
+ latin:keyboardLayout="@xml/key_comma" />
+ <!-- Space key. -->
+ <include
+ latin:keyboardLayout="@xml/key_space_3kw"
+ latin:backgroundType="normal" />
+ <Spacer
+ latin:keyWidth="28.0%p" />
+ <Key
+ latin:keyStyle="spaceKeyStyle"
+ latin:keyWidth="21.0%p" />
+ <include
+ latin:keyboardLayout="@xml/key_period" />
+ <include
+ latin:keyboardLayout="@xml/key_emoji" />
+ </Row>
+ </case>
+ <default>
+ <Row
+ latin:keyWidth="9.0%p"
+ latin:backgroundType="functional"
+ >
+ <Key
+ latin:keyStyle="toSymbolKeyStyle"
+ latin:keyWidth="10.0%p" />
+ <include
+ latin:keyboardLayout="@xml/key_comma" />
+ <!-- Space key. -->
+ <include
+ latin:keyXPos="19.0%p"
+ latin:keyboardLayout="@xml/key_space_7kw"
+ latin:backgroundType="normal" />
+ <include
+ latin:keyboardLayout="@xml/key_period" />
+ <include
+ latin:keyboardLayout="@xml/key_emoji" />
+ </Row>
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml-sw600dp-land/rows_qwerty.xml b/java/res/xml-sw600dp-land/rows_qwerty.xml
new file mode 100644
index 000000000..b580dcf6a
--- /dev/null
+++ b/java/res/xml-sw600dp-land/rows_qwerty.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <include
+ latin:keyboardLayout="@xml/key_styles_common" />
+ <!-- First row -->
+ <Row>
+ <switch>
+ <!-- Split keyboard layout for the first row -->
+ <case
+ latin:isSplitLayout="true"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty1_left5"
+ latin:keyWidth="7.0%p" />
+ <Spacer
+ latin:keyWidth="20.0%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty1_right5"
+ latin:keyWidth="7.0%p" />
+ <Key
+ latin:keyStyle="deleteKeyStyle"
+ latin:keyWidth="10.0%p" />
+ </case>
+ <!-- Regular layout for the first row -->
+ <default>
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty1"
+ latin:keyWidth="9.0%p" />
+ <Key
+ latin:keyStyle="deleteKeyStyle"
+ latin:keyWidth="fillRight" />
+ </default>
+ </switch>
+ </Row>
+ <!-- Second row -->
+ <Row>
+ <switch>
+ <!-- Split keyboard layout for the second row -->
+ <case
+ latin:isSplitLayout="true"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty2_left5"
+ latin:keyXPos="4.0%p"
+ latin:keyWidth="7.0%p" />
+ <Spacer
+ latin:keyWidth="23.0%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty2_right4"
+ latin:keyWidth="7.0%p" />
+ <Key
+ latin:keyStyle="enterKeyStyle"
+ latin:keyWidth="10.0%p" />
+ </case>
+ <!-- Regular layout for the second row -->
+ <default>
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty2"
+ latin:keyXPos="4.5%p"
+ latin:keyWidth="9.0%p" />
+ <Key
+ latin:keyStyle="enterKeyStyle"
+ latin:keyWidth="fillRight" />
+ </default>
+ </switch>
+ </Row>
+ <!-- Third row -->
+ <Row>
+ <switch>
+ <!-- Split keyboard layout for the third row -->
+ <case
+ latin:isSplitLayout="true"
+ >
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.0%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty3_left4"
+ latin:keyWidth="7.0%p" />
+ <Spacer
+ latin:keyWidth="17.0%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty3_right3"
+ latin:keyWidth="7.0%p" />
+ <include
+ latin:keyboardLayout="@xml/keys_exclamation_question"
+ latin:keyWidth="7.0%p" />
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.0%p" />
+ </case>
+ <!-- Regular layout for the third row -->
+ <default>
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.0%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty3"
+ latin:keyWidth="9.0%p" />
+ <include
+ latin:keyboardLayout="@xml/keys_exclamation_question"
+ latin:keyWidth="9.0%p" />
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="fillRight" />
+ </default>
+ </switch>
+ </Row>
+ <!-- Fourth row -->
+ <include
+ latin:keyboardLayout="@xml/row_qwerty4" />
+</merge>
diff --git a/java/res/xml-sw600dp/key_space_3kw.xml b/java/res/xml-sw600dp/key_space_3kw.xml
new file mode 100644
index 000000000..9932d342e
--- /dev/null
+++ b/java/res/xml-sw600dp/key_space_3kw.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <switch>
+ <!-- fa: Perisan
+ kn: Kannada
+ ne: Nepali
+ te: Telugu -->
+ <case
+ latin:languageCode="fa|kn|ne|te"
+ latin:languageSwitchKeyEnabled="true"
+ >
+ <Key
+ latin:keyStyle="languageSwitchKeyStyle" />
+ <Key
+ latin:keyStyle="spaceKeyStyle"
+ latin:keyWidth="8.0%p" />
+ <Key
+ latin:keyStyle="zwnjKeyStyle" />
+ </case>
+ <case
+ latin:languageCode="fa|kn|ne|te"
+ latin:languageSwitchKeyEnabled="false"
+ >
+ <Key
+ latin:keyStyle="spaceKeyStyle"
+ latin:keyWidth="16.0%p" />
+ <Key
+ latin:keyStyle="zwnjKeyStyle" />
+ </case>
+ <case
+ latin:languageSwitchKeyEnabled="true"
+ >
+ <Key
+ latin:keyStyle="languageSwitchKeyStyle" />
+ <Key
+ latin:keyStyle="spaceKeyStyle"
+ latin:keyWidth="16.0%p" />
+ </case>
+ <!-- languageSwitchKeyEnabled="false" -->
+ <default>
+ <Key
+ latin:keyStyle="spaceKeyStyle"
+ latin:keyWidth="24.0%p" />
+ </default>
+ </switch>
+</merge>
diff --git a/java/res/xml-sw600dp/row_qwerty4.xml b/java/res/xml-sw600dp/row_qwerty4.xml
index ed7150de4..bcfd2cb7f 100644
--- a/java/res/xml-sw600dp/row_qwerty4.xml
+++ b/java/res/xml-sw600dp/row_qwerty4.xml
@@ -21,23 +21,54 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <Row
- latin:keyWidth="9.0%p"
- latin:backgroundType="functional"
- >
- <Key
- latin:keyStyle="toSymbolKeyStyle"
- latin:keyWidth="10.0%p" />
- <include
- latin:keyboardLayout="@xml/key_comma" />
- <!-- Space key. -->
- <include
- latin:keyXPos="19.0%p"
- latin:keyboardLayout="@xml/key_space_7kw"
- latin:backgroundType="normal" />
- <include
- latin:keyboardLayout="@xml/key_period" />
- <include
- latin:keyboardLayout="@xml/key_emoji" />
- </Row>
+ <switch>
+ <!-- Split the 4th row for split layouts -->
+ <case
+ latin:isSplitLayout="true"
+ >
+ <Row
+ latin:keyWidth="8.0%p"
+ latin:backgroundType="functional"
+ >
+ <Key
+ latin:keyStyle="toSymbolKeyStyle" />
+ <include
+ latin:keyboardLayout="@xml/key_comma" />
+ <!-- Space key. -->
+ <include
+ latin:keyboardLayout="@xml/key_space_3kw"
+ latin:backgroundType="normal" />
+ <Spacer
+ latin:keyWidth="20.0%p" />
+ <Key
+ latin:keyStyle="spaceKeyStyle"
+ latin:keyWidth="24.0%p" />
+ <include
+ latin:keyboardLayout="@xml/key_period" />
+ <include
+ latin:keyboardLayout="@xml/key_emoji" />
+ </Row>
+ </case>
+ <default>
+ <Row
+ latin:keyWidth="9.0%p"
+ latin:backgroundType="functional"
+ >
+ <Key
+ latin:keyStyle="toSymbolKeyStyle"
+ latin:keyWidth="10.0%p" />
+ <include
+ latin:keyboardLayout="@xml/key_comma" />
+ <!-- Space key. -->
+ <include
+ latin:keyXPos="19.0%p"
+ latin:keyboardLayout="@xml/key_space_7kw"
+ latin:backgroundType="normal" />
+ <include
+ latin:keyboardLayout="@xml/key_period" />
+ <include
+ latin:keyboardLayout="@xml/key_emoji" />
+ </Row>
+ </default>
+ </switch>
</merge>
diff --git a/java/res/xml-sw600dp/rows_qwerty.xml b/java/res/xml-sw600dp/rows_qwerty.xml
index 58ba1d713..51df4b0cc 100644
--- a/java/res/xml-sw600dp/rows_qwerty.xml
+++ b/java/res/xml-sw600dp/rows_qwerty.xml
@@ -23,39 +23,114 @@
>
<include
latin:keyboardLayout="@xml/key_styles_common" />
- <Row
- latin:keyWidth="9.0%p"
- >
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty1" />
- <Key
- latin:keyStyle="deleteKeyStyle"
- latin:keyWidth="fillRight" />
+ <!-- TODO: Consolidate the layout specification between protrait and landscape.
+ Ideally just the keyWidth should be different and the spacer should adjust to fill
+ the available space. -->
+ <!-- First row -->
+ <Row>
+ <switch>
+ <!-- Split keyboard layout for the first row -->
+ <case
+ latin:isSplitLayout="true"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty1_left5"
+ latin:keyWidth="8.0%p" />
+ <Spacer
+ latin:keyWidth="10.0%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty1_right5"
+ latin:keyWidth="8.0%p" />
+ <Key
+ latin:keyStyle="deleteKeyStyle"
+ latin:keyWidth="10.0%p" />
+ </case>
+ <!-- Regular layout for the first row -->
+ <default>
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty1"
+ latin:keyWidth="9.0%p" />
+ <Key
+ latin:keyStyle="deleteKeyStyle"
+ latin:keyWidth="fillRight" />
+ </default>
+ </switch>
</Row>
- <Row
- latin:keyWidth="9.0%p"
- >
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty2"
- latin:keyXPos="4.5%p" />
- <Key
- latin:keyStyle="enterKeyStyle"
- latin:keyWidth="fillRight" />
+ <!-- Second row -->
+ <Row>
+ <switch>
+ <!-- Split keyboard layout for the second row -->
+ <case
+ latin:isSplitLayout="true"
+ >
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty2_left5"
+ latin:keyXPos="4.0%p"
+ latin:keyWidth="8.0%p" />
+ <Spacer
+ latin:keyWidth="14.0%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty2_right4"
+ latin:keyWidth="8.0%p" />
+ <Key
+ latin:keyStyle="enterKeyStyle"
+ latin:keyWidth="10.0%p" />
+ </case>
+ <!-- Regular layout for the second row -->
+ <default>
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty2"
+ latin:keyXPos="4.5%p"
+ latin:keyWidth="9.0%p" />
+ <Key
+ latin:keyStyle="enterKeyStyle"
+ latin:keyWidth="fillRight" />
+ </default>
+ </switch>
</Row>
- <Row
- latin:keyWidth="9.0%p"
- >
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="10.0%p" />
- <include
- latin:keyboardLayout="@xml/rowkeys_qwerty3" />
- <include
- latin:keyboardLayout="@xml/keys_exclamation_question" />
- <Key
- latin:keyStyle="shiftKeyStyle"
- latin:keyWidth="fillRight" />
+ <!-- Third row -->
+ <Row>
+ <switch>
+ <!-- Split keyboard layout for the third row -->
+ <case
+ latin:isSplitLayout="true"
+ >
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.0%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty3_left4"
+ latin:keyWidth="8.0%p" />
+ <Spacer
+ latin:keyWidth="8.0%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty3_right3"
+ latin:keyWidth="8.0%p" />
+ <include
+ latin:keyboardLayout="@xml/keys_exclamation_question"
+ latin:keyWidth="8.0%p" />
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.0%p" />
+ </case>
+ <!-- Regular layout for the third row -->
+ <default>
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="10.0%p" />
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty3"
+ latin:keyWidth="9.0%p" />
+ <include
+ latin:keyboardLayout="@xml/keys_exclamation_question"
+ latin:keyWidth="9.0%p" />
+ <Key
+ latin:keyStyle="shiftKeyStyle"
+ latin:keyWidth="fillRight" />
+ </default>
+ </switch>
</Row>
+ <!-- Fourth row -->
<include
latin:keyboardLayout="@xml/row_qwerty4" />
</merge>
diff --git a/java/res/xml/keyboard_layout_set_qwerty.xml b/java/res/xml/keyboard_layout_set_qwerty.xml
index 821517081..1aa6f010a 100644
--- a/java/res/xml/keyboard_layout_set_qwerty.xml
+++ b/java/res/xml/keyboard_layout_set_qwerty.xml
@@ -23,7 +23,8 @@
<Element
latin:elementName="alphabet"
latin:elementKeyboard="@xml/kbd_qwerty"
- latin:enableProximityCharsCorrection="true" />
+ latin:enableProximityCharsCorrection="true"
+ latin:supportsSplitLayout="false" />
<Element
latin:elementName="symbols"
latin:elementKeyboard="@xml/kbd_symbols" />
diff --git a/java/res/xml/rowkeys_qwerty1.xml b/java/res/xml/rowkeys_qwerty1.xml
index 8f3b160fe..b8e4a4c78 100644
--- a/java/res/xml/rowkeys_qwerty1.xml
+++ b/java/res/xml/rowkeys_qwerty1.xml
@@ -21,53 +21,10 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <Key
- latin:keySpec="!text/keyspec_q"
- latin:keyHintLabel="1"
- latin:additionalMoreKeys="1"
- latin:moreKeys="!text/morekeys_q" />
- <Key
- latin:keySpec="!text/keyspec_w"
- latin:keyHintLabel="2"
- latin:additionalMoreKeys="2"
- latin:moreKeys="!text/morekeys_w" />
- <Key
- latin:keySpec="e"
- latin:keyHintLabel="3"
- latin:additionalMoreKeys="3"
- latin:moreKeys="!text/morekeys_e" />
- <Key
- latin:keySpec="r"
- latin:keyHintLabel="4"
- latin:additionalMoreKeys="4"
- latin:moreKeys="!text/morekeys_r" />
- <Key
- latin:keySpec="t"
- latin:keyHintLabel="5"
- latin:additionalMoreKeys="5"
- latin:moreKeys="!text/morekeys_t" />
- <Key
- latin:keySpec="!text/keyspec_y"
- latin:keyHintLabel="6"
- latin:additionalMoreKeys="6"
- latin:moreKeys="!text/morekeys_y" />
- <Key
- latin:keySpec="u"
- latin:keyHintLabel="7"
- latin:additionalMoreKeys="7"
- latin:moreKeys="!text/morekeys_u" />
- <Key
- latin:keySpec="i"
- latin:keyHintLabel="8"
- latin:additionalMoreKeys="8"
- latin:moreKeys="!text/morekeys_i" />
- <Key
- latin:keySpec="o"
- latin:keyHintLabel="9"
- latin:additionalMoreKeys="9"
- latin:moreKeys="!text/morekeys_o" />
- <Key
- latin:keySpec="p"
- latin:keyHintLabel="0"
- latin:additionalMoreKeys="0" />
+ <!-- q,w,e,r,t -->
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty1_left5" />
+ <!-- y,u,i,o,p -->
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty1_right5" />
</merge>
diff --git a/java/res/xml/rowkeys_qwerty1_left5.xml b/java/res/xml/rowkeys_qwerty1_left5.xml
new file mode 100644
index 000000000..ff9f1b2b5
--- /dev/null
+++ b/java/res/xml/rowkeys_qwerty1_left5.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <Key
+ latin:keySpec="!text/keyspec_q"
+ latin:keyHintLabel="1"
+ latin:additionalMoreKeys="1"
+ latin:moreKeys="!text/morekeys_q" />
+ <Key
+ latin:keySpec="!text/keyspec_w"
+ latin:keyHintLabel="2"
+ latin:additionalMoreKeys="2"
+ latin:moreKeys="!text/morekeys_w" />
+ <Key
+ latin:keySpec="e"
+ latin:keyHintLabel="3"
+ latin:additionalMoreKeys="3"
+ latin:moreKeys="!text/morekeys_e" />
+ <Key
+ latin:keySpec="r"
+ latin:keyHintLabel="4"
+ latin:additionalMoreKeys="4"
+ latin:moreKeys="!text/morekeys_r" />
+ <Key
+ latin:keySpec="t"
+ latin:keyHintLabel="5"
+ latin:additionalMoreKeys="5"
+ latin:moreKeys="!text/morekeys_t" />
+</merge>
diff --git a/java/res/xml/rowkeys_qwerty1_right5.xml b/java/res/xml/rowkeys_qwerty1_right5.xml
new file mode 100644
index 000000000..2b3cae2e8
--- /dev/null
+++ b/java/res/xml/rowkeys_qwerty1_right5.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <Key
+ latin:keySpec="!text/keyspec_y"
+ latin:keyHintLabel="6"
+ latin:additionalMoreKeys="6"
+ latin:moreKeys="!text/morekeys_y" />
+ <Key
+ latin:keySpec="u"
+ latin:keyHintLabel="7"
+ latin:additionalMoreKeys="7"
+ latin:moreKeys="!text/morekeys_u" />
+ <Key
+ latin:keySpec="i"
+ latin:keyHintLabel="8"
+ latin:additionalMoreKeys="8"
+ latin:moreKeys="!text/morekeys_i" />
+ <Key
+ latin:keySpec="o"
+ latin:keyHintLabel="9"
+ latin:additionalMoreKeys="9"
+ latin:moreKeys="!text/morekeys_o" />
+ <Key
+ latin:keySpec="p"
+ latin:keyHintLabel="0"
+ latin:additionalMoreKeys="0" />
+</merge>
diff --git a/java/res/xml/rowkeys_qwerty2.xml b/java/res/xml/rowkeys_qwerty2.xml
index 4077beaf6..550db3b3f 100644
--- a/java/res/xml/rowkeys_qwerty2.xml
+++ b/java/res/xml/rowkeys_qwerty2.xml
@@ -21,30 +21,10 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <Key
- latin:keySpec="a"
- latin:moreKeys="!text/morekeys_a" />
- <Key
- latin:keySpec="s"
- latin:moreKeys="!text/morekeys_s" />
- <Key
- latin:keySpec="d"
- latin:moreKeys="!text/morekeys_d" />
- <Key
- latin:keySpec="f" />
- <Key
- latin:keySpec="g"
- latin:moreKeys="!text/morekeys_g" />
- <Key
- latin:keySpec="h"
- latin:moreKeys="!text/morekeys_h" />
- <Key
- latin:keySpec="j"
- latin:moreKeys="!text/morekeys_j" />
- <Key
- latin:keySpec="k"
- latin:moreKeys="!text/morekeys_k" />
- <Key
- latin:keySpec="l"
- latin:moreKeys="!text/morekeys_l" />
+ <!-- a,s,d,f,g -->
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty2_left5" />
+ <!-- h,j,k,l -->
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty2_right4" />
</merge>
diff --git a/java/res/xml/rowkeys_qwerty2_left5.xml b/java/res/xml/rowkeys_qwerty2_left5.xml
new file mode 100644
index 000000000..1803bf203
--- /dev/null
+++ b/java/res/xml/rowkeys_qwerty2_left5.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <Key
+ latin:keySpec="a"
+ latin:moreKeys="!text/morekeys_a" />
+ <Key
+ latin:keySpec="s"
+ latin:moreKeys="!text/morekeys_s" />
+ <Key
+ latin:keySpec="d"
+ latin:moreKeys="!text/morekeys_d" />
+ <Key
+ latin:keySpec="f" />
+ <Key
+ latin:keySpec="g"
+ latin:moreKeys="!text/morekeys_g" />
+</merge>
diff --git a/java/res/xml/rowkeys_qwerty2_right4.xml b/java/res/xml/rowkeys_qwerty2_right4.xml
new file mode 100644
index 000000000..99936b7a2
--- /dev/null
+++ b/java/res/xml/rowkeys_qwerty2_right4.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <Key
+ latin:keySpec="h"
+ latin:moreKeys="!text/morekeys_h" />
+ <Key
+ latin:keySpec="j"
+ latin:moreKeys="!text/morekeys_j" />
+ <Key
+ latin:keySpec="k"
+ latin:moreKeys="!text/morekeys_k" />
+ <Key
+ latin:keySpec="l"
+ latin:moreKeys="!text/morekeys_l" />
+</merge>
diff --git a/java/res/xml/rowkeys_qwerty3.xml b/java/res/xml/rowkeys_qwerty3.xml
index 8562003d2..7a523f1f6 100644
--- a/java/res/xml/rowkeys_qwerty3.xml
+++ b/java/res/xml/rowkeys_qwerty3.xml
@@ -21,23 +21,10 @@
<merge
xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
>
- <Key
- latin:keySpec="z"
- latin:moreKeys="!text/morekeys_z" />
- <Key
- latin:keySpec="!text/keyspec_x"
- latin:moreKeys="!text/morekeys_x" />
- <Key
- latin:keySpec="c"
- latin:moreKeys="!text/morekeys_c" />
- <Key
- latin:keySpec="v"
- latin:moreKeys="!text/morekeys_v" />
- <Key
- latin:keySpec="b" />
- <Key
- latin:keySpec="n"
- latin:moreKeys="!text/morekeys_n" />
- <Key
- latin:keySpec="m" />
+ <!-- z,x,c,v -->
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty3_left4" />
+ <!-- b,n,m -->
+ <include
+ latin:keyboardLayout="@xml/rowkeys_qwerty3_right3" />
</merge>
diff --git a/java/res/xml/rowkeys_qwerty3_left4.xml b/java/res/xml/rowkeys_qwerty3_left4.xml
new file mode 100644
index 000000000..6043c3bba
--- /dev/null
+++ b/java/res/xml/rowkeys_qwerty3_left4.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <Key
+ latin:keySpec="z"
+ latin:moreKeys="!text/morekeys_z" />
+ <Key
+ latin:keySpec="!text/keyspec_x"
+ latin:moreKeys="!text/morekeys_x" />
+ <Key
+ latin:keySpec="c"
+ latin:moreKeys="!text/morekeys_c" />
+ <Key
+ latin:keySpec="v"
+ latin:moreKeys="!text/morekeys_v" />
+</merge>
diff --git a/java/res/xml/rowkeys_qwerty3_right3.xml b/java/res/xml/rowkeys_qwerty3_right3.xml
new file mode 100644
index 000000000..f69910344
--- /dev/null
+++ b/java/res/xml/rowkeys_qwerty3_right3.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<merge
+ xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin"
+>
+ <Key
+ latin:keySpec="b" />
+ <Key
+ latin:keySpec="n"
+ latin:moreKeys="!text/morekeys_n" />
+ <Key
+ latin:keySpec="m" />
+</merge>
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index bd1c1479a..99a34bec7 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -702,6 +702,10 @@ public class Key implements Comparable<Key> {
return ((mLabelFlags | defaultFlags) & LABEL_FLAGS_KEEP_BACKGROUND_ASPECT_RATIO) != 0;
}
+ public final boolean hasCustomActionLabel() {
+ return (mLabelFlags & LABEL_FLAGS_FROM_CUSTOM_ACTION_LABEL) != 0;
+ }
+
private final boolean isShiftedLetterActivated() {
return (mLabelFlags & LABEL_FLAGS_SHIFTED_LETTER_ACTIVATED) != 0
&& !TextUtils.isEmpty(mHintLabel);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index 538e515bc..43c61443e 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -73,10 +73,12 @@ public final class KeyboardId {
public final boolean mLanguageSwitchKeyEnabled;
public final String mCustomActionLabel;
public final boolean mHasShortcutKey;
+ public final boolean mIsSplitLayout;
private final int mHashCode;
- public KeyboardId(final int elementId, final KeyboardLayoutSet.Params params) {
+ public KeyboardId(final int elementId, final KeyboardLayoutSet.Params params,
+ boolean isSplitLayout) {
mSubtype = params.mSubtype;
mLocale = SubtypeLocaleUtils.getSubtypeLocale(mSubtype);
mWidth = params.mKeyboardWidth;
@@ -89,6 +91,7 @@ public final class KeyboardId {
mCustomActionLabel = (mEditorInfo.actionLabel != null)
? mEditorInfo.actionLabel.toString() : null;
mHasShortcutKey = params.mVoiceInputKeyEnabled;
+ mIsSplitLayout = isSplitLayout;
mHashCode = computeHashCode(this);
}
@@ -108,7 +111,8 @@ public final class KeyboardId {
id.mCustomActionLabel,
id.navigateNext(),
id.navigatePrevious(),
- id.mSubtype
+ id.mSubtype,
+ id.mIsSplitLayout
});
}
@@ -128,7 +132,8 @@ public final class KeyboardId {
&& TextUtils.equals(other.mCustomActionLabel, mCustomActionLabel)
&& other.navigateNext() == navigateNext()
&& other.navigatePrevious() == navigatePrevious()
- && other.mSubtype.equals(mSubtype);
+ && other.mSubtype.equals(mSubtype)
+ && other.mIsSplitLayout == mIsSplitLayout;
}
private static boolean isAlphabetKeyboard(final int elementId) {
@@ -175,7 +180,7 @@ public final class KeyboardId {
@Override
public String toString() {
- return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s%s%s%s%s%s%s%s]",
+ return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s%s%s%s%s%s%s%s%s]",
elementIdToName(mElementId),
mLocale, mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET),
mWidth, mHeight,
@@ -187,7 +192,8 @@ public final class KeyboardId {
(passwordInput() ? " passwordInput" : ""),
(mHasShortcutKey ? " hasShortcutKey" : ""),
(mLanguageSwitchKeyEnabled ? " languageSwitchKeyEnabled" : ""),
- (isMultiLine() ? " isMultiLine" : "")
+ (isMultiLine() ? " isMultiLine" : ""),
+ (mIsSplitLayout ? " isSplitLayout" : "")
);
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index 3f4367313..1dbecdc81 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -96,6 +96,7 @@ public final class KeyboardLayoutSet {
private static final class ElementParams {
int mKeyboardXmlId;
boolean mProximityCharsCorrectionEnabled;
+ boolean mSupportsSplitLayout;
public ElementParams() {}
}
@@ -168,7 +169,10 @@ public final class KeyboardLayoutSet {
// attribute in a keyboard_layout_set XML file. Also each keyboard layout XML resource is
// specified as an elementKeyboard attribute in the file.
// The KeyboardId is an internal key for a Keyboard object.
- final KeyboardId id = new KeyboardId(keyboardLayoutSetElementId, mParams);
+
+ // TODO: AND mSupportsSplitLayout with the user preference that forces a split.
+ final KeyboardId id = new KeyboardId(keyboardLayoutSetElementId, mParams,
+ elementParams.mSupportsSplitLayout);
try {
return getKeyboard(elementParams, id);
} catch (final RuntimeException e) {
@@ -376,6 +380,8 @@ public final class KeyboardLayoutSet {
elementParams.mProximityCharsCorrectionEnabled = a.getBoolean(
R.styleable.KeyboardLayoutSet_Element_enableProximityCharsCorrection,
false);
+ elementParams.mSupportsSplitLayout = a.getBoolean(
+ R.styleable.KeyboardLayoutSet_Element_supportsSplitLayout, false);
mParams.mKeyboardLayoutSetElementIdToParamsMap.put(elementName, elementParams);
} finally {
a.recycle();
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index d36c199e2..6cd7955ce 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -17,9 +17,7 @@
package com.android.inputmethod.keyboard;
import android.content.Context;
-import android.content.SharedPreferences;
import android.content.res.Resources;
-import android.preference.PreferenceManager;
import android.util.Log;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
@@ -47,7 +45,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
private static final String TAG = KeyboardSwitcher.class.getSimpleName();
private SubtypeSwitcher mSubtypeSwitcher;
- private SharedPreferences mPrefs;
private InputView mCurrentInputView;
private View mMainKeyboardFrame;
@@ -76,13 +73,11 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
}
public static void init(final LatinIME latinIme) {
- final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(latinIme);
- sInstance.initInternal(latinIme, prefs);
+ sInstance.initInternal(latinIme);
}
- private void initInternal(final LatinIME latinIme, final SharedPreferences prefs) {
+ private void initInternal(final LatinIME latinIme) {
mLatinIME = latinIme;
- mPrefs = prefs;
mSubtypeSwitcher = SubtypeSwitcher.getInstance();
mState = new KeyboardState(this);
mIsHardwareAcceleratedDrawingEnabled =
@@ -91,7 +86,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
public void updateKeyboardTheme() {
final boolean themeUpdated = updateKeyboardThemeAndContextThemeWrapper(
- mLatinIME, KeyboardTheme.getKeyboardTheme(mPrefs));
+ mLatinIME, KeyboardTheme.getKeyboardTheme(mLatinIME /* context */));
if (themeUpdated && mKeyboardView != null) {
mLatinIME.setInputView(onCreateInputView(mIsHardwareAcceleratedDrawingEnabled));
}
@@ -348,7 +343,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
}
updateKeyboardThemeAndContextThemeWrapper(
- mLatinIME, KeyboardTheme.getKeyboardTheme(mPrefs));
+ mLatinIME, KeyboardTheme.getKeyboardTheme(mLatinIME /* context */));
mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
R.layout.input_view, null);
mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame);
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
index 7161d3f26..6d8c8b76f 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
@@ -16,14 +16,17 @@
package com.android.inputmethod.keyboard;
+import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build.VERSION_CODES;
+import android.preference.PreferenceManager;
import android.util.Log;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.compat.BuildCompatUtils;
import com.android.inputmethod.latin.R;
+import java.util.ArrayList;
import java.util.Arrays;
public final class KeyboardTheme implements Comparable<KeyboardTheme> {
@@ -40,7 +43,10 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
public static final int THEME_ID_LXX_DARK = 4;
public static final int DEFAULT_THEME_ID = THEME_ID_KLP;
- private static final KeyboardTheme[] KEYBOARD_THEMES = {
+ private static KeyboardTheme[] AVAILABLE_KEYBOARD_THEMES;
+
+ @UsedForTesting
+ static final KeyboardTheme[] KEYBOARD_THEMES = {
new KeyboardTheme(THEME_ID_ICS, "ICS", R.style.KeyboardTheme_ICS,
// This has never been selected because we support ICS or later.
VERSION_CODES.BASE),
@@ -93,9 +99,10 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
}
@UsedForTesting
- static KeyboardTheme searchKeyboardThemeById(final int themeId) {
+ static KeyboardTheme searchKeyboardThemeById(final int themeId,
+ final KeyboardTheme[] availableThemeIds) {
// TODO: This search algorithm isn't optimal if there are many themes.
- for (final KeyboardTheme theme : KEYBOARD_THEMES) {
+ for (final KeyboardTheme theme : availableThemeIds) {
if (theme.mThemeId == themeId) {
return theme;
}
@@ -105,13 +112,14 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
@UsedForTesting
static KeyboardTheme getDefaultKeyboardTheme(final SharedPreferences prefs,
- final int sdkVersion) {
+ final int sdkVersion, final KeyboardTheme[] availableThemeArray) {
final String klpThemeIdString = prefs.getString(KLP_KEYBOARD_THEME_KEY, null);
if (klpThemeIdString != null) {
if (sdkVersion <= VERSION_CODES.KITKAT) {
try {
final int themeId = Integer.parseInt(klpThemeIdString);
- final KeyboardTheme theme = searchKeyboardThemeById(themeId);
+ final KeyboardTheme theme = searchKeyboardThemeById(themeId,
+ availableThemeArray);
if (theme != null) {
return theme;
}
@@ -125,22 +133,21 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
prefs.edit().remove(KLP_KEYBOARD_THEME_KEY).apply();
}
// TODO: This search algorithm isn't optimal if there are many themes.
- for (final KeyboardTheme theme : KEYBOARD_THEMES) {
+ for (final KeyboardTheme theme : availableThemeArray) {
if (sdkVersion >= theme.mMinApiVersion) {
return theme;
}
}
- return searchKeyboardThemeById(DEFAULT_THEME_ID);
+ return searchKeyboardThemeById(DEFAULT_THEME_ID, availableThemeArray);
}
public static String getKeyboardThemeName(final int themeId) {
- final KeyboardTheme theme = searchKeyboardThemeById(themeId);
+ final KeyboardTheme theme = searchKeyboardThemeById(themeId, KEYBOARD_THEMES);
return theme.mThemeName;
}
- public static void saveKeyboardThemeId(final String themeIdString,
- final SharedPreferences prefs) {
- saveKeyboardThemeId(themeIdString, prefs, BuildCompatUtils.EFFECTIVE_SDK_INT);
+ public static void saveKeyboardThemeId(final int themeId, final SharedPreferences prefs) {
+ saveKeyboardThemeId(themeId, prefs, BuildCompatUtils.EFFECTIVE_SDK_INT);
}
@UsedForTesting
@@ -152,25 +159,45 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
}
@UsedForTesting
- static void saveKeyboardThemeId(final String themeIdString,
- final SharedPreferences prefs, final int sdkVersion) {
+ static void saveKeyboardThemeId(final int themeId, final SharedPreferences prefs,
+ final int sdkVersion) {
final String prefKey = getPreferenceKey(sdkVersion);
- prefs.edit().putString(prefKey, themeIdString).apply();
+ prefs.edit().putString(prefKey, Integer.toString(themeId)).apply();
}
- public static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs) {
- return getKeyboardTheme(prefs, BuildCompatUtils.EFFECTIVE_SDK_INT);
+ public static KeyboardTheme getKeyboardTheme(final Context context) {
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ final KeyboardTheme[] availableThemeArray = getAvailableThemeArray(context);
+ return getKeyboardTheme(prefs, BuildCompatUtils.EFFECTIVE_SDK_INT, availableThemeArray);
+ }
+
+ static KeyboardTheme[] getAvailableThemeArray(final Context context) {
+ if (AVAILABLE_KEYBOARD_THEMES == null) {
+ final int[] availableThemeIdStringArray = context.getResources().getIntArray(
+ R.array.keyboard_theme_ids);
+ final ArrayList<KeyboardTheme> availableThemeList = new ArrayList<>();
+ for (final int id : availableThemeIdStringArray) {
+ final KeyboardTheme theme = searchKeyboardThemeById(id, KEYBOARD_THEMES);
+ if (theme != null) {
+ availableThemeList.add(theme);
+ }
+ }
+ AVAILABLE_KEYBOARD_THEMES = availableThemeList.toArray(
+ new KeyboardTheme[availableThemeList.size()]);
+ }
+ return AVAILABLE_KEYBOARD_THEMES;
}
@UsedForTesting
- static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs, final int sdkVersion) {
+ static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs, final int sdkVersion,
+ final KeyboardTheme[] availableThemeArray) {
final String lxxThemeIdString = prefs.getString(LXX_KEYBOARD_THEME_KEY, null);
if (lxxThemeIdString == null) {
- return getDefaultKeyboardTheme(prefs, sdkVersion);
+ return getDefaultKeyboardTheme(prefs, sdkVersion, availableThemeArray);
}
try {
final int themeId = Integer.parseInt(lxxThemeIdString);
- final KeyboardTheme theme = searchKeyboardThemeById(themeId);
+ final KeyboardTheme theme = searchKeyboardThemeById(themeId, availableThemeArray);
if (theme != null) {
return theme;
}
@@ -180,6 +207,6 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
}
// Remove preference that contains unknown or illegal theme id.
prefs.edit().remove(LXX_KEYBOARD_THEME_KEY).apply();
- return getDefaultKeyboardTheme(prefs, sdkVersion);
+ return getDefaultKeyboardTheme(prefs, sdkVersion, availableThemeArray);
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index bb3cbb0eb..98cd1da54 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -343,7 +343,9 @@ public class KeyboardView extends View {
final int keyWidth = key.getDrawWidth();
final int keyHeight = key.getHeight();
final int bgWidth, bgHeight, bgX, bgY;
- if (key.needsToKeepBackgroundAspectRatio(mDefaultKeyLabelFlags)) {
+ if (key.needsToKeepBackgroundAspectRatio(mDefaultKeyLabelFlags)
+ // HACK: To disable expanding normal/functional key background.
+ && !key.hasCustomActionLabel()) {
final int intrinsicWidth = background.getIntrinsicWidth();
final int intrinsicHeight = background.getIntrinsicHeight();
final float minScale = Math.min(
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index c20546607..eced45ea5 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
@@ -61,9 +61,9 @@ public class DictionaryFacilitator {
// dictionary.
private static final int CAPITALIZED_FORM_MAX_PROBABILITY_FOR_INSERT = 140;
- private DictionaryGroup mDictionaryGroup = new DictionaryGroup();
+ private DictionaryGroup[] mDictionaryGroups = new DictionaryGroup[] { new DictionaryGroup() };
private boolean mIsUserDictEnabled = false;
- private volatile CountDownLatch mLatchForWaitingLoadingMainDictionary = new CountDownLatch(0);
+ private volatile CountDownLatch mLatchForWaitingLoadingMainDictionaries = new CountDownLatch(0);
// To synchronize assigning mDictionaryGroup to ensure closing dictionaries.
private final Object mLock = new Object();
private final DistracterFilter mDistracterFilter;
@@ -193,8 +193,9 @@ public class DictionaryFacilitator {
mPersonalizationHelper.setIsMonolingualUser(isMonolingualUser);
}
+ // TODO: remove this, replace with version returning multiple locales
public Locale getLocale() {
- return mDictionaryGroup.mLocale;
+ return mDictionaryGroups[0].mLocale;
}
private static ExpandableBinaryDictionary getSubDict(final String dictType,
@@ -226,6 +227,21 @@ public class DictionaryFacilitator {
usePersonalizedDicts, forceReloadMainDictionary, listener, "" /* dictNamePrefix */);
}
+ private DictionaryGroup findDictionaryGroupWithLocale(final DictionaryGroup[] dictionaryGroups,
+ final Locale locale) {
+ for (int i = 0; i < dictionaryGroups.length; ++i) {
+ if (locale.equals(dictionaryGroups[i].mLocale)) {
+ return dictionaryGroups[i];
+ }
+ }
+ return null;
+ }
+
+ private DictionaryGroup getDictionaryGroupForActiveLanguage() {
+ // TODO: implement this
+ return mDictionaryGroups[0];
+ }
+
public void resetDictionariesWithDictNamePrefix(final Context context,
final Locale newLocaleToUse,
final boolean useContactsDict, final boolean usePersonalizedDicts,
@@ -252,7 +268,7 @@ public class DictionaryFacilitator {
final ArrayList<String> dictsForLocale = new ArrayList<>();
existingDictsToCleanup.put(newLocale, dictsForLocale);
final DictionaryGroup currentDictionaryGroupForLocale =
- newLocale.equals(mDictionaryGroup.mLocale) ? mDictionaryGroup : null;
+ findDictionaryGroupWithLocale(mDictionaryGroups, newLocale);
if (null == currentDictionaryGroupForLocale) {
continue;
}
@@ -266,10 +282,11 @@ public class DictionaryFacilitator {
}
}
- final HashMap<Locale, DictionaryGroup> newDictionaryGroups = new HashMap<>();
- for (final Locale newLocale : newLocales) {
+ final DictionaryGroup[] newDictionaryGroups = new DictionaryGroup[newLocales.length];
+ for (int i = 0; i < newLocales.length; ++i) {
+ final Locale newLocale = newLocales[i];
final DictionaryGroup dictionaryGroupForLocale =
- newLocale.equals(mDictionaryGroup.mLocale) ? mDictionaryGroup : null;
+ findDictionaryGroupWithLocale(mDictionaryGroups, newLocale);
final ArrayList<String> dictsToCleanupForLocale = existingDictsToCleanup.get(newLocale);
final boolean noExistingDictsForThisLocale = (null == dictionaryGroupForLocale);
@@ -297,30 +314,29 @@ public class DictionaryFacilitator {
}
subDicts.put(subDictType, subDict);
}
- newDictionaryGroups.put(newLocale, new DictionaryGroup(newLocale, mainDict, subDicts));
+ newDictionaryGroups[i] = new DictionaryGroup(newLocale, mainDict, subDicts);
}
// Replace Dictionaries.
- // TODO: use multiple locales.
- final DictionaryGroup newDictionaryGroup = newDictionaryGroups.get(newLocaleToUse);
- final DictionaryGroup oldDictionaryGroup;
+ final DictionaryGroup[] oldDictionaryGroups;
synchronized (mLock) {
- oldDictionaryGroup = mDictionaryGroup;
- mDictionaryGroup = newDictionaryGroup;
+ oldDictionaryGroups = mDictionaryGroups;
+ mDictionaryGroups = newDictionaryGroups;
mIsUserDictEnabled = UserBinaryDictionary.isEnabled(context);
- if (null == newDictionaryGroup.getDict(Dictionary.TYPE_MAIN)) {
+ if (hasAtLeastOneUninitializedMainDictionary()) {
asyncReloadUninitializedMainDictionaries(context, newLocales, listener);
}
}
if (listener != null) {
- listener.onUpdateMainDictionaryAvailability(hasInitializedMainDictionary());
+ listener.onUpdateMainDictionaryAvailability(hasAtLeastOneInitializedMainDictionary());
}
// Clean up old dictionaries.
for (final Locale localeToCleanUp : existingDictsToCleanup.keySet()) {
final ArrayList<String> dictTypesToCleanUp =
existingDictsToCleanup.get(localeToCleanUp);
- final DictionaryGroup dictionarySetToCleanup = oldDictionaryGroup;
+ final DictionaryGroup dictionarySetToCleanup =
+ findDictionaryGroupWithLocale(oldDictionaryGroups, localeToCleanUp);
for (final String dictType : dictTypesToCleanUp) {
dictionarySetToCleanup.closeDict(dictType);
}
@@ -330,12 +346,18 @@ public class DictionaryFacilitator {
private void asyncReloadUninitializedMainDictionaries(final Context context,
final Locale[] locales, final DictionaryInitializationListener listener) {
final CountDownLatch latchForWaitingLoadingMainDictionary = new CountDownLatch(1);
- mLatchForWaitingLoadingMainDictionary = latchForWaitingLoadingMainDictionary;
+ mLatchForWaitingLoadingMainDictionaries = latchForWaitingLoadingMainDictionary;
ExecutorUtils.getExecutor("InitializeBinaryDictionary").execute(new Runnable() {
@Override
public void run() {
for (final Locale locale : locales) {
- final DictionaryGroup dictionaryGroup = mDictionaryGroup;
+ final DictionaryGroup dictionaryGroup =
+ findDictionaryGroupWithLocale(mDictionaryGroups, locale);
+ if (null == dictionaryGroup) {
+ // This should never happen, but better safe than crashy
+ Log.w(TAG, "Expected a dictionary group for " + locale + " but none found");
+ continue;
+ }
final Dictionary mainDict =
DictionaryFactory.createMainDictionaryFromManager(context, locale);
synchronized (mLock) {
@@ -348,7 +370,8 @@ public class DictionaryFacilitator {
}
}
if (listener != null) {
- listener.onUpdateMainDictionaryAvailability(hasInitializedMainDictionary());
+ listener.onUpdateMainDictionaryAvailability(
+ hasAtLeastOneInitializedMainDictionary());
}
latchForWaitingLoadingMainDictionary.countDown();
}
@@ -381,17 +404,20 @@ public class DictionaryFacilitator {
subDicts.put(dictType, dict);
}
}
- mDictionaryGroup = new DictionaryGroup(locale, mainDictionary, subDicts);
+ mDictionaryGroups = new DictionaryGroup[] {
+ new DictionaryGroup(locale, mainDictionary, subDicts) };
}
public void closeDictionaries() {
- final DictionaryGroup dictionaryGroup;
+ final DictionaryGroup[] dictionaryGroups;
synchronized (mLock) {
- dictionaryGroup = mDictionaryGroup;
- mDictionaryGroup = new DictionaryGroup();
+ dictionaryGroups = mDictionaryGroups;
+ mDictionaryGroups = new DictionaryGroup[] { new DictionaryGroup() };
}
- for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
- dictionaryGroup.closeDict(dictType);
+ for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+ for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
+ dictionaryGroup.closeDict(dictType);
+ }
}
mDistracterFilter.close();
if (mPersonalizationHelper != null) {
@@ -401,40 +427,71 @@ public class DictionaryFacilitator {
@UsedForTesting
public ExpandableBinaryDictionary getSubDictForTesting(final String dictName) {
- return mDictionaryGroup.getSubDict(dictName);
+ return mDictionaryGroups[0].getSubDict(dictName);
}
- // The main dictionary could have been loaded asynchronously. Don't cache the return value
- // of this method.
- public boolean hasInitializedMainDictionary() {
- final Dictionary mainDict = mDictionaryGroup.getDict(Dictionary.TYPE_MAIN);
- return mainDict != null && mainDict.isInitialized();
+ // The main dictionaries are loaded asynchronously. Don't cache the return value
+ // of these methods.
+ public boolean hasAtLeastOneInitializedMainDictionary() {
+ final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+ for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+ final Dictionary mainDict = dictionaryGroup.getDict(Dictionary.TYPE_MAIN);
+ if (mainDict != null && mainDict.isInitialized()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean hasAtLeastOneUninitializedMainDictionary() {
+ final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+ for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+ final Dictionary mainDict = dictionaryGroup.getDict(Dictionary.TYPE_MAIN);
+ if (mainDict == null || !mainDict.isInitialized()) {
+ return true;
+ }
+ }
+ return false;
}
public boolean hasPersonalizationDictionary() {
- return mDictionaryGroup.hasDict(Dictionary.TYPE_PERSONALIZATION);
+ final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+ for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+ if (dictionaryGroup.hasDict(Dictionary.TYPE_PERSONALIZATION)) {
+ return true;
+ }
+ }
+ return false;
}
public void flushPersonalizationDictionary() {
- final ExpandableBinaryDictionary personalizationDictUsedForSuggestion =
- mDictionaryGroup.getSubDict(Dictionary.TYPE_PERSONALIZATION);
+ final HashSet<ExpandableBinaryDictionary> personalizationDictsUsedForSuggestion =
+ new HashSet<>();
+ final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+ for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+ final ExpandableBinaryDictionary personalizationDictUsedForSuggestion =
+ dictionaryGroup.getSubDict(Dictionary.TYPE_PERSONALIZATION);
+ personalizationDictsUsedForSuggestion.add(personalizationDictUsedForSuggestion);
+ }
mPersonalizationHelper.flushPersonalizationDictionariesToUpdate(
- personalizationDictUsedForSuggestion);
+ personalizationDictsUsedForSuggestion);
mDistracterFilter.close();
}
- public void waitForLoadingMainDictionary(final long timeout, final TimeUnit unit)
+ public void waitForLoadingMainDictionaries(final long timeout, final TimeUnit unit)
throws InterruptedException {
- mLatchForWaitingLoadingMainDictionary.await(timeout, unit);
+ mLatchForWaitingLoadingMainDictionaries.await(timeout, unit);
}
@UsedForTesting
public void waitForLoadingDictionariesForTesting(final long timeout, final TimeUnit unit)
throws InterruptedException {
- waitForLoadingMainDictionary(timeout, unit);
- final Map<String, ExpandableBinaryDictionary> dictMap = mDictionaryGroup.mSubDictMap;
- for (final ExpandableBinaryDictionary dict : dictMap.values()) {
- dict.waitAllTasksForTests();
+ waitForLoadingMainDictionaries(timeout, unit);
+ final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+ for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+ for (final ExpandableBinaryDictionary dict : dictionaryGroup.mSubDictMap.values()) {
+ dict.waitAllTasksForTests();
+ }
}
}
@@ -453,7 +510,7 @@ public class DictionaryFacilitator {
public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized,
final PrevWordsInfo prevWordsInfo, final int timeStampInSeconds,
final boolean blockPotentiallyOffensive) {
- final DictionaryGroup dictionaryGroup = mDictionaryGroup;
+ final DictionaryGroup dictionaryGroup = getDictionaryGroupForActiveLanguage();
final String[] words = suggestion.split(Constants.WORD_SEPARATOR);
PrevWordsInfo prevWordsInfoForCurrentWord = prevWordsInfo;
for (int i = 0; i < words.length; i++) {
@@ -520,7 +577,8 @@ public class DictionaryFacilitator {
}
private void removeWord(final String dictName, final String word) {
- final ExpandableBinaryDictionary dictionary = mDictionaryGroup.getSubDict(dictName);
+ final ExpandableBinaryDictionary dictionary =
+ getDictionaryGroupForActiveLanguage().getSubDict(dictName);
if (dictionary != null) {
dictionary.removeUnigramEntryDynamically(word);
}
@@ -536,20 +594,22 @@ public class DictionaryFacilitator {
public SuggestionResults getSuggestionResults(final WordComposer composer,
final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo,
final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId) {
- final DictionaryGroup dictionaryGroup = mDictionaryGroup;
+ final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
final SuggestionResults suggestionResults =
new SuggestionResults(SuggestedWords.MAX_SUGGESTIONS);
final float[] languageWeight = new float[] { Dictionary.NOT_A_LANGUAGE_WEIGHT };
- for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
- final Dictionary dictionary = dictionaryGroup.getDict(dictType);
- if (null == dictionary) continue;
- final ArrayList<SuggestedWordInfo> dictionarySuggestions =
- dictionary.getSuggestions(composer, prevWordsInfo, proximityInfo,
- settingsValuesForSuggestion, sessionId, languageWeight);
- if (null == dictionarySuggestions) continue;
- suggestionResults.addAll(dictionarySuggestions);
- if (null != suggestionResults.mRawSuggestions) {
- suggestionResults.mRawSuggestions.addAll(dictionarySuggestions);
+ for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+ for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
+ final Dictionary dictionary = dictionaryGroup.getDict(dictType);
+ if (null == dictionary) continue;
+ final ArrayList<SuggestedWordInfo> dictionarySuggestions =
+ dictionary.getSuggestions(composer, prevWordsInfo, proximityInfo,
+ settingsValuesForSuggestion, sessionId, languageWeight);
+ if (null == dictionarySuggestions) continue;
+ suggestionResults.addAll(dictionarySuggestions);
+ if (null != suggestionResults.mRawSuggestions) {
+ suggestionResults.mRawSuggestions.addAll(dictionarySuggestions);
+ }
}
}
return suggestionResults;
@@ -559,20 +619,22 @@ public class DictionaryFacilitator {
if (TextUtils.isEmpty(word)) {
return false;
}
- final DictionaryGroup dictionaryGroup = mDictionaryGroup;
- if (dictionaryGroup.mLocale == null) {
- return false;
- }
- final String lowerCasedWord = word.toLowerCase(dictionaryGroup.mLocale);
- for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
- final Dictionary dictionary = dictionaryGroup.getDict(dictType);
- // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and
- // would be immutable once it's finished initializing, but concretely a null test is
- // probably good enough for the time being.
- if (null == dictionary) continue;
- if (dictionary.isValidWord(word)
- || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) {
- return true;
+ final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+ for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+ if (dictionaryGroup.mLocale == null) {
+ continue;
+ }
+ final String lowerCasedWord = word.toLowerCase(dictionaryGroup.mLocale);
+ for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
+ final Dictionary dictionary = dictionaryGroup.getDict(dictType);
+ // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and
+ // would be immutable once it's finished initializing, but concretely a null test is
+ // probably good enough for the time being.
+ if (null == dictionary) continue;
+ if (dictionary.isValidWord(word)
+ || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) {
+ return true;
+ }
}
}
return false;
@@ -584,18 +646,20 @@ public class DictionaryFacilitator {
return Dictionary.NOT_A_PROBABILITY;
}
int maxFreq = Dictionary.NOT_A_PROBABILITY;
- final DictionaryGroup dictionaryGroup = mDictionaryGroup;
- for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
- final Dictionary dictionary = dictionaryGroup.getDict(dictType);
- if (dictionary == null) continue;
- final int tempFreq;
- if (isGettingMaxFrequencyOfExactMatches) {
- tempFreq = dictionary.getMaxFrequencyOfExactMatches(word);
- } else {
- tempFreq = dictionary.getFrequency(word);
- }
- if (tempFreq >= maxFreq) {
- maxFreq = tempFreq;
+ final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+ for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+ for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) {
+ final Dictionary dictionary = dictionaryGroup.getDict(dictType);
+ if (dictionary == null) continue;
+ final int tempFreq;
+ if (isGettingMaxFrequencyOfExactMatches) {
+ tempFreq = dictionary.getMaxFrequencyOfExactMatches(word);
+ } else {
+ tempFreq = dictionary.getFrequency(word);
+ }
+ if (tempFreq >= maxFreq) {
+ maxFreq = tempFreq;
+ }
}
}
return maxFreq;
@@ -610,9 +674,12 @@ public class DictionaryFacilitator {
}
private void clearSubDictionary(final String dictName) {
- final ExpandableBinaryDictionary dictionary = mDictionaryGroup.getSubDict(dictName);
- if (dictionary != null) {
- dictionary.clear();
+ final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+ for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+ final ExpandableBinaryDictionary dictionary = dictionaryGroup.getSubDict(dictName);
+ if (dictionary != null) {
+ dictionary.clear();
+ }
}
}
@@ -641,8 +708,10 @@ public class DictionaryFacilitator {
public void addPhraseToContextualDictionary(final String[] phrase, final int probability,
final int bigramProbabilityForWords, final int bigramProbabilityForPhrases) {
+ // TODO: we're inserting the phrase into the dictionary for the active language. Rethink
+ // this a bit from a theoretical point of view.
final ExpandableBinaryDictionary contextualDict =
- mDictionaryGroup.getSubDict(Dictionary.TYPE_CONTEXTUAL);
+ getDictionaryGroupForActiveLanguage().getSubDict(Dictionary.TYPE_CONTEXTUAL);
if (contextualDict == null) {
return;
}
@@ -675,22 +744,27 @@ public class DictionaryFacilitator {
}
public void dumpDictionaryForDebug(final String dictName) {
- final ExpandableBinaryDictionary dictToDump = mDictionaryGroup.getSubDict(dictName);
- if (dictToDump == null) {
- Log.e(TAG, "Cannot dump " + dictName + ". "
- + "The dictionary is not being used for suggestion or cannot be dumped.");
- return;
+ final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+ for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+ final ExpandableBinaryDictionary dictToDump = dictionaryGroup.getSubDict(dictName);
+ if (dictToDump == null) {
+ Log.e(TAG, "Cannot dump " + dictName + ". "
+ + "The dictionary is not being used for suggestion or cannot be dumped.");
+ return;
+ }
+ dictToDump.dumpAllWordsForDebug();
}
- dictToDump.dumpAllWordsForDebug();
}
public ArrayList<Pair<String, DictionaryStats>> getStatsOfEnabledSubDicts() {
final ArrayList<Pair<String, DictionaryStats>> statsOfEnabledSubDicts = new ArrayList<>();
- final DictionaryGroup dictionaryGroup = mDictionaryGroup;
- for (final String dictType : SUB_DICT_TYPES) {
- final ExpandableBinaryDictionary dictionary = dictionaryGroup.getSubDict(dictType);
- if (dictionary == null) continue;
- statsOfEnabledSubDicts.add(new Pair<>(dictType, dictionary.getDictionaryStats()));
+ final DictionaryGroup[] dictionaryGroups = mDictionaryGroups;
+ for (final DictionaryGroup dictionaryGroup : dictionaryGroups) {
+ for (final String dictType : SUB_DICT_TYPES) {
+ final ExpandableBinaryDictionary dictionary = dictionaryGroup.getSubDict(dictType);
+ if (dictionary == null) continue;
+ statsOfEnabledSubDicts.add(new Pair<>(dictType, dictionary.getDictionaryStats()));
+ }
}
return statsOfEnabledSubDicts;
}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
index fa0265d86..ff4a6bde1 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java
@@ -84,7 +84,7 @@ public class DictionaryFacilitatorLruCache {
private void waitForLoadingMainDictionary(final DictionaryFacilitator dictionaryFacilitator) {
for (int i = 0; i < MAX_RETRY_COUNT_FOR_WAITING_FOR_LOADING_DICT; i++) {
try {
- dictionaryFacilitator.waitForLoadingMainDictionary(
+ dictionaryFacilitator.waitForLoadingMainDictionaries(
WAIT_FOR_LOADING_MAIN_DICT_IN_MILLISECONDS, TimeUnit.MILLISECONDS);
return;
} catch (final InterruptedException e) {
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index a1dd67f27..671ba6714 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -156,23 +156,25 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
}
private void asyncExecuteTaskWithWriteLock(final Runnable task) {
- asyncExecuteTaskWithLock(mLock.writeLock(), task);
+ asyncExecuteTaskWithLock(mLock.writeLock(), mDictName /* executorName */, task);
}
- private void asyncExecuteTaskWithLock(final Lock lock, final Runnable task) {
- asyncPreCheckAndExecuteTaskWithLock(lock, null /* preCheckTask */, task);
+ private void asyncExecuteTaskWithLock(final Lock lock, final String executorName,
+ final Runnable task) {
+ asyncPreCheckAndExecuteTaskWithLock(lock, null /* preCheckTask */, executorName, task);
}
private void asyncPreCheckAndExecuteTaskWithWriteLock(
final Callable<Boolean> preCheckTask, final Runnable task) {
- asyncPreCheckAndExecuteTaskWithLock(mLock.writeLock(), preCheckTask, task);
+ asyncPreCheckAndExecuteTaskWithLock(mLock.writeLock(), preCheckTask,
+ mDictName /* executorName */, task);
}
// Execute task with lock when the result of preCheckTask is true or preCheckTask is null.
private void asyncPreCheckAndExecuteTaskWithLock(final Lock lock,
- final Callable<Boolean> preCheckTask, final Runnable task) {
- ExecutorUtils.getExecutor(mDictName).execute(new Runnable() {
+ final Callable<Boolean> preCheckTask, final String executorName, final Runnable task) {
+ ExecutorUtils.getExecutor(executorName).execute(new Runnable() {
@Override
public void run() {
if (preCheckTask != null) {
@@ -676,10 +678,10 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
public void dumpAllWordsForDebug() {
reloadDictionaryIfRequired();
- asyncExecuteTaskWithLock(mLock.readLock(), new Runnable() {
+ asyncExecuteTaskWithLock(mLock.readLock(), "dumpAllWordsForDebug", new Runnable() {
@Override
public void run() {
- Log.d(TAG, "Dump dictionary: " + mDictName);
+ Log.d(TAG, "Dump dictionary: " + mDictName + " for " + mLocale);
try {
final DictionaryHeader header = mBinaryDictionary.getHeader();
Log.d(TAG, "Format version: " + mBinaryDictionary.getFormatVersion());
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 0a64c4c26..475782042 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1000,7 +1000,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mHandler.cancelUpdateSuggestionStrip();
mainKeyboardView.setMainDictionaryAvailability(
- mDictionaryFacilitator.hasInitializedMainDictionary());
+ mDictionaryFacilitator.hasAtLeastOneInitializedMainDictionary());
mainKeyboardView.setKeyPreviewPopupEnabled(currentSettingsValues.mKeyPreviewPopupOn,
currentSettingsValues.mKeyPreviewPopupDismissDelay);
mainKeyboardView.setSlidingKeyInputPreviewEnabled(
diff --git a/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java
index 43cebdfa4..396d062f8 100644
--- a/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java
@@ -88,17 +88,17 @@ public class PersonalizationHelperForDictionaryFacilitator {
/**
* Flush personalization dictionaries to dictionary files. Close dictionaries after writing
- * files except the dictionary that is used for generating suggestions.
+ * files except the dictionaries that is used for generating suggestions.
*
- * @param personalizationDictUsedForSuggestion the personalization dictionary used for
+ * @param personalizationDictsUsedForSuggestion the personalization dictionaries used for
* generating suggestions that won't be closed.
*/
public void flushPersonalizationDictionariesToUpdate(
- final ExpandableBinaryDictionary personalizationDictUsedForSuggestion) {
+ final HashSet<ExpandableBinaryDictionary> personalizationDictsUsedForSuggestion) {
for (final ExpandableBinaryDictionary personalizationDict :
mPersonalizationDictsToUpdate.values()) {
personalizationDict.asyncFlushBinaryDictionary();
- if (personalizationDict != personalizationDictUsedForSuggestion) {
+ if (!personalizationDictsUsedForSuggestion.contains(personalizationDict)) {
// Close if the dictionary is not being used for suggestion.
personalizationDict.close();
}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 9e4aa40a2..4ad5ba65e 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -157,7 +157,7 @@ public final class Suggest {
if (!isCorrectionEnabled || !allowsToBeAutoCorrected || resultsArePredictions
|| suggestionResults.isEmpty() || wordComposer.hasDigits()
|| wordComposer.isMostlyCaps() || wordComposer.isResumed()
- || !mDictionaryFacilitator.hasInitializedMainDictionary()
+ || !mDictionaryFacilitator.hasAtLeastOneInitializedMainDictionary()
|| suggestionResults.first().isKindOf(SuggestedWordInfo.KIND_SHORTCUT)) {
// If we don't have a main dictionary, we never want to auto-correct. The reason for
// this is, the user may have a contact whose name happens to match a valid word in
@@ -235,7 +235,7 @@ public final class Suggest {
SuggestedWordInfo.removeDups(null /* typedWord */, suggestionsContainer);
// For some reason some suggestions with MIN_VALUE are making their way here.
- // TODO: Find a more robust way to detect distractors.
+ // TODO: Find a more robust way to detect distracters.
for (int i = suggestionsContainer.size() - 1; i >= 0; --i) {
if (suggestionsContainer.get(i).mScore < SUPPRESS_SUGGEST_THRESHOLD) {
suggestionsContainer.remove(i);
diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java
index 32d1fe372..567aa07f1 100644
--- a/java/src/com/android/inputmethod/latin/WordComposer.java
+++ b/java/src/com/android/inputmethod/latin/WordComposer.java
@@ -49,6 +49,7 @@ public final class WordComposer {
private final ArrayList<Event> mEvents;
private final InputPointers mInputPointers = new InputPointers(MAX_WORD_LENGTH);
private String mAutoCorrection;
+ private String mAutoCorrectionDictionaryType;
private boolean mIsResumed;
private boolean mIsBatchMode;
// A memory of the last rejected batch mode suggestion, if any. This goes like this: the user
@@ -418,8 +419,9 @@ public final class WordComposer {
/**
* Sets the auto-correction for this word.
*/
- public void setAutoCorrection(final String correction) {
+ public void setAutoCorrection(final String correction, String dictType) {
mAutoCorrection = correction;
+ mAutoCorrectionDictionaryType = dictType;
}
/**
@@ -430,6 +432,13 @@ public final class WordComposer {
}
/**
+ * @return the auto-correction dictionary type or null if none.
+ */
+ public String getAutoCorrectionDictionaryTypeOrNull() {
+ return mAutoCorrectionDictionaryType;
+ }
+
+ /**
* @return whether we started composing this word by resuming suggestion on an existing string
*/
public boolean isResumed() {
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index c5e60d677..0942c078f 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -612,14 +612,21 @@ public final class InputLogic {
final SettingsValues settingsValues, final LatinIME.UIHandler handler) {
if (SuggestedWords.EMPTY != suggestedWords) {
final String autoCorrection;
+ final String dictType;
if (suggestedWords.mWillAutoCorrect) {
- autoCorrection = suggestedWords.getWord(SuggestedWords.INDEX_OF_AUTO_CORRECTION);
+ SuggestedWordInfo info = suggestedWords.getInfo(
+ SuggestedWords.INDEX_OF_AUTO_CORRECTION);
+ autoCorrection = info.mWord;
+ dictType = info.mSourceDict.mDictType;
} else {
// We can't use suggestedWords.getWord(SuggestedWords.INDEX_OF_TYPED_WORD)
// because it may differ from mWordComposer.mTypedWord.
autoCorrection = suggestedWords.mTypedWord;
+ dictType = Dictionary.TYPE_USER_TYPED;
}
- mWordComposer.setAutoCorrection(autoCorrection);
+ // TODO: Use the SuggestedWordInfo to set the auto correction when
+ // user typed word is available via SuggestedWordInfo.
+ mWordComposer.setAutoCorrection(autoCorrection, dictType);
}
mSuggestedWords = suggestedWords;
final boolean newAutoCorrectionIndicator = suggestedWords.mWillAutoCorrect;
@@ -2100,6 +2107,8 @@ public final class InputLogic {
mConnection.commitCorrection(new CorrectionInfo(
mConnection.getExpectedSelectionEnd() - autoCorrection.length(),
typedWord, autoCorrection));
+ StatsUtils.onAutoCorrection(typedWord, autoCorrection, mWordComposer.isBatchMode(),
+ mWordComposer.getAutoCorrectionDictionaryTypeOrNull());
}
}
}
diff --git a/java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java
index 5a3fc3600..29289aed2 100644
--- a/java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/ThemeSettingsFragment.java
@@ -17,7 +17,6 @@
package com.android.inputmethod.latin.settings;
import android.content.Context;
-import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import android.preference.Preference;
@@ -32,12 +31,12 @@ import com.android.inputmethod.latin.settings.RadioButtonPreference.OnRadioButto
*/
public final class ThemeSettingsFragment extends SubScreenFragment
implements OnRadioButtonClickedListener {
- private String mSelectedThemeId;
+ private int mSelectedThemeId;
static class KeyboardThemePreference extends RadioButtonPreference {
- final String mThemeId;
+ final int mThemeId;
- KeyboardThemePreference(final Context context, final String name, final String id) {
+ KeyboardThemePreference(final Context context, final String name, final int id) {
super(context);
setTitle(name);
mThemeId = id;
@@ -45,14 +44,13 @@ public final class ThemeSettingsFragment extends SubScreenFragment
}
static void updateKeyboardThemeSummary(final Preference pref) {
- final Resources res = pref.getContext().getResources();
- final SharedPreferences prefs = pref.getSharedPreferences();
- final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(prefs);
- final String keyboardThemeId = String.valueOf(keyboardTheme.mThemeId);
+ final Context context = pref.getContext();
+ final Resources res = context.getResources();
+ final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(context);
final String[] keyboardThemeNames = res.getStringArray(R.array.keyboard_theme_names);
- final String[] keyboardThemeIds = res.getStringArray(R.array.keyboard_theme_ids);
+ final int[] keyboardThemeIds = res.getIntArray(R.array.keyboard_theme_ids);
for (int index = 0; index < keyboardThemeNames.length; index++) {
- if (keyboardThemeId.equals(keyboardThemeIds[index])) {
+ if (keyboardTheme.mThemeId == keyboardThemeIds[index]) {
pref.setSummary(keyboardThemeNames[index]);
return;
}
@@ -64,18 +62,18 @@ public final class ThemeSettingsFragment extends SubScreenFragment
super.onCreate(icicle);
addPreferencesFromResource(R.xml.prefs_screen_theme);
final PreferenceScreen screen = getPreferenceScreen();
+ final Context context = getActivity();
final Resources res = getResources();
final String[] keyboardThemeNames = res.getStringArray(R.array.keyboard_theme_names);
- final String[] keyboardThemeIds = res.getStringArray(R.array.keyboard_theme_ids);
+ final int[] keyboardThemeIds = res.getIntArray(R.array.keyboard_theme_ids);
for (int index = 0; index < keyboardThemeNames.length; index++) {
final KeyboardThemePreference pref = new KeyboardThemePreference(
- getActivity(), keyboardThemeNames[index], keyboardThemeIds[index]);
+ context, keyboardThemeNames[index], keyboardThemeIds[index]);
screen.addPreference(pref);
pref.setOnRadioButtonClickedListener(this);
}
- final SharedPreferences prefs = getSharedPreferences();
- final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(prefs);
- mSelectedThemeId = String.valueOf(keyboardTheme.mThemeId);
+ final KeyboardTheme keyboardTheme = KeyboardTheme.getKeyboardTheme(context);
+ mSelectedThemeId = keyboardTheme.mThemeId;
}
@Override
@@ -106,7 +104,7 @@ public final class ThemeSettingsFragment extends SubScreenFragment
final Preference preference = screen.getPreference(index);
if (preference instanceof KeyboardThemePreference) {
final KeyboardThemePreference pref = (KeyboardThemePreference)preference;
- final boolean selected = mSelectedThemeId.equals(pref.mThemeId);
+ final boolean selected = (mSelectedThemeId == pref.mThemeId);
pref.setSelected(selected);
}
}
diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
index 49b34d391..352391611 100644
--- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
+++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java
@@ -185,7 +185,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
try {
final DictionaryFacilitator dictionaryFacilitator =
mDictionaryFacilitatorCache.get(locale);
- return dictionaryFacilitator.hasInitializedMainDictionary();
+ return dictionaryFacilitator.hasAtLeastOneInitializedMainDictionary();
} finally {
mSemaphore.release();
}
diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
index 1db525502..f8a845304 100644
--- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java
@@ -64,9 +64,9 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
private final Object mLock = new Object();
// If the score of the top suggestion exceeds this value, the tested word (e.g.,
- // an OOV, a misspelling, or an in-vocabulary word) would be considered as a distractor to
+ // an OOV, a misspelling, or an in-vocabulary word) would be considered as a distracter to
// words in dictionary. The greater the threshold is, the less likely the tested word would
- // become a distractor, which means the tested word will be more likely to be added to
+ // become a distracter, which means the tested word will be more likely to be added to
// the dictionary.
private static final float DISTRACTER_WORD_SCORE_THRESHOLD = 0.4f;
@@ -196,7 +196,7 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
}
final boolean Word = dictionaryFacilitator.isValidWord(testedWord, false /* ignoreCase */);
if (Word) {
- // Valid word is not a distractor.
+ // Valid word is not a distracter.
if (DEBUG) {
Log.d(TAG, "isDistracter: false (valid word)");
}
@@ -257,12 +257,12 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr
return false;
}
final SuggestedWordInfo firstSuggestion = suggestionResults.first();
- final boolean isDistractor = suggestionExceedsDistracterThreshold(
+ final boolean isDistracter = suggestionExceedsDistracterThreshold(
firstSuggestion, consideredWord, DISTRACTER_WORD_SCORE_THRESHOLD);
if (DEBUG) {
- Log.d(TAG, "isDistracter: " + isDistractor);
+ Log.d(TAG, "isDistracter: " + isDistracter);
}
- return isDistractor;
+ return isDistracter;
}
private static boolean suggestionExceedsDistracterThreshold(final SuggestedWordInfo suggestion,
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 81e2ff548..440b963d9 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -259,20 +259,21 @@ static jint latinime_BinaryDictionary_getProbability(JNIEnv *env, jclass clazz,
jintArray word) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
if (!dictionary) return NOT_A_PROBABILITY;
- const jsize wordLength = env->GetArrayLength(word);
- int codePoints[wordLength];
- env->GetIntArrayRegion(word, 0, wordLength, codePoints);
- return dictionary->getProbability(codePoints, wordLength);
+ const jsize codePointCount = env->GetArrayLength(word);
+ int codePoints[codePointCount];
+ env->GetIntArrayRegion(word, 0, codePointCount, codePoints);
+ return dictionary->getProbability(CodePointArrayView(codePoints, codePointCount));
}
static jint latinime_BinaryDictionary_getMaxProbabilityOfExactMatches(
JNIEnv *env, jclass clazz, jlong dict, jintArray word) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
if (!dictionary) return NOT_A_PROBABILITY;
- const jsize wordLength = env->GetArrayLength(word);
- int codePoints[wordLength];
- env->GetIntArrayRegion(word, 0, wordLength, codePoints);
- return dictionary->getMaxProbabilityOfExactMatches(codePoints, wordLength);
+ const jsize codePointCount = env->GetArrayLength(word);
+ int codePoints[codePointCount];
+ env->GetIntArrayRegion(word, 0, codePointCount, codePoints);
+ return dictionary->getMaxProbabilityOfExactMatches(
+ CodePointArrayView(codePoints, codePointCount));
}
static jint latinime_BinaryDictionary_getNgramProbability(JNIEnv *env, jclass clazz,
@@ -285,7 +286,8 @@ static jint latinime_BinaryDictionary_getNgramProbability(JNIEnv *env, jclass cl
env->GetIntArrayRegion(word, 0, wordLength, wordCodePoints);
const PrevWordsInfo prevWordsInfo = JniDataUtils::constructPrevWordsInfo(env,
prevWordCodePointArrays, isBeginningOfSentenceArray);
- return dictionary->getNgramProbability(&prevWordsInfo, wordCodePoints, wordLength);
+ return dictionary->getNgramProbability(&prevWordsInfo,
+ CodePointArrayView(wordCodePoints, wordLength));
}
// Method to iterate all words in the dictionary for makedict.
@@ -340,7 +342,8 @@ static void latinime_BinaryDictionary_getWordProperty(JNIEnv *env, jclass clazz,
return;
}
}
- const WordProperty wordProperty = dictionary->getWordProperty(wordCodePoints, codePointCount);
+ const WordProperty wordProperty = dictionary->getWordProperty(
+ CodePointArrayView(wordCodePoints, codePointCount));
wordProperty.outputProperties(env, outCodePoints, outFlags, outProbabilityInfo,
outBigramTargets, outBigramProbabilityInfo, outShortcutTargets,
outShortcutProbabilities);
@@ -366,7 +369,8 @@ static bool latinime_BinaryDictionary_addUnigramEntry(JNIEnv *env, jclass clazz,
// Use 1 for count to indicate the word has inputted.
const UnigramProperty unigramProperty(isBeginningOfSentence, isNotAWord,
isBlacklisted, probability, timestamp, 0 /* level */, 1 /* count */, &shortcuts);
- return dictionary->addUnigramEntry(codePoints, codePointCount, &unigramProperty);
+ return dictionary->addUnigramEntry(CodePointArrayView(codePoints, codePointCount),
+ &unigramProperty);
}
static bool latinime_BinaryDictionary_removeUnigramEntry(JNIEnv *env, jclass clazz, jlong dict,
@@ -378,7 +382,7 @@ static bool latinime_BinaryDictionary_removeUnigramEntry(JNIEnv *env, jclass cla
jsize codePointCount = env->GetArrayLength(word);
int codePoints[codePointCount];
env->GetIntArrayRegion(word, 0, codePointCount, codePoints);
- return dictionary->removeUnigramEntry(codePoints, codePointCount);
+ return dictionary->removeUnigramEntry(CodePointArrayView(codePoints, codePointCount));
}
static bool latinime_BinaryDictionary_addNgramEntry(JNIEnv *env, jclass clazz, jlong dict,
@@ -410,10 +414,11 @@ static bool latinime_BinaryDictionary_removeNgramEntry(JNIEnv *env, jclass clazz
}
const PrevWordsInfo prevWordsInfo = JniDataUtils::constructPrevWordsInfo(env,
prevWordCodePointArrays, isBeginningOfSentenceArray);
- jsize wordLength = env->GetArrayLength(word);
- int wordCodePoints[wordLength];
- env->GetIntArrayRegion(word, 0, wordLength, wordCodePoints);
- return dictionary->removeNgramEntry(&prevWordsInfo, wordCodePoints, wordLength);
+ jsize codePointCount = env->GetArrayLength(word);
+ int wordCodePoints[codePointCount];
+ env->GetIntArrayRegion(word, 0, codePointCount, wordCodePoints);
+ return dictionary->removeNgramEntry(&prevWordsInfo,
+ CodePointArrayView(wordCodePoints, codePointCount));
}
// Returns how many language model params are processed.
@@ -484,7 +489,8 @@ static int latinime_BinaryDictionary_addMultipleDictionaryEntries(JNIEnv *env, j
const UnigramProperty unigramProperty(false /* isBeginningOfSentence */, isNotAWord,
isBlacklisted, unigramProbability, timestamp, 0 /* level */, 1 /* count */,
&shortcuts);
- dictionary->addUnigramEntry(word1CodePoints, word1Length, &unigramProperty);
+ dictionary->addUnigramEntry(CodePointArrayView(word1CodePoints, word1Length),
+ &unigramProperty);
if (word0) {
jint bigramProbability = env->GetIntField(languageModelParam, bigramProbabilityFieldId);
const std::vector<int> bigramTargetCodePoints(
@@ -568,8 +574,8 @@ static bool latinime_BinaryDictionary_migrateNative(JNIEnv *env, jclass clazz, j
// Add unigrams.
do {
token = dictionary->getNextWordAndNextToken(token, wordCodePoints, &wordCodePointCount);
- const WordProperty wordProperty = dictionary->getWordProperty(wordCodePoints,
- wordCodePointCount);
+ const WordProperty wordProperty = dictionary->getWordProperty(
+ CodePointArrayView(wordCodePoints, wordCodePointCount));
if (wordCodePoints[0] == CODE_POINT_BEGINNING_OF_SENTENCE) {
// Skip beginning-of-sentence unigram.
continue;
@@ -593,8 +599,8 @@ static bool latinime_BinaryDictionary_migrateNative(JNIEnv *env, jclass clazz, j
// Add bigrams.
do {
token = dictionary->getNextWordAndNextToken(token, wordCodePoints, &wordCodePointCount);
- const WordProperty wordProperty = dictionary->getWordProperty(wordCodePoints,
- wordCodePointCount);
+ const WordProperty wordProperty = dictionary->getWordProperty(
+ CodePointArrayView(wordCodePoints, wordCodePointCount));
if (dictionaryStructureWithBufferPolicy->needsToRunGC(true /* mindsBlockByGC */)) {
dictionaryStructureWithBufferPolicy = runGCAndGetNewStructurePolicy(
std::move(dictionaryStructureWithBufferPolicy), dictFilePathChars);
diff --git a/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h b/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h
index cecfc7aa9..1b796b5d4 100644
--- a/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h
+++ b/native/jni/src/suggest/core/dicnode/internal/dic_node_properties.h
@@ -32,7 +32,7 @@ class DicNodeProperties {
public:
AK_FORCE_INLINE DicNodeProperties()
: mChildrenPtNodeArrayPos(NOT_A_DICT_POS), mDicNodeCodePoint(NOT_A_CODE_POINT),
- mWordId(NOT_A_WORD_ID), mDepth(0), mLeavingDepth(0) {}
+ mWordId(NOT_A_WORD_ID), mDepth(0), mLeavingDepth(0), mPrevWordCount(0) {}
~DicNodeProperties() {}
@@ -45,6 +45,7 @@ class DicNodeProperties {
mDepth = depth;
mLeavingDepth = leavingDepth;
prevWordIds.copyToArray(&mPrevWordIds, 0 /* offset */);
+ mPrevWordCount = prevWordIds.size();
}
// Init for root with prevWordsPtNodePos which is used for n-gram
@@ -55,6 +56,7 @@ class DicNodeProperties {
mDepth = 0;
mLeavingDepth = 0;
prevWordIds.copyToArray(&mPrevWordIds, 0 /* offset */);
+ mPrevWordCount = prevWordIds.size();
}
void initByCopy(const DicNodeProperties *const dicNodeProp) {
@@ -63,8 +65,9 @@ class DicNodeProperties {
mWordId = dicNodeProp->mWordId;
mDepth = dicNodeProp->mDepth;
mLeavingDepth = dicNodeProp->mLeavingDepth;
- WordIdArrayView::fromArray(dicNodeProp->mPrevWordIds)
- .copyToArray(&mPrevWordIds, 0 /* offset */);
+ const WordIdArrayView prevWordIdArrayView = dicNodeProp->getPrevWordIds();
+ prevWordIdArrayView.copyToArray(&mPrevWordIds, 0 /* offset */);
+ mPrevWordCount = prevWordIdArrayView.size();
}
// Init as passing child
@@ -74,8 +77,9 @@ class DicNodeProperties {
mWordId = dicNodeProp->mWordId;
mDepth = dicNodeProp->mDepth + 1; // Increment the depth of a passing child
mLeavingDepth = dicNodeProp->mLeavingDepth;
- WordIdArrayView::fromArray(dicNodeProp->mPrevWordIds)
- .copyToArray(&mPrevWordIds, 0 /* offset */);
+ const WordIdArrayView prevWordIdArrayView = dicNodeProp->getPrevWordIds();
+ prevWordIdArrayView.copyToArray(&mPrevWordIds, 0 /* offset */);
+ mPrevWordCount = prevWordIdArrayView.size();
}
int getChildrenPtNodeArrayPos() const {
@@ -104,7 +108,7 @@ class DicNodeProperties {
}
const WordIdArrayView getPrevWordIds() const {
- return WordIdArrayView::fromArray(mPrevWordIds);
+ return WordIdArrayView::fromArray(mPrevWordIds).limit(mPrevWordCount);
}
int getWordId() const {
@@ -121,6 +125,7 @@ class DicNodeProperties {
uint16_t mDepth;
uint16_t mLeavingDepth;
WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> mPrevWordIds;
+ size_t mPrevWordCount;
};
} // namespace latinime
#endif // LATINIME_DIC_NODE_PROPERTIES_H
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index ec261cfbf..f9f36ce44 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -93,42 +93,42 @@ void Dictionary::NgramListenerForPrediction::onVisitEntry(const int ngramProbabi
void Dictionary::getPredictions(const PrevWordsInfo *const prevWordsInfo,
SuggestionResults *const outSuggestionResults) const {
TimeKeeper::setCurrentTime();
- WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIds;
- prevWordsInfo->getPrevWordIds(mDictionaryStructureWithBufferPolicy.get(), prevWordIds.data(),
+ WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
+ const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds(
+ mDictionaryStructureWithBufferPolicy.get(), &prevWordIdArray,
true /* tryLowerCaseSearch */);
- const WordIdArrayView prevWordIdArrayView = WordIdArrayView::fromArray(prevWordIds);
- NgramListenerForPrediction listener(prevWordsInfo, prevWordIdArrayView, outSuggestionResults,
+ NgramListenerForPrediction listener(prevWordsInfo, prevWordIds, outSuggestionResults,
mDictionaryStructureWithBufferPolicy.get());
- mDictionaryStructureWithBufferPolicy->iterateNgramEntries(prevWordIdArrayView, &listener);
+ mDictionaryStructureWithBufferPolicy->iterateNgramEntries(prevWordIds, &listener);
}
-int Dictionary::getProbability(const int *word, int length) const {
- return getNgramProbability(nullptr /* prevWordsInfo */, word, length);
+int Dictionary::getProbability(const CodePointArrayView codePoints) const {
+ return getNgramProbability(nullptr /* prevWordsInfo */, codePoints);
}
-int Dictionary::getMaxProbabilityOfExactMatches(const int *word, int length) const {
+int Dictionary::getMaxProbabilityOfExactMatches(const CodePointArrayView codePoints) const {
TimeKeeper::setCurrentTime();
return DictionaryUtils::getMaxProbabilityOfExactMatches(
- mDictionaryStructureWithBufferPolicy.get(), word, length);
+ mDictionaryStructureWithBufferPolicy.get(), codePoints);
}
-int Dictionary::getNgramProbability(const PrevWordsInfo *const prevWordsInfo, const int *word,
- int length) const {
+int Dictionary::getNgramProbability(const PrevWordsInfo *const prevWordsInfo,
+ const CodePointArrayView codePoints) const {
TimeKeeper::setCurrentTime();
- int wordId = mDictionaryStructureWithBufferPolicy->getWordId(
- CodePointArrayView(word, length), false /* forceLowerCaseSearch */);
+ const int wordId = mDictionaryStructureWithBufferPolicy->getWordId(codePoints,
+ false /* forceLowerCaseSearch */);
if (wordId == NOT_A_WORD_ID) return NOT_A_PROBABILITY;
if (!prevWordsInfo) {
return getDictionaryStructurePolicy()->getProbabilityOfWord(WordIdArrayView(), wordId);
}
- WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIds;
- prevWordsInfo->getPrevWordIds(mDictionaryStructureWithBufferPolicy.get(), prevWordIds.data(),
+ WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
+ const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds
+ (mDictionaryStructureWithBufferPolicy.get(), &prevWordIdArray,
true /* tryLowerCaseSearch */);
- return getDictionaryStructurePolicy()->getProbabilityOfWord(
- IntArrayView::fromArray(prevWordIds), wordId);
+ return getDictionaryStructurePolicy()->getProbabilityOfWord(prevWordIds, wordId);
}
-bool Dictionary::addUnigramEntry(const int *const word, const int length,
+bool Dictionary::addUnigramEntry(const CodePointArrayView codePoints,
const UnigramProperty *const unigramProperty) {
if (unigramProperty->representsBeginningOfSentence()
&& !mDictionaryStructureWithBufferPolicy->getHeaderStructurePolicy()
@@ -137,14 +137,12 @@ bool Dictionary::addUnigramEntry(const int *const word, const int length,
return false;
}
TimeKeeper::setCurrentTime();
- return mDictionaryStructureWithBufferPolicy->addUnigramEntry(CodePointArrayView(word, length),
- unigramProperty);
+ return mDictionaryStructureWithBufferPolicy->addUnigramEntry(codePoints, unigramProperty);
}
-bool Dictionary::removeUnigramEntry(const int *const codePoints, const int codePointCount) {
+bool Dictionary::removeUnigramEntry(const CodePointArrayView codePoints) {
TimeKeeper::setCurrentTime();
- return mDictionaryStructureWithBufferPolicy->removeUnigramEntry(
- CodePointArrayView(codePoints, codePointCount));
+ return mDictionaryStructureWithBufferPolicy->removeUnigramEntry(codePoints);
}
bool Dictionary::addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
@@ -154,10 +152,9 @@ bool Dictionary::addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
}
bool Dictionary::removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
- const int *const word, const int length) {
+ const CodePointArrayView codePoints) {
TimeKeeper::setCurrentTime();
- return mDictionaryStructureWithBufferPolicy->removeNgramEntry(prevWordsInfo,
- CodePointArrayView(word, length));
+ return mDictionaryStructureWithBufferPolicy->removeNgramEntry(prevWordsInfo, codePoints);
}
bool Dictionary::flush(const char *const filePath) {
@@ -182,11 +179,9 @@ void Dictionary::getProperty(const char *const query, const int queryLength, cha
maxResultLength);
}
-const WordProperty Dictionary::getWordProperty(const int *const codePoints,
- const int codePointCount) {
+const WordProperty Dictionary::getWordProperty(const CodePointArrayView codePoints) {
TimeKeeper::setCurrentTime();
- return mDictionaryStructureWithBufferPolicy->getWordProperty(
- CodePointArrayView(codePoints, codePointCount));
+ return mDictionaryStructureWithBufferPolicy->getWordProperty(codePoints);
}
int Dictionary::getNextWordAndNextToken(const int token, int *const outCodePoints,
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index 0b54f30e9..f6482ab78 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -72,23 +72,23 @@ class Dictionary {
void getPredictions(const PrevWordsInfo *const prevWordsInfo,
SuggestionResults *const outSuggestionResults) const;
- int getProbability(const int *word, int length) const;
+ int getProbability(const CodePointArrayView codePoints) const;
- int getMaxProbabilityOfExactMatches(const int *word, int length) const;
+ int getMaxProbabilityOfExactMatches(const CodePointArrayView codePoints) const;
int getNgramProbability(const PrevWordsInfo *const prevWordsInfo,
- const int *word, int length) const;
+ const CodePointArrayView codePoints) const;
- bool addUnigramEntry(const int *const codePoints, const int codePointCount,
+ bool addUnigramEntry(const CodePointArrayView codePoints,
const UnigramProperty *const unigramProperty);
- bool removeUnigramEntry(const int *const codePoints, const int codePointCount);
+ bool removeUnigramEntry(const CodePointArrayView codePoints);
bool addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
const BigramProperty *const bigramProperty);
- bool removeNgramEntry(const PrevWordsInfo *const prevWordsInfo, const int *const word,
- const int length);
+ bool removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+ const CodePointArrayView codePoints);
bool flush(const char *const filePath);
@@ -99,7 +99,7 @@ class Dictionary {
void getProperty(const char *const query, const int queryLength, char *const outResult,
const int maxResultLength);
- const WordProperty getWordProperty(const int *const codePoints, const int codePointCount);
+ const WordProperty getWordProperty(const CodePointArrayView codePoints);
// Method to iterate all words in the dictionary.
// The returned token has to be used to get the next word. If token is 0, this method newly
diff --git a/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp b/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp
index 617bf5a90..b85f3622a 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp
@@ -29,28 +29,27 @@ namespace latinime {
/* static */ int DictionaryUtils::getMaxProbabilityOfExactMatches(
const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy,
- const int *const codePoints, const int codePointCount) {
+ const CodePointArrayView codePoints) {
std::vector<DicNode> current;
std::vector<DicNode> next;
// No prev words information.
PrevWordsInfo emptyPrevWordsInfo;
- WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIds;
- emptyPrevWordsInfo.getPrevWordIds(dictionaryStructurePolicy, prevWordIds.data(),
- false /* tryLowerCaseSearch */);
+ WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
+ const WordIdArrayView prevWordIds = emptyPrevWordsInfo.getPrevWordIds(
+ dictionaryStructurePolicy, &prevWordIdArray, false /* tryLowerCaseSearch */);
current.emplace_back();
- DicNodeUtils::initAsRoot(dictionaryStructurePolicy,
- IntArrayView::fromArray(prevWordIds), &current.front());
- for (int i = 0; i < codePointCount; ++i) {
+ DicNodeUtils::initAsRoot(dictionaryStructurePolicy, prevWordIds, &current.front());
+ for (const int codePoint : codePoints) {
// The base-lower input is used to ignore case errors and accent errors.
- const int codePoint = CharUtils::toBaseLowerCase(codePoints[i]);
+ const int baseLowerCodePoint = CharUtils::toBaseLowerCase(codePoint);
for (const DicNode &dicNode : current) {
- if (dicNode.isInDigraph() && dicNode.getNodeCodePoint() == codePoint) {
+ if (dicNode.isInDigraph() && dicNode.getNodeCodePoint() == baseLowerCodePoint) {
next.emplace_back(dicNode);
next.back().advanceDigraphIndex();
continue;
}
- processChildDicNodes(dictionaryStructurePolicy, codePoint, &dicNode, &next);
+ processChildDicNodes(dictionaryStructurePolicy, baseLowerCodePoint, &dicNode, &next);
}
current.clear();
current.swap(next);
diff --git a/native/jni/src/suggest/core/dictionary/dictionary_utils.h b/native/jni/src/suggest/core/dictionary/dictionary_utils.h
index 358ebf674..4dd21c9be 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary_utils.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary_utils.h
@@ -20,6 +20,7 @@
#include <vector>
#include "defines.h"
+#include "utils/int_array_view.h"
namespace latinime {
@@ -30,7 +31,7 @@ class DictionaryUtils {
public:
static int getMaxProbabilityOfExactMatches(
const DictionaryStructureWithBufferPolicy *const dictionaryStructurePolicy,
- const int *const codePoints, const int codePointCount);
+ const CodePointArrayView codePoints);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(DictionaryUtils);
diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.cpp b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
index 4f58c0c54..4d7505a55 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.cpp
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
@@ -35,8 +35,8 @@ void DicTraverseSession::init(const Dictionary *const dictionary,
mMultiWordCostMultiplier = getDictionaryStructurePolicy()->getHeaderStructurePolicy()
->getMultiWordCostMultiplier();
mSuggestOptions = suggestOptions;
- prevWordsInfo->getPrevWordIds(getDictionaryStructurePolicy(), mPrevWordsIds.data(),
- true /* tryLowerCaseSearch */);
+ mPrevWordIdCount = prevWordsInfo->getPrevWordIds(getDictionaryStructurePolicy(),
+ &mPrevWordIdArray, true /* tryLowerCaseSearch */).size();
}
void DicTraverseSession::setupForGetSuggestions(const ProximityInfo *pInfo,
diff --git a/native/jni/src/suggest/core/session/dic_traverse_session.h b/native/jni/src/suggest/core/session/dic_traverse_session.h
index af199071e..9f841aa3c 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.h
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.h
@@ -51,12 +51,11 @@ class DicTraverseSession {
}
AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr, bool usesLargeCache)
- : mProximityInfo(nullptr), mDictionary(nullptr), mSuggestOptions(nullptr),
- mDicNodesCache(usesLargeCache), mMultiBigramMap(), mInputSize(0), mMaxPointerCount(1),
- mMultiWordCostMultiplier(1.0f) {
+ : mPrevWordIdCount(0), mProximityInfo(nullptr), mDictionary(nullptr),
+ mSuggestOptions(nullptr), mDicNodesCache(usesLargeCache), mMultiBigramMap(),
+ mInputSize(0), mMaxPointerCount(1), mMultiWordCostMultiplier(1.0f) {
// NOTE: mProximityInfoStates is an array of instances.
// No need to initialize it explicitly here.
- mPrevWordsIds.fill(NOT_A_DICT_POS);
}
// Non virtual inline destructor -- never inherit this class
@@ -78,7 +77,9 @@ class DicTraverseSession {
//--------------------
const ProximityInfo *getProximityInfo() const { return mProximityInfo; }
const SuggestOptions *getSuggestOptions() const { return mSuggestOptions; }
- const WordIdArrayView getPrevWordIds() const { return IntArrayView::fromArray(mPrevWordsIds); }
+ const WordIdArrayView getPrevWordIds() const {
+ return WordIdArrayView::fromArray(mPrevWordIdArray).limit(mPrevWordIdCount);
+ }
DicNodesCache *getDicTraverseCache() { return &mDicNodesCache; }
MultiBigramMap *getMultiBigramMap() { return &mMultiBigramMap; }
const ProximityInfoState *getProximityInfoState(int id) const {
@@ -165,7 +166,8 @@ class DicTraverseSession {
const int *const inputYs, const int *const times, const int *const pointerIds,
const int inputSize, const float maxSpatialDistance, const int maxPointerCount);
- WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> mPrevWordsIds;
+ WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> mPrevWordIdArray;
+ size_t mPrevWordIdCount;
const ProximityInfo *mProximityInfo;
const Dictionary *mDictionary;
const SuggestOptions *mSuggestOptions;
diff --git a/native/jni/src/suggest/core/session/prev_words_info.h b/native/jni/src/suggest/core/session/prev_words_info.h
index fc9a35968..02e82a8e0 100644
--- a/native/jni/src/suggest/core/session/prev_words_info.h
+++ b/native/jni/src/suggest/core/session/prev_words_info.h
@@ -17,6 +17,8 @@
#ifndef LATINIME_PREV_WORDS_INFO_H
#define LATINIME_PREV_WORDS_INFO_H
+#include <array>
+
#include "defines.h"
#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
#include "utils/char_utils.h"
@@ -27,12 +29,13 @@ namespace latinime {
class PrevWordsInfo {
public:
// No prev word information.
- PrevWordsInfo() {
+ PrevWordsInfo() : mPrevWordCount(0) {
clear();
}
- PrevWordsInfo(PrevWordsInfo &&prevWordsInfo) {
- for (size_t i = 0; i < NELEMS(mPrevWordCodePoints); ++i) {
+ PrevWordsInfo(PrevWordsInfo &&prevWordsInfo)
+ : mPrevWordCount(prevWordsInfo.mPrevWordCount) {
+ for (size_t i = 0; i < mPrevWordCount; ++i) {
mPrevWordCodePointCount[i] = prevWordsInfo.mPrevWordCodePointCount[i];
memmove(mPrevWordCodePoints[i], prevWordsInfo.mPrevWordCodePoints[i],
sizeof(mPrevWordCodePoints[i][0]) * mPrevWordCodePointCount[i]);
@@ -43,9 +46,10 @@ class PrevWordsInfo {
// Construct from previous words.
PrevWordsInfo(const int prevWordCodePoints[][MAX_WORD_LENGTH],
const int *const prevWordCodePointCount, const bool *const isBeginningOfSentence,
- const size_t prevWordCount) {
+ const size_t prevWordCount)
+ : mPrevWordCount(std::min(NELEMS(mPrevWordCodePoints), prevWordCount)) {
clear();
- for (size_t i = 0; i < std::min(NELEMS(mPrevWordCodePoints), prevWordCount); ++i) {
+ for (size_t i = 0; i < mPrevWordCount; ++i) {
if (prevWordCodePointCount[i] < 0 || prevWordCodePointCount[i] > MAX_WORD_LENGTH) {
continue;
}
@@ -58,7 +62,7 @@ class PrevWordsInfo {
// Construct from a previous word.
PrevWordsInfo(const int *const prevWordCodePoints, const int prevWordCodePointCount,
- const bool isBeginningOfSentence) {
+ const bool isBeginningOfSentence) : mPrevWordCount(1) {
clear();
if (prevWordCodePointCount > MAX_WORD_LENGTH || !prevWordCodePoints) {
return;
@@ -79,26 +83,29 @@ class PrevWordsInfo {
return false;
}
- void getPrevWordIds(const DictionaryStructureWithBufferPolicy *const dictStructurePolicy,
- int *const outPrevWordIds, const bool tryLowerCaseSearch) const {
- for (size_t i = 0; i < NELEMS(mPrevWordCodePoints); ++i) {
- outPrevWordIds[i] = getWordId(dictStructurePolicy,
+ template<size_t N>
+ const WordIdArrayView getPrevWordIds(
+ const DictionaryStructureWithBufferPolicy *const dictStructurePolicy,
+ std::array<int, N> *const prevWordIdBuffer, const bool tryLowerCaseSearch) const {
+ for (size_t i = 0; i < std::min(mPrevWordCount, N); ++i) {
+ prevWordIdBuffer->at(i) = getWordId(dictStructurePolicy,
mPrevWordCodePoints[i], mPrevWordCodePointCount[i],
mIsBeginningOfSentence[i], tryLowerCaseSearch);
}
+ return WordIdArrayView::fromArray(*prevWordIdBuffer).limit(mPrevWordCount);
}
// n is 1-indexed.
- const CodePointArrayView getNthPrevWordCodePoints(const int n) const {
- if (n <= 0 || n > MAX_PREV_WORD_COUNT_FOR_N_GRAM) {
+ const CodePointArrayView getNthPrevWordCodePoints(const size_t n) const {
+ if (n <= 0 || n > mPrevWordCount) {
return CodePointArrayView();
}
return CodePointArrayView(mPrevWordCodePoints[n - 1], mPrevWordCodePointCount[n - 1]);
}
// n is 1-indexed.
- bool isNthPrevWordBeginningOfSentence(const int n) const {
- if (n <= 0 || n > MAX_PREV_WORD_COUNT_FOR_N_GRAM) {
+ bool isNthPrevWordBeginningOfSentence(const size_t n) const {
+ if (n <= 0 || n > mPrevWordCount) {
return false;
}
return mIsBeginningOfSentence[n - 1];
@@ -142,6 +149,7 @@ class PrevWordsInfo {
}
}
+ const size_t mPrevWordCount;
int mPrevWordCodePoints[MAX_PREV_WORD_COUNT_FOR_N_GRAM][MAX_WORD_LENGTH];
int mPrevWordCodePointCount[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
bool mIsBeginningOfSentence[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
index dfc3d2d9b..ee1403739 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp
@@ -268,8 +268,8 @@ bool Ver4PatriciaTriePolicy::addUnigramEntry(const CodePointArrayView wordCodePo
return false;
}
const CodePointArrayView codePointArrayView(codePointsToAdd, codePointCountToAdd);
- if (mUpdatingHelper.addUnigramWord(&readingHelper, codePointArrayView.data(),
- codePointArrayView.size(), unigramProperty, &addedNewUnigram)) {
+ if (mUpdatingHelper.addUnigramWord(&readingHelper, codePointArrayView, unigramProperty,
+ &addedNewUnigram)) {
if (addedNewUnigram && !unigramProperty->representsBeginningOfSentence()) {
mUnigramCount++;
}
@@ -283,8 +283,8 @@ bool Ver4PatriciaTriePolicy::addUnigramEntry(const CodePointArrayView wordCodePo
}
for (const auto &shortcut : unigramProperty->getShortcuts()) {
if (!mUpdatingHelper.addShortcutTarget(wordPos,
- shortcut.getTargetCodePoints()->data(),
- shortcut.getTargetCodePoints()->size(), shortcut.getProbability())) {
+ CodePointArrayView(*shortcut.getTargetCodePoints()),
+ shortcut.getProbability())) {
AKLOGE("Cannot add new shortcut target. PtNodePos: %d, length: %zd, "
"probability: %d", wordPos, shortcut.getTargetCodePoints()->size(),
shortcut.getProbability());
@@ -332,8 +332,12 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
"length: %zd", bigramProperty->getTargetCodePoints()->size());
return false;
}
- int prevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
- prevWordsInfo->getPrevWordIds(this, prevWordIds, false /* tryLowerCaseSearch */);
+ WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
+ const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds(this, &prevWordIdArray,
+ false /* tryLowerCaseSearch */);
+ if (prevWordIds.empty()) {
+ return false;
+ }
if (prevWordIds[0] == NOT_A_WORD_ID) {
if (prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)) {
const std::vector<UnigramProperty::ShortcutProperty> shortcuts;
@@ -347,7 +351,7 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
return false;
}
// Refresh word ids.
- prevWordsInfo->getPrevWordIds(this, prevWordIds, false /* tryLowerCaseSearch */);
+ prevWordsInfo->getPrevWordIds(this, &prevWordIdArray, false /* tryLowerCaseSearch */);
} else {
return false;
}
@@ -390,9 +394,10 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor
AKLOGE("word is too long to remove n-gram entry form the dictionary. length: %zd",
wordCodePoints.size());
}
- int prevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
- prevWordsInfo->getPrevWordIds(this, prevWordIds, false /* tryLowerCaseSerch */);
- if (prevWordIds[0] == NOT_A_WORD_ID) {
+ WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
+ const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds(this, &prevWordIdArray,
+ false /* tryLowerCaseSerch */);
+ if (prevWordIds.firstOrDefault(NOT_A_WORD_ID) == NOT_A_WORD_ID) {
return false;
}
const int wordPos = getTerminalPtNodePosFromWordId(getWordId(wordCodePoints,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp
index f7fd5c071..1b2f857ab 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.cpp
@@ -39,32 +39,31 @@ const BigramListReadWriteUtils::BigramFlags
BigramListReadWriteUtils::MASK_ATTRIBUTE_PROBABILITY = 0x0F;
/* static */ bool BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(
- const uint8_t *const bigramsBuf, const int bufSize, BigramFlags *const outBigramFlags,
+ const ReadOnlyByteArrayView buffer, BigramFlags *const outBigramFlags,
int *const outTargetPtNodePos, int *const bigramEntryPos) {
- if (bufSize <= *bigramEntryPos) {
- AKLOGE("Read invalid pos in getBigramEntryPropertiesAndAdvancePosition(). bufSize: %d, "
- "bigramEntryPos: %d.", bufSize, *bigramEntryPos);
+ if (static_cast<int>(buffer.size()) <= *bigramEntryPos) {
+ AKLOGE("Read invalid pos in getBigramEntryPropertiesAndAdvancePosition(). bufSize: %zd, "
+ "bigramEntryPos: %d.", buffer.size(), *bigramEntryPos);
return false;
}
- const BigramFlags bigramFlags = ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf,
+ const BigramFlags bigramFlags = ByteArrayUtils::readUint8AndAdvancePosition(buffer.data(),
bigramEntryPos);
if (outBigramFlags) {
*outBigramFlags = bigramFlags;
}
- const int targetPos = getBigramAddressAndAdvancePosition(bigramsBuf, bigramFlags,
- bigramEntryPos);
+ const int targetPos = getBigramAddressAndAdvancePosition(buffer, bigramFlags, bigramEntryPos);
if (outTargetPtNodePos) {
*outTargetPtNodePos = targetPos;
}
return true;
}
-/* static */ bool BigramListReadWriteUtils::skipExistingBigrams(const uint8_t *const bigramsBuf,
- const int bufSize, int *const bigramListPos) {
+/* static */ bool BigramListReadWriteUtils::skipExistingBigrams(const ReadOnlyByteArrayView buffer,
+ int *const bigramListPos) {
BigramFlags flags;
do {
- if (!getBigramEntryPropertiesAndAdvancePosition(bigramsBuf, bufSize, &flags,
- 0 /* outTargetPtNodePos */, bigramListPos)) {
+ if (!getBigramEntryPropertiesAndAdvancePosition(buffer, &flags, 0 /* outTargetPtNodePos */,
+ bigramListPos)) {
return false;
}
} while(hasNext(flags));
@@ -72,18 +71,18 @@ const BigramListReadWriteUtils::BigramFlags
}
/* static */ int BigramListReadWriteUtils::getBigramAddressAndAdvancePosition(
- const uint8_t *const bigramsBuf, const BigramFlags flags, int *const pos) {
+ const ReadOnlyByteArrayView buffer, const BigramFlags flags, int *const pos) {
int offset = 0;
const int origin = *pos;
switch (MASK_ATTRIBUTE_ADDRESS_TYPE & flags) {
case FLAG_ATTRIBUTE_ADDRESS_TYPE_ONEBYTE:
- offset = ByteArrayUtils::readUint8AndAdvancePosition(bigramsBuf, pos);
+ offset = ByteArrayUtils::readUint8AndAdvancePosition(buffer.data(), pos);
break;
case FLAG_ATTRIBUTE_ADDRESS_TYPE_TWOBYTES:
- offset = ByteArrayUtils::readUint16AndAdvancePosition(bigramsBuf, pos);
+ offset = ByteArrayUtils::readUint16AndAdvancePosition(buffer.data(), pos);
break;
case FLAG_ATTRIBUTE_ADDRESS_TYPE_THREEBYTES:
- offset = ByteArrayUtils::readUint24AndAdvancePosition(bigramsBuf, pos);
+ offset = ByteArrayUtils::readUint24AndAdvancePosition(buffer.data(), pos);
break;
}
if (isOffsetNegative(flags)) {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h
index 10f93fb7a..a0f7d5e83 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h
@@ -21,6 +21,7 @@
#include <cstdlib>
#include "defines.h"
+#include "utils/byte_array_view.h"
namespace latinime {
@@ -30,8 +31,8 @@ class BigramListReadWriteUtils {
public:
typedef uint8_t BigramFlags;
- static bool getBigramEntryPropertiesAndAdvancePosition(const uint8_t *const bigramsBuf,
- const int bufSize, BigramFlags *const outBigramFlags, int *const outTargetPtNodePos,
+ static bool getBigramEntryPropertiesAndAdvancePosition(const ReadOnlyByteArrayView buffer,
+ BigramFlags *const outBigramFlags, int *const outTargetPtNodePos,
int *const bigramEntryPos);
static AK_FORCE_INLINE int getProbabilityFromFlags(const BigramFlags flags) {
@@ -43,8 +44,7 @@ public:
}
// Bigrams reading methods
- static bool skipExistingBigrams(const uint8_t *const bigramsBuf, const int bufSize,
- int *const bigramListPos);
+ static bool skipExistingBigrams(const ReadOnlyByteArrayView buffer, int *const bigramListPos);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BigramListReadWriteUtils);
@@ -61,7 +61,7 @@ private:
return (flags & FLAG_ATTRIBUTE_OFFSET_NEGATIVE) != 0;
}
- static int getBigramAddressAndAdvancePosition(const uint8_t *const bigramsBuf,
+ static int getBigramAddressAndAdvancePosition(const ReadOnlyByteArrayView buffer,
const BigramFlags flags, int *const pos);
};
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp
index 086d98b4a..40782a44f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.cpp
@@ -218,9 +218,9 @@ int DynamicPtReadingHelper::getCodePointsAndProbabilityAndReturnCodePointCount(
}
int DynamicPtReadingHelper::getTerminalPtNodePositionOfWord(const int *const inWord,
- const int length, const bool forceLowerCaseSearch) {
+ const size_t length, const bool forceLowerCaseSearch) {
int searchCodePoints[length];
- for (int i = 0; i < length; ++i) {
+ for (size_t i = 0; i < length; ++i) {
searchCodePoints[i] = forceLowerCaseSearch ? CharUtils::toLowerCase(inWord[i]) : inWord[i];
}
while (!isEnd()) {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h
index b7262581a..9a7abc97f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h
@@ -138,12 +138,12 @@ class DynamicPtReadingHelper {
}
// Return code point count exclude the last read node's code points.
- AK_FORCE_INLINE int getPrevTotalCodePointCount() const {
+ AK_FORCE_INLINE size_t getPrevTotalCodePointCount() const {
return mReadingState.mTotalCodePointCountSinceInitialization;
}
// Return code point count include the last read node's code points.
- AK_FORCE_INLINE int getTotalCodePointCount(const PtNodeParams &ptNodeParams) const {
+ AK_FORCE_INLINE size_t getTotalCodePointCount(const PtNodeParams &ptNodeParams) const {
return mReadingState.mTotalCodePointCountSinceInitialization
+ ptNodeParams.getCodePointCount();
}
@@ -214,7 +214,7 @@ class DynamicPtReadingHelper {
int getCodePointsAndProbabilityAndReturnCodePointCount(const int maxCodePointCount,
int *const outCodePoints, int *const outUnigramProbability);
- int getTerminalPtNodePositionOfWord(const int *const inWord, const int length,
+ int getTerminalPtNodePositionOfWord(const int *const inWord, const size_t length,
const bool forceLowerCaseSearch);
private:
@@ -234,7 +234,7 @@ class DynamicPtReadingHelper {
int mPos;
// Remaining node count in the current array.
int mRemainingPtNodeCountInThisArray;
- int mTotalCodePointCountSinceInitialization;
+ size_t mTotalCodePointCountSinceInitialization;
// Counter of PtNodes used to avoid infinite loops caused by broken or malicious links.
int mTotalPtNodeIndexInThisArrayChain;
// Counter of PtNode arrays used to avoid infinite loops caused by cyclic links of empty
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
index 3c62e2e56..3b58d7d6d 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.cpp
@@ -28,17 +28,16 @@ namespace latinime {
const int DynamicPtUpdatingHelper::CHILDREN_POSITION_FIELD_SIZE = 3;
-bool DynamicPtUpdatingHelper::addUnigramWord(
- DynamicPtReadingHelper *const readingHelper,
- const int *const wordCodePoints, const int codePointCount,
- const UnigramProperty *const unigramProperty, bool *const outAddedNewUnigram) {
+bool DynamicPtUpdatingHelper::addUnigramWord(DynamicPtReadingHelper *const readingHelper,
+ const CodePointArrayView wordCodePoints, const UnigramProperty *const unigramProperty,
+ bool *const outAddedNewUnigram) {
int parentPos = NOT_A_DICT_POS;
while (!readingHelper->isEnd()) {
const PtNodeParams ptNodeParams(readingHelper->getPtNodeParams());
if (!ptNodeParams.isValid()) {
break;
}
- const int matchedCodePointCount = readingHelper->getPrevTotalCodePointCount();
+ const size_t matchedCodePointCount = readingHelper->getPrevTotalCodePointCount();
if (!readingHelper->isMatchedCodePoint(ptNodeParams, 0 /* index */,
wordCodePoints[matchedCodePointCount])) {
// The first code point is different from target code point. Skip this node and read
@@ -47,26 +46,25 @@ bool DynamicPtUpdatingHelper::addUnigramWord(
continue;
}
// Check following merged node code points.
- const int nodeCodePointCount = ptNodeParams.getCodePointCount();
- for (int j = 1; j < nodeCodePointCount; ++j) {
- const int nextIndex = matchedCodePointCount + j;
- if (nextIndex >= codePointCount || !readingHelper->isMatchedCodePoint(ptNodeParams, j,
- wordCodePoints[matchedCodePointCount + j])) {
+ const size_t nodeCodePointCount = ptNodeParams.getCodePointArrayView().size();
+ for (size_t j = 1; j < nodeCodePointCount; ++j) {
+ const size_t nextIndex = matchedCodePointCount + j;
+ if (nextIndex >= wordCodePoints.size()
+ || !readingHelper->isMatchedCodePoint(ptNodeParams, j,
+ wordCodePoints[matchedCodePointCount + j])) {
*outAddedNewUnigram = true;
return reallocatePtNodeAndAddNewPtNodes(&ptNodeParams, j, unigramProperty,
- wordCodePoints + matchedCodePointCount,
- codePointCount - matchedCodePointCount);
+ wordCodePoints.skip(matchedCodePointCount));
}
}
// All characters are matched.
- if (codePointCount == readingHelper->getTotalCodePointCount(ptNodeParams)) {
+ if (wordCodePoints.size() == readingHelper->getTotalCodePointCount(ptNodeParams)) {
return setPtNodeProbability(&ptNodeParams, unigramProperty, outAddedNewUnigram);
}
if (!ptNodeParams.hasChildren()) {
*outAddedNewUnigram = true;
return createChildrenPtNodeArrayAndAChildPtNode(&ptNodeParams, unigramProperty,
- wordCodePoints + readingHelper->getTotalCodePointCount(ptNodeParams),
- codePointCount - readingHelper->getTotalCodePointCount(ptNodeParams));
+ wordCodePoints.skip(readingHelper->getTotalCodePointCount(ptNodeParams)));
}
// Advance to the children nodes.
parentPos = ptNodeParams.getHeadPos();
@@ -79,9 +77,8 @@ bool DynamicPtUpdatingHelper::addUnigramWord(
int pos = readingHelper->getPosOfLastForwardLinkField();
*outAddedNewUnigram = true;
return createAndInsertNodeIntoPtNodeArray(parentPos,
- wordCodePoints + readingHelper->getPrevTotalCodePointCount(),
- codePointCount - readingHelper->getPrevTotalCodePointCount(),
- unigramProperty, &pos);
+ wordCodePoints.skip(readingHelper->getPrevTotalCodePointCount()), unigramProperty,
+ &pos);
}
bool DynamicPtUpdatingHelper::addNgramEntry(const PtNodePosArrayView prevWordsPtNodePos,
@@ -120,23 +117,21 @@ bool DynamicPtUpdatingHelper::removeNgramEntry(const PtNodePosArrayView prevWord
}
bool DynamicPtUpdatingHelper::addShortcutTarget(const int wordPos,
- const int *const targetCodePoints, const int targetCodePointCount,
- const int shortcutProbability) {
+ const CodePointArrayView targetCodePoints, const int shortcutProbability) {
const PtNodeParams ptNodeParams(mPtNodeReader->fetchPtNodeParamsInBufferFromPtNodePos(wordPos));
- return mPtNodeWriter->addShortcutTarget(&ptNodeParams, targetCodePoints, targetCodePointCount,
- shortcutProbability);
+ return mPtNodeWriter->addShortcutTarget(&ptNodeParams, targetCodePoints.data(),
+ targetCodePoints.size(), shortcutProbability);
}
bool DynamicPtUpdatingHelper::createAndInsertNodeIntoPtNodeArray(const int parentPos,
- const int *const nodeCodePoints, const int nodeCodePointCount,
- const UnigramProperty *const unigramProperty, int *const forwardLinkFieldPos) {
+ const CodePointArrayView ptNodeCodePoints, const UnigramProperty *const unigramProperty,
+ int *const forwardLinkFieldPos) {
const int newPtNodeArrayPos = mBuffer->getTailPosition();
if (!DynamicPtWritingUtils::writeForwardLinkPositionAndAdvancePosition(mBuffer,
newPtNodeArrayPos, forwardLinkFieldPos)) {
return false;
}
- return createNewPtNodeArrayWithAChildPtNode(parentPos, nodeCodePoints, nodeCodePointCount,
- unigramProperty);
+ return createNewPtNodeArrayWithAChildPtNode(parentPos, ptNodeCodePoints, unigramProperty);
}
bool DynamicPtUpdatingHelper::setPtNodeProbability(const PtNodeParams *const originalPtNodeParams,
@@ -153,8 +148,7 @@ bool DynamicPtUpdatingHelper::setPtNodeProbability(const PtNodeParams *const ori
const PtNodeParams ptNodeParamsToWrite(getUpdatedPtNodeParams(originalPtNodeParams,
unigramProperty->isNotAWord(), unigramProperty->isBlacklisted(),
true /* isTerminal */, originalPtNodeParams->getParentPos(),
- originalPtNodeParams->getCodePointCount(), originalPtNodeParams->getCodePoints(),
- unigramProperty->getProbability()));
+ originalPtNodeParams->getCodePointArrayView(), unigramProperty->getProbability()));
if (!mPtNodeWriter->writeNewTerminalPtNodeAndAdvancePosition(&ptNodeParamsToWrite,
unigramProperty, &writingPos)) {
return false;
@@ -168,17 +162,17 @@ bool DynamicPtUpdatingHelper::setPtNodeProbability(const PtNodeParams *const ori
bool DynamicPtUpdatingHelper::createChildrenPtNodeArrayAndAChildPtNode(
const PtNodeParams *const parentPtNodeParams, const UnigramProperty *const unigramProperty,
- const int *const codePoints, const int codePointCount) {
+ const CodePointArrayView codePoints) {
const int newPtNodeArrayPos = mBuffer->getTailPosition();
if (!mPtNodeWriter->updateChildrenPosition(parentPtNodeParams, newPtNodeArrayPos)) {
return false;
}
return createNewPtNodeArrayWithAChildPtNode(parentPtNodeParams->getHeadPos(), codePoints,
- codePointCount, unigramProperty);
+ unigramProperty);
}
bool DynamicPtUpdatingHelper::createNewPtNodeArrayWithAChildPtNode(
- const int parentPtNodePos, const int *const nodeCodePoints, const int nodeCodePointCount,
+ const int parentPtNodePos, const CodePointArrayView ptNodeCodePoints,
const UnigramProperty *const unigramProperty) {
int writingPos = mBuffer->getTailPosition();
if (!DynamicPtWritingUtils::writePtNodeArraySizeAndAdvancePosition(mBuffer,
@@ -187,8 +181,7 @@ bool DynamicPtUpdatingHelper::createNewPtNodeArrayWithAChildPtNode(
}
const PtNodeParams ptNodeParamsToWrite(getPtNodeParamsForNewPtNode(
unigramProperty->isNotAWord(), unigramProperty->isBlacklisted(), true /* isTerminal */,
- parentPtNodePos, nodeCodePointCount, nodeCodePoints,
- unigramProperty->getProbability()));
+ parentPtNodePos, ptNodeCodePoints, unigramProperty->getProbability()));
if (!mPtNodeWriter->writeNewTerminalPtNodeAndAdvancePosition(&ptNodeParamsToWrite,
unigramProperty, &writingPos)) {
return false;
@@ -202,9 +195,9 @@ bool DynamicPtUpdatingHelper::createNewPtNodeArrayWithAChildPtNode(
// Returns whether the dictionary updating was succeeded or not.
bool DynamicPtUpdatingHelper::reallocatePtNodeAndAddNewPtNodes(
- const PtNodeParams *const reallocatingPtNodeParams, const int overlappingCodePointCount,
- const UnigramProperty *const unigramProperty, const int *const newNodeCodePoints,
- const int newNodeCodePointCount) {
+ const PtNodeParams *const reallocatingPtNodeParams, const size_t overlappingCodePointCount,
+ const UnigramProperty *const unigramProperty,
+ const CodePointArrayView newPtNodeCodePoints) {
// When addsExtraChild is true, split the reallocating PtNode and add new child.
// Reallocating PtNode: abcde, newNode: abcxy.
// abc (1st, not terminal) __ de (2nd)
@@ -212,16 +205,18 @@ bool DynamicPtUpdatingHelper::reallocatePtNodeAndAddNewPtNodes(
// Otherwise, this method makes 1st part terminal and write information in unigramProperty.
// Reallocating PtNode: abcde, newNode: abc.
// abc (1st, terminal) __ de (2nd)
- const bool addsExtraChild = newNodeCodePointCount > overlappingCodePointCount;
+ const bool addsExtraChild = newPtNodeCodePoints.size() > overlappingCodePointCount;
const int firstPartOfReallocatedPtNodePos = mBuffer->getTailPosition();
int writingPos = firstPartOfReallocatedPtNodePos;
// Write the 1st part of the reallocating node. The children position will be updated later
// with actual children position.
+ const CodePointArrayView firstPtNodeCodePoints =
+ reallocatingPtNodeParams->getCodePointArrayView().limit(overlappingCodePointCount);
if (addsExtraChild) {
const PtNodeParams ptNodeParamsToWrite(getPtNodeParamsForNewPtNode(
false /* isNotAWord */, false /* isBlacklisted */, false /* isTerminal */,
- reallocatingPtNodeParams->getParentPos(), overlappingCodePointCount,
- reallocatingPtNodeParams->getCodePoints(), NOT_A_PROBABILITY));
+ reallocatingPtNodeParams->getParentPos(), firstPtNodeCodePoints,
+ NOT_A_PROBABILITY));
if (!mPtNodeWriter->writePtNodeAndAdvancePosition(&ptNodeParamsToWrite, &writingPos)) {
return false;
}
@@ -229,8 +224,7 @@ bool DynamicPtUpdatingHelper::reallocatePtNodeAndAddNewPtNodes(
const PtNodeParams ptNodeParamsToWrite(getPtNodeParamsForNewPtNode(
unigramProperty->isNotAWord(), unigramProperty->isBlacklisted(),
true /* isTerminal */, reallocatingPtNodeParams->getParentPos(),
- overlappingCodePointCount, reallocatingPtNodeParams->getCodePoints(),
- unigramProperty->getProbability()));
+ firstPtNodeCodePoints, unigramProperty->getProbability()));
if (!mPtNodeWriter->writeNewTerminalPtNodeAndAdvancePosition(&ptNodeParamsToWrite,
unigramProperty, &writingPos)) {
return false;
@@ -248,8 +242,7 @@ bool DynamicPtUpdatingHelper::reallocatePtNodeAndAddNewPtNodes(
const PtNodeParams childPartPtNodeParams(getUpdatedPtNodeParams(reallocatingPtNodeParams,
reallocatingPtNodeParams->isNotAWord(), reallocatingPtNodeParams->isBlacklisted(),
reallocatingPtNodeParams->isTerminal(), firstPartOfReallocatedPtNodePos,
- reallocatingPtNodeParams->getCodePointCount() - overlappingCodePointCount,
- reallocatingPtNodeParams->getCodePoints() + overlappingCodePointCount,
+ reallocatingPtNodeParams->getCodePointArrayView().skip(overlappingCodePointCount),
reallocatingPtNodeParams->getProbability()));
if (!mPtNodeWriter->writePtNodeAndAdvancePosition(&childPartPtNodeParams, &writingPos)) {
return false;
@@ -258,8 +251,8 @@ bool DynamicPtUpdatingHelper::reallocatePtNodeAndAddNewPtNodes(
const PtNodeParams extraChildPtNodeParams(getPtNodeParamsForNewPtNode(
unigramProperty->isNotAWord(), unigramProperty->isBlacklisted(),
true /* isTerminal */, firstPartOfReallocatedPtNodePos,
- newNodeCodePointCount - overlappingCodePointCount,
- newNodeCodePoints + overlappingCodePointCount, unigramProperty->getProbability()));
+ newPtNodeCodePoints.skip(overlappingCodePointCount),
+ unigramProperty->getProbability()));
if (!mPtNodeWriter->writeNewTerminalPtNodeAndAdvancePosition(&extraChildPtNodeParams,
unigramProperty, &writingPos)) {
return false;
@@ -282,26 +275,24 @@ bool DynamicPtUpdatingHelper::reallocatePtNodeAndAddNewPtNodes(
}
const PtNodeParams DynamicPtUpdatingHelper::getUpdatedPtNodeParams(
- const PtNodeParams *const originalPtNodeParams,
- const bool isNotAWord, const bool isBlacklisted, const bool isTerminal, const int parentPos,
- const int codePointCount, const int *const codePoints, const int probability) const {
+ const PtNodeParams *const originalPtNodeParams, const bool isNotAWord,
+ const bool isBlacklisted, const bool isTerminal, const int parentPos,
+ const CodePointArrayView codePoints, const int probability) const {
const PatriciaTrieReadingUtils::NodeFlags flags = PatriciaTrieReadingUtils::createAndGetFlags(
isBlacklisted, isNotAWord, isTerminal, false /* hasShortcutTargets */,
- false /* hasBigrams */, codePointCount > 1 /* hasMultipleChars */,
+ false /* hasBigrams */, codePoints.size() > 1u /* hasMultipleChars */,
CHILDREN_POSITION_FIELD_SIZE);
- return PtNodeParams(originalPtNodeParams, flags, parentPos, codePointCount, codePoints,
- probability);
+ return PtNodeParams(originalPtNodeParams, flags, parentPos, codePoints, probability);
}
-const PtNodeParams DynamicPtUpdatingHelper::getPtNodeParamsForNewPtNode(
- const bool isNotAWord, const bool isBlacklisted, const bool isTerminal,
- const int parentPos, const int codePointCount, const int *const codePoints,
- const int probability) const {
+const PtNodeParams DynamicPtUpdatingHelper::getPtNodeParamsForNewPtNode(const bool isNotAWord,
+ const bool isBlacklisted, const bool isTerminal, const int parentPos,
+ const CodePointArrayView codePoints, const int probability) const {
const PatriciaTrieReadingUtils::NodeFlags flags = PatriciaTrieReadingUtils::createAndGetFlags(
isBlacklisted, isNotAWord, isTerminal, false /* hasShortcutTargets */,
- false /* hasBigrams */, codePointCount > 1 /* hasMultipleChars */,
+ false /* hasBigrams */, codePoints.size() > 1u /* hasMultipleChars */,
CHILDREN_POSITION_FIELD_SIZE);
- return PtNodeParams(flags, parentPos, codePointCount, codePoints, probability);
+ return PtNodeParams(flags, parentPos, codePoints, probability);
}
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h
index 97c05c1ea..710047e8c 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_updating_helper.h
@@ -40,19 +40,21 @@ class DynamicPtUpdatingHelper {
// Add a word to the dictionary. If the word already exists, update the probability.
bool addUnigramWord(DynamicPtReadingHelper *const readingHelper,
- const int *const wordCodePoints, const int codePointCount,
- const UnigramProperty *const unigramProperty, bool *const outAddedNewUnigram);
+ const CodePointArrayView wordCodePoints, const UnigramProperty *const unigramProperty,
+ bool *const outAddedNewUnigram);
+ // TODO: Remove after stopping supporting v402.
// Add an n-gram entry.
bool addNgramEntry(const PtNodePosArrayView prevWordsPtNodePos, const int wordPos,
const BigramProperty *const bigramProperty, bool *const outAddedNewEntry);
+ // TODO: Remove after stopping supporting v402.
// Remove an n-gram entry.
bool removeNgramEntry(const PtNodePosArrayView prevWordsPtNodePos, const int wordPos);
// Add a shortcut target.
- bool addShortcutTarget(const int wordPos, const int *const targetCodePoints,
- const int targetCodePointCount, const int shortcutProbability);
+ bool addShortcutTarget(const int wordPos, const CodePointArrayView targetCodePoints,
+ const int shortcutProbability);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(DynamicPtUpdatingHelper);
@@ -63,33 +65,32 @@ class DynamicPtUpdatingHelper {
const PtNodeReader *const mPtNodeReader;
PtNodeWriter *const mPtNodeWriter;
- bool createAndInsertNodeIntoPtNodeArray(const int parentPos, const int *const nodeCodePoints,
- const int nodeCodePointCount, const UnigramProperty *const unigramProperty,
+ bool createAndInsertNodeIntoPtNodeArray(const int parentPos,
+ const CodePointArrayView ptNodeCodePoints, const UnigramProperty *const unigramProperty,
int *const forwardLinkFieldPos);
bool setPtNodeProbability(const PtNodeParams *const originalPtNodeParams,
const UnigramProperty *const unigramProperty, bool *const outAddedNewUnigram);
bool createChildrenPtNodeArrayAndAChildPtNode(const PtNodeParams *const parentPtNodeParams,
- const UnigramProperty *const unigramProperty, const int *const codePoints,
- const int codePointCount);
+ const UnigramProperty *const unigramProperty,
+ const CodePointArrayView remainingCodePoints);
- bool createNewPtNodeArrayWithAChildPtNode(const int parentPos, const int *const nodeCodePoints,
- const int nodeCodePointCount, const UnigramProperty *const unigramProperty);
+ bool createNewPtNodeArrayWithAChildPtNode(const int parentPos,
+ const CodePointArrayView ptNodeCodePoints,
+ const UnigramProperty *const unigramProperty);
- bool reallocatePtNodeAndAddNewPtNodes(
- const PtNodeParams *const reallocatingPtNodeParams, const int overlappingCodePointCount,
- const UnigramProperty *const unigramProperty, const int *const newNodeCodePoints,
- const int newNodeCodePointCount);
+ bool reallocatePtNodeAndAddNewPtNodes(const PtNodeParams *const reallocatingPtNodeParams,
+ const size_t overlappingCodePointCount, const UnigramProperty *const unigramProperty,
+ const CodePointArrayView newPtNodeCodePoints);
const PtNodeParams getUpdatedPtNodeParams(const PtNodeParams *const originalPtNodeParams,
const bool isNotAWord, const bool isBlacklisted, const bool isTerminal,
- const int parentPos, const int codePointCount,
- const int *const codePoints, const int probability) const;
+ const int parentPos, const CodePointArrayView codePoints, const int probability) const;
const PtNodeParams getPtNodeParamsForNewPtNode(const bool isNotAWord, const bool isBlacklisted,
- const bool isTerminal, const int parentPos,
- const int codePointCount, const int *const codePoints, const int probability) const;
+ const bool isTerminal, const int parentPos, const CodePointArrayView codePoints,
+ const int probability) const;
};
} // namespace latinime
#endif /* LATINIME_DYNAMIC_PATRICIA_TRIE_UPDATING_HELPER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h
index c12fed324..3ff1829bd 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h
@@ -89,9 +89,9 @@ class PtNodeParams {
// Construct new params by updating existing PtNode params.
PtNodeParams(const PtNodeParams *const ptNodeParams,
const PatriciaTrieReadingUtils::NodeFlags flags, const int parentPos,
- const int codePointCount, const int *const codePoints, const int probability)
+ const CodePointArrayView codePoints, const int probability)
: mHeadPos(ptNodeParams->getHeadPos()), mFlags(flags), mHasMovedFlag(true),
- mParentPos(parentPos), mCodePointCount(codePointCount), mCodePoints(),
+ mParentPos(parentPos), mCodePointCount(codePoints.size()), mCodePoints(),
mTerminalIdFieldPos(ptNodeParams->getTerminalIdFieldPos()),
mTerminalId(ptNodeParams->getTerminalId()),
mProbabilityFieldPos(ptNodeParams->getProbabilityFieldPos()),
@@ -102,20 +102,20 @@ class PtNodeParams {
mShortcutPos(ptNodeParams->getShortcutPos()),
mBigramPos(ptNodeParams->getBigramsPos()),
mSiblingPos(ptNodeParams->getSiblingNodePos()) {
- memcpy(mCodePoints, codePoints, sizeof(int) * mCodePointCount);
+ memcpy(mCodePoints, codePoints.data(), sizeof(int) * mCodePointCount);
}
PtNodeParams(const PatriciaTrieReadingUtils::NodeFlags flags, const int parentPos,
- const int codePointCount, const int *const codePoints, const int probability)
+ const CodePointArrayView codePoints, const int probability)
: mHeadPos(NOT_A_DICT_POS), mFlags(flags), mHasMovedFlag(true), mParentPos(parentPos),
- mCodePointCount(codePointCount), mCodePoints(),
+ mCodePointCount(codePoints.size()), mCodePoints(),
mTerminalIdFieldPos(NOT_A_DICT_POS),
mTerminalId(Ver4DictConstants::NOT_A_TERMINAL_ID),
mProbabilityFieldPos(NOT_A_DICT_POS), mProbability(probability),
mChildrenPosFieldPos(NOT_A_DICT_POS), mChildrenPos(NOT_A_DICT_POS),
mBigramLinkedNodePos(NOT_A_DICT_POS), mShortcutPos(NOT_A_DICT_POS),
mBigramPos(NOT_A_DICT_POS), mSiblingPos(NOT_A_DICT_POS) {
- memcpy(mCodePoints, codePoints, sizeof(int) * mCodePointCount);
+ memcpy(mCodePoints, codePoints.data(), sizeof(int) * mCodePointCount);
}
AK_FORCE_INLINE bool isValid() const {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.cpp
index 91c76941c..7cb7dff9a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.cpp
@@ -31,21 +31,21 @@ const int ShortcutListReadingUtils::SHORTCUT_LIST_SIZE_FIELD_SIZE = 2;
const int ShortcutListReadingUtils::WHITELIST_SHORTCUT_PROBABILITY = 15;
/* static */ ShortcutListReadingUtils::ShortcutFlags
- ShortcutListReadingUtils::getFlagsAndForwardPointer(const uint8_t *const dictRoot,
+ ShortcutListReadingUtils::getFlagsAndForwardPointer(const ReadOnlyByteArrayView buffer,
int *const pos) {
- return ByteArrayUtils::readUint8AndAdvancePosition(dictRoot, pos);
+ return ByteArrayUtils::readUint8AndAdvancePosition(buffer.data(), pos);
}
/* static */ int ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(
- const uint8_t *const dictRoot, int *const pos) {
+ const ReadOnlyByteArrayView buffer, int *const pos) {
// readUint16andAdvancePosition() returns an offset *including* the uint16 field itself.
- return ByteArrayUtils::readUint16AndAdvancePosition(dictRoot, pos)
+ return ByteArrayUtils::readUint16AndAdvancePosition(buffer.data(), pos)
- SHORTCUT_LIST_SIZE_FIELD_SIZE;
}
-/* static */ int ShortcutListReadingUtils::readShortcutTarget(
- const uint8_t *const dictRoot, const int maxLength, int *const outWord, int *const pos) {
- return ByteArrayUtils::readStringAndAdvancePosition(dictRoot, maxLength, outWord, pos);
+/* static */ int ShortcutListReadingUtils::readShortcutTarget(const ReadOnlyByteArrayView buffer,
+ const int maxLength, int *const outWord, int *const pos) {
+ return ByteArrayUtils::readStringAndAdvancePosition(buffer.data(), maxLength, outWord, pos);
}
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h
index d065bf7fd..71cb8cc2c 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h
@@ -20,6 +20,7 @@
#include <cstdint>
#include "defines.h"
+#include "utils/byte_array_view.h"
namespace latinime {
@@ -27,7 +28,8 @@ class ShortcutListReadingUtils {
public:
typedef uint8_t ShortcutFlags;
- static ShortcutFlags getFlagsAndForwardPointer(const uint8_t *const dictRoot, int *const pos);
+ static ShortcutFlags getFlagsAndForwardPointer(const ReadOnlyByteArrayView buffer,
+ int *const pos);
static AK_FORCE_INLINE int getProbabilityFromFlags(const ShortcutFlags flags) {
return flags & MASK_ATTRIBUTE_PROBABILITY;
@@ -39,14 +41,15 @@ class ShortcutListReadingUtils {
// This method returns the size of the shortcut list region excluding the shortcut list size
// field at the beginning.
- static int getShortcutListSizeAndForwardPointer(const uint8_t *const dictRoot, int *const pos);
+ static int getShortcutListSizeAndForwardPointer(const ReadOnlyByteArrayView buffer,
+ int *const pos);
static AK_FORCE_INLINE int getShortcutListSizeFieldSize() {
return SHORTCUT_LIST_SIZE_FIELD_SIZE;
}
- static AK_FORCE_INLINE void skipShortcuts(const uint8_t *const dictRoot, int *const pos) {
- const int shortcutListSize = getShortcutListSizeAndForwardPointer(dictRoot, pos);
+ static AK_FORCE_INLINE void skipShortcuts(const ReadOnlyByteArrayView buffer, int *const pos) {
+ const int shortcutListSize = getShortcutListSizeAndForwardPointer(buffer, pos);
*pos += shortcutListSize;
}
@@ -54,7 +57,7 @@ class ShortcutListReadingUtils {
return getProbabilityFromFlags(flags) == WHITELIST_SHORTCUT_PROBABILITY;
}
- static int readShortcutTarget(const uint8_t *const dictRoot, const int maxLength,
+ static int readShortcutTarget(const ReadOnlyByteArrayView buffer, const int maxLength,
int *const outWord, int *const pos);
private:
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h
index 73e291ec2..e2608435c 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/bigram/bigram_list_policy.h
@@ -22,22 +22,22 @@
#include "defines.h"
#include "suggest/core/policy/dictionary_bigrams_structure_policy.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/bigram/bigram_list_read_write_utils.h"
+#include "utils/byte_array_view.h"
namespace latinime {
class BigramListPolicy : public DictionaryBigramsStructurePolicy {
public:
- BigramListPolicy(const uint8_t *const bigramsBuf, const int bufSize)
- : mBigramsBuf(bigramsBuf), mBufSize(bufSize) {}
+ BigramListPolicy(const ReadOnlyByteArrayView buffer) : mBuffer(buffer) {}
~BigramListPolicy() {}
void getNextBigram(int *const outBigramPos, int *const outProbability, bool *const outHasNext,
int *const pos) const {
BigramListReadWriteUtils::BigramFlags flags;
- if (!BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(mBigramsBuf,
- mBufSize, &flags, outBigramPos, pos)) {
- AKLOGE("Cannot read bigram entry. mBufSize: %d, pos: %d. ", mBufSize, *pos);
+ if (!BigramListReadWriteUtils::getBigramEntryPropertiesAndAdvancePosition(mBuffer, &flags,
+ outBigramPos, pos)) {
+ AKLOGE("Cannot read bigram entry. bufSize: %zd, pos: %d. ", mBuffer.size(), *pos);
*outProbability = NOT_A_PROBABILITY;
*outHasNext = false;
return;
@@ -47,14 +47,13 @@ class BigramListPolicy : public DictionaryBigramsStructurePolicy {
}
bool skipAllBigrams(int *const pos) const {
- return BigramListReadWriteUtils::skipExistingBigrams(mBigramsBuf, mBufSize, pos);
+ return BigramListReadWriteUtils::skipExistingBigrams(mBuffer, pos);
}
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BigramListPolicy);
- const uint8_t *const mBigramsBuf;
- const int mBufSize;
+ const ReadOnlyByteArrayView mBuffer;
};
} // namespace latinime
#endif // LATINIME_BIGRAM_LIST_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp
index aae61afca..64b767dac 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp
@@ -37,19 +37,19 @@ void PatriciaTriePolicy::createAndGetAllChildDicNodes(const DicNode *const dicNo
return;
}
int nextPos = dicNode->getChildrenPtNodeArrayPos();
- if (nextPos < 0 || nextPos >= mDictBufferSize) {
- AKLOGE("Children PtNode array position is invalid. pos: %d, dict size: %d",
- nextPos, mDictBufferSize);
+ if (!isValidPos(nextPos)) {
+ AKLOGE("Children PtNode array position is invalid. pos: %d, dict size: %zd",
+ nextPos, mBuffer.size());
mIsCorrupted = true;
ASSERT(false);
return;
}
const int childCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(
- mDictRoot, &nextPos);
+ mBuffer.data(), &nextPos);
for (int i = 0; i < childCount; i++) {
- if (nextPos < 0 || nextPos >= mDictBufferSize) {
- AKLOGE("Child PtNode position is invalid. pos: %d, dict size: %d, childCount: %d / %d",
- nextPos, mDictBufferSize, i, childCount);
+ if (!isValidPos(nextPos)) {
+ AKLOGE("Child PtNode position is invalid. pos: %d, dict size: %zd, childCount: %d / %d",
+ nextPos, mBuffer.size(), i, childCount);
mIsCorrupted = true;
ASSERT(false);
return;
@@ -91,56 +91,57 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
int lastCandidatePtNodePos = 0;
// Let's loop through PtNodes in this PtNode array searching for either the terminal
// or one of its ascendants.
- if (pos < 0 || pos >= mDictBufferSize) {
- AKLOGE("PtNode array position is invalid. pos: %d, dict size: %d",
- pos, mDictBufferSize);
+ if (!isValidPos(pos)) {
+ AKLOGE("PtNode array position is invalid. pos: %d, dict size: %zd",
+ pos, mBuffer.size());
mIsCorrupted = true;
ASSERT(false);
*outUnigramProbability = NOT_A_PROBABILITY;
return 0;
}
for (int ptNodeCount = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(
- mDictRoot, &pos); ptNodeCount > 0; --ptNodeCount) {
+ mBuffer.data(), &pos); ptNodeCount > 0; --ptNodeCount) {
const int startPos = pos;
- if (pos < 0 || pos >= mDictBufferSize) {
- AKLOGE("PtNode position is invalid. pos: %d, dict size: %d", pos, mDictBufferSize);
+ if (!isValidPos(pos)) {
+ AKLOGE("PtNode position is invalid. pos: %d, dict size: %zd", pos, mBuffer.size());
mIsCorrupted = true;
ASSERT(false);
*outUnigramProbability = NOT_A_PROBABILITY;
return 0;
}
const PatriciaTrieReadingUtils::NodeFlags flags =
- PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mDictRoot, &pos);
+ PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(mBuffer.data(), &pos);
const int character = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
- mDictRoot, &pos);
+ mBuffer.data(), &pos);
if (ptNodePos == startPos) {
// We found the position. Copy the rest of the code points in the buffer and return
// the length.
outCodePoints[wordPos] = character;
if (PatriciaTrieReadingUtils::hasMultipleChars(flags)) {
int nextChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
- mDictRoot, &pos);
+ mBuffer.data(), &pos);
// We count code points in order to avoid infinite loops if the file is broken
// or if there is some other bug
int charCount = maxCodePointCount;
while (NOT_A_CODE_POINT != nextChar && --charCount > 0) {
outCodePoints[++wordPos] = nextChar;
nextChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
- mDictRoot, &pos);
+ mBuffer.data(), &pos);
}
}
*outUnigramProbability =
- PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot,
+ PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mBuffer.data(),
&pos);
return ++wordPos;
}
// We need to skip past this PtNode, so skip any remaining code points after the
// first and possibly the probability.
if (PatriciaTrieReadingUtils::hasMultipleChars(flags)) {
- PatriciaTrieReadingUtils::skipCharacters(mDictRoot, flags, MAX_WORD_LENGTH, &pos);
+ PatriciaTrieReadingUtils::skipCharacters(mBuffer.data(), flags, MAX_WORD_LENGTH,
+ &pos);
}
if (PatriciaTrieReadingUtils::isTerminal(flags)) {
- PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot, &pos);
+ PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mBuffer.data(), &pos);
}
// The fact that this PtNode has children is very important. Since we already know
// that this PtNode does not match, if it has no children we know it is irrelevant
@@ -155,7 +156,8 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
int currentPos = pos;
// Here comes the tricky part. First, read the children position.
const int childrenPos = PatriciaTrieReadingUtils
- ::readChildrenPositionAndAdvancePosition(mDictRoot, flags, &currentPos);
+ ::readChildrenPositionAndAdvancePosition(mBuffer.data(), flags,
+ &currentPos);
if (childrenPos > ptNodePos) {
// If the children pos is greater than the position, it means the previous
// PtNode, which position is stored in lastCandidatePtNodePos, was the right
@@ -185,30 +187,30 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
if (0 != lastCandidatePtNodePos) {
const PatriciaTrieReadingUtils::NodeFlags lastFlags =
PatriciaTrieReadingUtils::getFlagsAndAdvancePosition(
- mDictRoot, &lastCandidatePtNodePos);
+ mBuffer.data(), &lastCandidatePtNodePos);
const int lastChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
- mDictRoot, &lastCandidatePtNodePos);
+ mBuffer.data(), &lastCandidatePtNodePos);
// We copy all the characters in this PtNode to the buffer
outCodePoints[wordPos] = lastChar;
if (PatriciaTrieReadingUtils::hasMultipleChars(lastFlags)) {
int nextChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
- mDictRoot, &lastCandidatePtNodePos);
+ mBuffer.data(), &lastCandidatePtNodePos);
int charCount = maxCodePointCount;
while (-1 != nextChar && --charCount > 0) {
outCodePoints[++wordPos] = nextChar;
nextChar = PatriciaTrieReadingUtils::getCodePointAndAdvancePosition(
- mDictRoot, &lastCandidatePtNodePos);
+ mBuffer.data(), &lastCandidatePtNodePos);
}
}
++wordPos;
// Now we only need to branch to the children address. Skip the probability if
// it's there, read pos, and break to resume the search at pos.
if (PatriciaTrieReadingUtils::isTerminal(lastFlags)) {
- PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mDictRoot,
+ PatriciaTrieReadingUtils::readProbabilityAndAdvancePosition(mBuffer.data(),
&lastCandidatePtNodePos);
}
pos = PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
- mDictRoot, lastFlags, &lastCandidatePtNodePos);
+ mBuffer.data(), lastFlags, &lastCandidatePtNodePos);
break;
} else {
// Here is a little tricky part: we come here if we found out that all children
@@ -220,14 +222,14 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
// ready to start the next one.
if (PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) {
PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
- mDictRoot, flags, &pos);
+ mBuffer.data(), flags, &pos);
}
if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
mShortcutListPolicy.skipAllShortcuts(&pos);
}
if (PatriciaTrieReadingUtils::hasBigrams(flags)) {
if (!mBigramListPolicy.skipAllBigrams(&pos)) {
- AKLOGE("Cannot skip bigrams. BufSize: %d, pos: %d.", mDictBufferSize,
+ AKLOGE("Cannot skip bigrams. BufSize: %zd, pos: %d.", mBuffer.size(),
pos);
mIsCorrupted = true;
ASSERT(false);
@@ -244,14 +246,14 @@ int PatriciaTriePolicy::getCodePointsAndProbabilityAndReturnCodePointCount(
// our pos is after the end of this PtNode, at the start of the next one.
if (PatriciaTrieReadingUtils::hasChildrenInFlags(flags)) {
PatriciaTrieReadingUtils::readChildrenPositionAndAdvancePosition(
- mDictRoot, flags, &pos);
+ mBuffer.data(), flags, &pos);
}
if (PatriciaTrieReadingUtils::hasShortcutTargets(flags)) {
mShortcutListPolicy.skipAllShortcuts(&pos);
}
if (PatriciaTrieReadingUtils::hasBigrams(flags)) {
if (!mBigramListPolicy.skipAllBigrams(&pos)) {
- AKLOGE("Cannot skip bigrams. BufSize: %d, pos: %d.", mDictBufferSize, pos);
+ AKLOGE("Cannot skip bigrams. BufSize: %zd, pos: %d.", mBuffer.size(), pos);
mIsCorrupted = true;
ASSERT(false);
*outUnigramProbability = NOT_A_PROBABILITY;
@@ -402,7 +404,7 @@ int PatriciaTriePolicy::createAndGetLeavingChildNode(const DicNode *const dicNod
int shortcutPos = NOT_A_DICT_POS;
int bigramPos = NOT_A_DICT_POS;
int siblingPos = NOT_A_DICT_POS;
- PatriciaTrieReadingUtils::readPtNodeInfo(mDictRoot, ptNodePos, &mShortcutListPolicy,
+ PatriciaTrieReadingUtils::readPtNodeInfo(mBuffer.data(), ptNodePos, &mShortcutListPolicy,
&mBigramListPolicy, &flags, &mergedNodeCodePointCount, mergedNodeCodePoints,
&probability, &childrenPos, &shortcutPos, &bigramPos, &siblingPos);
// Skip PtNodes don't start with Unicode code point because they represent non-word information.
@@ -452,14 +454,14 @@ const WordProperty PatriciaTriePolicy::getWordProperty(
int shortcutPos = getShortcutPositionOfPtNode(ptNodePos);
if (shortcutPos != NOT_A_DICT_POS) {
int shortcutTargetCodePoints[MAX_WORD_LENGTH];
- ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(mDictRoot, &shortcutPos);
+ ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(mBuffer, &shortcutPos);
bool hasNext = true;
while (hasNext) {
const ShortcutListReadingUtils::ShortcutFlags shortcutFlags =
- ShortcutListReadingUtils::getFlagsAndForwardPointer(mDictRoot, &shortcutPos);
+ ShortcutListReadingUtils::getFlagsAndForwardPointer(mBuffer, &shortcutPos);
hasNext = ShortcutListReadingUtils::hasNext(shortcutFlags);
const int shortcutTargetLength = ShortcutListReadingUtils::readShortcutTarget(
- mDictRoot, MAX_WORD_LENGTH, shortcutTargetCodePoints, &shortcutPos);
+ mBuffer, MAX_WORD_LENGTH, shortcutTargetCodePoints, &shortcutPos);
const std::vector<int> shortcutTarget(shortcutTargetCodePoints,
shortcutTargetCodePoints + shortcutTargetLength);
const int shortcutProbability =
@@ -512,4 +514,9 @@ int PatriciaTriePolicy::getWordIdFromTerminalPtNodePos(const int ptNodePos) cons
int PatriciaTriePolicy::getTerminalPtNodePosFromWordId(const int wordId) const {
return wordId == NOT_A_WORD_ID ? NOT_A_DICT_POS : wordId;
}
+
+bool PatriciaTriePolicy::isValidPos(const int pos) const {
+ return pos >= 0 && pos < static_cast<int>(mBuffer.size());
+}
+
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
index fc65de58c..70e8d847e 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h
@@ -44,14 +44,11 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
: mMmappedBuffer(std::move(mmappedBuffer)),
mHeaderPolicy(mMmappedBuffer->getReadOnlyByteArrayView().data(),
FormatUtils::VERSION_2),
- mDictRoot(mMmappedBuffer->getReadOnlyByteArrayView().data()
- + mHeaderPolicy.getSize()),
- mDictBufferSize(mMmappedBuffer->getReadOnlyByteArrayView().size()
- - mHeaderPolicy.getSize()),
- mBigramListPolicy(mDictRoot, mDictBufferSize), mShortcutListPolicy(mDictRoot),
- mPtNodeReader(mDictRoot, mDictBufferSize, &mBigramListPolicy, &mShortcutListPolicy),
- mPtNodeArrayReader(mDictRoot, mDictBufferSize),
- mTerminalPtNodePositionsForIteratingWords(), mIsCorrupted(false) {}
+ mBuffer(mMmappedBuffer->getReadOnlyByteArrayView().skip(mHeaderPolicy.getSize())),
+ mBigramListPolicy(mBuffer), mShortcutListPolicy(mBuffer),
+ mPtNodeReader(mBuffer, &mBigramListPolicy, &mShortcutListPolicy),
+ mPtNodeArrayReader(mBuffer), mTerminalPtNodePositionsForIteratingWords(),
+ mIsCorrupted(false) {}
AK_FORCE_INLINE int getRootPosition() const {
return 0;
@@ -149,8 +146,7 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
const MmappedBuffer::MmappedBufferPtr mMmappedBuffer;
const HeaderPolicy mHeaderPolicy;
- const uint8_t *const mDictRoot;
- const int mDictBufferSize;
+ const ReadOnlyByteArrayView mBuffer;
const BigramListPolicy mBigramListPolicy;
const ShortcutListPolicy mShortcutListPolicy;
const Ver2ParticiaTrieNodeReader mPtNodeReader;
@@ -166,6 +162,7 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
int getTerminalPtNodePosFromWordId(const int wordId) const;
const WordAttributes getWordAttributes(const int probability,
const PtNodeParams &ptNodeParams) const;
+ bool isValidPos(const int pos) const;
};
} // namespace latinime
#endif // LATINIME_PATRICIA_TRIE_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/shortcut/shortcut_list_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/shortcut/shortcut_list_policy.h
index 8e16ccc05..5319dd26c 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/shortcut/shortcut_list_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/shortcut/shortcut_list_policy.h
@@ -22,13 +22,13 @@
#include "defines.h"
#include "suggest/core/policy/dictionary_shortcuts_structure_policy.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/shortcut/shortcut_list_reading_utils.h"
+#include "utils/byte_array_view.h"
namespace latinime {
class ShortcutListPolicy : public DictionaryShortcutsStructurePolicy {
public:
- explicit ShortcutListPolicy(const uint8_t *const shortcutBuf)
- : mShortcutsBuf(shortcutBuf) {}
+ explicit ShortcutListPolicy(const ReadOnlyByteArrayView buffer) : mBuffer(buffer) {}
~ShortcutListPolicy() {}
@@ -37,7 +37,7 @@ class ShortcutListPolicy : public DictionaryShortcutsStructurePolicy {
return NOT_A_DICT_POS;
}
int listPos = pos;
- ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(mShortcutsBuf, &listPos);
+ ShortcutListReadingUtils::getShortcutListSizeAndForwardPointer(mBuffer, &listPos);
return listPos;
}
@@ -45,7 +45,7 @@ class ShortcutListPolicy : public DictionaryShortcutsStructurePolicy {
int *const outCodePointCount, bool *const outIsWhitelist, bool *const outHasNext,
int *const pos) const {
const ShortcutListReadingUtils::ShortcutFlags flags =
- ShortcutListReadingUtils::getFlagsAndForwardPointer(mShortcutsBuf, pos);
+ ShortcutListReadingUtils::getFlagsAndForwardPointer(mBuffer, pos);
if (outHasNext) {
*outHasNext = ShortcutListReadingUtils::hasNext(flags);
}
@@ -54,20 +54,20 @@ class ShortcutListPolicy : public DictionaryShortcutsStructurePolicy {
}
if (outCodePoint) {
*outCodePointCount = ShortcutListReadingUtils::readShortcutTarget(
- mShortcutsBuf, maxCodePointCount, outCodePoint, pos);
+ mBuffer, maxCodePointCount, outCodePoint, pos);
}
}
void skipAllShortcuts(int *const pos) const {
const int shortcutListSize = ShortcutListReadingUtils
- ::getShortcutListSizeAndForwardPointer(mShortcutsBuf, pos);
+ ::getShortcutListSizeAndForwardPointer(mBuffer, pos);
*pos += shortcutListSize;
}
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ShortcutListPolicy);
- const uint8_t *const mShortcutsBuf;
+ const ReadOnlyByteArrayView mBuffer;
};
} // namespace latinime
#endif // LATINIME_SHORTCUT_LIST_POLICY_H
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp
index c1e938710..74cdf7929 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp
@@ -22,10 +22,10 @@ namespace latinime {
const PtNodeParams Ver2ParticiaTrieNodeReader::fetchPtNodeParamsInBufferFromPtNodePos(
const int ptNodePos) const {
- if (ptNodePos < 0 || ptNodePos >= mDictSize) {
+ if (ptNodePos < 0 || ptNodePos >= static_cast<int>(mBuffer.size())) {
// Reading invalid position because of bug or broken dictionary.
- AKLOGE("Fetching PtNode info from invalid dictionary position: %d, dictionary size: %d",
- ptNodePos, mDictSize);
+ AKLOGE("Fetching PtNode info from invalid dictionary position: %d, dictionary size: %zd",
+ ptNodePos, mBuffer.size());
ASSERT(false);
return PtNodeParams();
}
@@ -37,7 +37,7 @@ const PtNodeParams Ver2ParticiaTrieNodeReader::fetchPtNodeParamsInBufferFromPtNo
int shortcutPos = NOT_A_DICT_POS;
int bigramPos = NOT_A_DICT_POS;
int siblingPos = NOT_A_DICT_POS;
- PatriciaTrieReadingUtils::readPtNodeInfo(mDictBuffer, ptNodePos, mShortuctPolicy,
+ PatriciaTrieReadingUtils::readPtNodeInfo(mBuffer.data(), ptNodePos, mShortuctPolicy,
mBigramPolicy, &flags, &mergedNodeCodePointCount, mergedNodeCodePoints, &probability,
&childrenPos, &shortcutPos, &bigramPos, &siblingPos);
if (mergedNodeCodePointCount <= 0) {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h
index f0725b66d..0f6769dc8 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h
@@ -22,6 +22,7 @@
#include "defines.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_params.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_reader.h"
+#include "utils/byte_array_view.h"
namespace latinime {
@@ -30,19 +31,17 @@ class DictionaryShortcutsStructurePolicy;
class Ver2ParticiaTrieNodeReader : public PtNodeReader {
public:
- Ver2ParticiaTrieNodeReader(const uint8_t *const dictBuffer, const int dictSize,
+ Ver2ParticiaTrieNodeReader(const ReadOnlyByteArrayView buffer,
const DictionaryBigramsStructurePolicy *const bigramPolicy,
const DictionaryShortcutsStructurePolicy *const shortcutPolicy)
- : mDictBuffer(dictBuffer), mDictSize(dictSize), mBigramPolicy(bigramPolicy),
- mShortuctPolicy(shortcutPolicy) {}
+ : mBuffer(buffer), mBigramPolicy(bigramPolicy), mShortuctPolicy(shortcutPolicy) {}
virtual const PtNodeParams fetchPtNodeParamsInBufferFromPtNodePos(const int ptNodePos) const;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Ver2ParticiaTrieNodeReader);
- const uint8_t *const mDictBuffer;
- const int mDictSize;
+ const ReadOnlyByteArrayView mBuffer;
const DictionaryBigramsStructurePolicy *const mBigramPolicy;
const DictionaryShortcutsStructurePolicy *const mShortuctPolicy;
};
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.cpp
index b46617d96..72ad1eb66 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.cpp
@@ -22,16 +22,16 @@ namespace latinime {
bool Ver2PtNodeArrayReader::readPtNodeArrayInfoAndReturnIfValid(const int ptNodeArrayPos,
int *const outPtNodeCount, int *const outFirstPtNodePos) const {
- if (ptNodeArrayPos < 0 || ptNodeArrayPos >= mDictSize) {
+ if (ptNodeArrayPos < 0 || ptNodeArrayPos >= static_cast<int>(mBuffer.size())) {
// Reading invalid position because of a bug or a broken dictionary.
- AKLOGE("Reading PtNode array info from invalid dictionary position: %d, dict size: %d",
- ptNodeArrayPos, mDictSize);
+ AKLOGE("Reading PtNode array info from invalid dictionary position: %d, dict size: %zd",
+ ptNodeArrayPos, mBuffer.size());
ASSERT(false);
return false;
}
int readingPos = ptNodeArrayPos;
const int ptNodeCountInArray = PatriciaTrieReadingUtils::getPtNodeArraySizeAndAdvancePosition(
- mDictBuffer, &readingPos);
+ mBuffer.data(), &readingPos);
*outPtNodeCount = ptNodeCountInArray;
*outFirstPtNodePos = readingPos;
return true;
@@ -39,10 +39,10 @@ bool Ver2PtNodeArrayReader::readPtNodeArrayInfoAndReturnIfValid(const int ptNode
bool Ver2PtNodeArrayReader::readForwardLinkAndReturnIfValid(const int forwordLinkPos,
int *const outNextPtNodeArrayPos) const {
- if (forwordLinkPos < 0 || forwordLinkPos >= mDictSize) {
+ if (forwordLinkPos < 0 || forwordLinkPos >= static_cast<int>(mBuffer.size())) {
// Reading invalid position because of bug or broken dictionary.
- AKLOGE("Reading forward link from invalid dictionary position: %d, dict size: %d",
- forwordLinkPos, mDictSize);
+ AKLOGE("Reading forward link from invalid dictionary position: %d, dict size: %zd",
+ forwordLinkPos, mBuffer.size());
ASSERT(false);
return false;
}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h
index 548272148..548f36bf3 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_pt_node_array_reader.h
@@ -21,13 +21,13 @@
#include "defines.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/pt_node_array_reader.h"
+#include "utils/byte_array_view.h"
namespace latinime {
class Ver2PtNodeArrayReader : public PtNodeArrayReader {
public:
- Ver2PtNodeArrayReader(const uint8_t *const dictBuffer, const int dictSize)
- : mDictBuffer(dictBuffer), mDictSize(dictSize) {};
+ Ver2PtNodeArrayReader(const ReadOnlyByteArrayView buffer) : mBuffer(buffer) {};
virtual bool readPtNodeArrayInfoAndReturnIfValid(const int ptNodeArrayPos,
int *const outPtNodeCount, int *const outFirstPtNodePos) const;
@@ -37,8 +37,7 @@ class Ver2PtNodeArrayReader : public PtNodeArrayReader {
private:
DISALLOW_COPY_AND_ASSIGN(Ver2PtNodeArrayReader);
- const uint8_t *const mDictBuffer;
- const int mDictSize;
+ const ReadOnlyByteArrayView mBuffer;
};
} // namespace latinime
#endif /* LATINIME_VER2_PT_NODE_ARRAY_READER_H */
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp
index f54bb151a..35f0f768f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp
@@ -39,7 +39,7 @@ bool LanguageModelDictContent::runGC(
}
int LanguageModelDictContent::getWordProbability(const WordIdArrayView prevWordIds,
- const int wordId) const {
+ const int wordId, const HeaderPolicy *const headerPolicy) const {
int bitmapEntryIndices[MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1];
bitmapEntryIndices[0] = mTrieMap.getRootBitmapEntryIndex();
int maxLevel = 0;
@@ -58,14 +58,15 @@ int LanguageModelDictContent::getWordProbability(const WordIdArrayView prevWordI
if (!result.mIsValid) {
continue;
}
- const int probability =
- ProbabilityEntry::decode(result.mValue, mHasHistoricalInfo).getProbability();
+ const ProbabilityEntry probabilityEntry =
+ ProbabilityEntry::decode(result.mValue, mHasHistoricalInfo);
if (mHasHistoricalInfo) {
- return std::min(
- probability + ForgettingCurveUtils::getProbabilityBiasForNgram(i + 1 /* n */),
- MAX_PROBABILITY);
+ const int probability = ForgettingCurveUtils::decodeProbability(
+ probabilityEntry.getHistoricalInfo(), headerPolicy)
+ + ForgettingCurveUtils::getProbabilityBiasForNgram(i + 1 /* n */);
+ return std::min(probability, MAX_PROBABILITY);
} else {
- return probability;
+ return probabilityEntry.getProbability();
}
}
// Cannot find the word.
@@ -166,7 +167,15 @@ int LanguageModelDictContent::createAndGetBitmapEntryIndex(const WordIdArrayView
if (lastBitmapEntryIndex == TrieMap::INVALID_INDEX) {
return TrieMap::INVALID_INDEX;
}
- return mTrieMap.getNextLevelBitmapEntryIndex(prevWordIds[prevWordIds.size() - 1],
+ const int oldestPrevWordId = prevWordIds.lastOrDefault(NOT_A_WORD_ID);
+ const TrieMap::Result result = mTrieMap.get(oldestPrevWordId, lastBitmapEntryIndex);
+ if (!result.mIsValid) {
+ if (!mTrieMap.put(oldestPrevWordId,
+ ProbabilityEntry().encode(mHasHistoricalInfo), lastBitmapEntryIndex)) {
+ return TrieMap::INVALID_INDEX;
+ }
+ }
+ return mTrieMap.getNextLevelBitmapEntryIndex(prevWordIds.lastOrDefault(NOT_A_WORD_ID),
lastBitmapEntryIndex);
}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h
index 4e0b47036..a793af4be 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h
@@ -128,7 +128,8 @@ class LanguageModelDictContent {
const LanguageModelDictContent *const originalContent,
int *const outNgramCount);
- int getWordProbability(const WordIdArrayView prevWordIds, const int wordId) const;
+ int getWordProbability(const WordIdArrayView prevWordIds, const int wordId,
+ const HeaderPolicy *const headerPolicy) const;
ProbabilityEntry getProbabilityEntry(const int wordId) const {
return getNgramProbabilityEntry(WordIdArrayView(), wordId);
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h
index 3dfaba755..f1bf12cb2 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h
@@ -36,7 +36,8 @@ class ProbabilityEntry {
// Dummy entry
ProbabilityEntry()
- : mFlags(0), mProbability(NOT_A_PROBABILITY), mHistoricalInfo() {}
+ : mFlags(Ver4DictConstants::FLAG_NOT_A_VALID_ENTRY), mProbability(NOT_A_PROBABILITY),
+ mHistoricalInfo() {}
// Entry without historical information
ProbabilityEntry(const int flags, const int probability)
@@ -61,7 +62,7 @@ class ProbabilityEntry {
bigramProperty->getCount()) {}
bool isValid() const {
- return (mProbability != NOT_A_PROBABILITY) || hasHistoricalInfo();
+ return (mFlags & Ver4DictConstants::FLAG_NOT_A_VALID_ENTRY) == 0;
}
bool hasHistoricalInfo() const {
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
index 9acf2d44f..39822b94a 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.cpp
@@ -53,6 +53,7 @@ const int Ver4DictConstants::WORD_LEVEL_FIELD_SIZE = 1;
const int Ver4DictConstants::WORD_COUNT_FIELD_SIZE = 1;
const uint8_t Ver4DictConstants::FLAG_REPRESENTS_BEGINNING_OF_SENTENCE = 0x1;
+const uint8_t Ver4DictConstants::FLAG_NOT_A_VALID_ENTRY = 0x2;
const int Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE = 64;
const int Ver4DictConstants::SHORTCUT_ADDRESS_TABLE_DATA_SIZE = 4;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
index 97035311e..dfcdd4d6f 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_dict_constants.h
@@ -51,6 +51,7 @@ class Ver4DictConstants {
static const int WORD_COUNT_FIELD_SIZE;
// Flags in probability entry.
static const uint8_t FLAG_REPRESENTS_BEGINNING_OF_SENTENCE;
+ static const uint8_t FLAG_NOT_A_VALID_ENTRY;
static const int SHORTCUT_ADDRESS_TABLE_BLOCK_SIZE;
static const int SHORTCUT_ADDRESS_TABLE_DATA_SIZE;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
index 9ca712470..75ec16912 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp
@@ -211,19 +211,17 @@ bool Ver4PatriciaTrieNodeWriter::writeNewTerminalPtNodeAndAdvancePosition(
bool Ver4PatriciaTrieNodeWriter::addNgramEntry(const WordIdArrayView prevWordIds, const int wordId,
const BigramProperty *const bigramProperty, bool *const outAddedNewBigram) {
- // TODO: Support n-gram.
LanguageModelDictContent *const languageModelDictContent =
mBuffers->getMutableLanguageModelDictContent();
const ProbabilityEntry probabilityEntry =
- languageModelDictContent->getNgramProbabilityEntry(
- prevWordIds.limit(1 /* maxSize */), wordId);
+ languageModelDictContent->getNgramProbabilityEntry(prevWordIds, wordId);
const ProbabilityEntry probabilityEntryOfBigramProperty(bigramProperty);
const ProbabilityEntry updatedProbabilityEntry = createUpdatedEntryFrom(
&probabilityEntry, &probabilityEntryOfBigramProperty);
if (!languageModelDictContent->setNgramProbabilityEntry(
- prevWordIds.limit(1 /* maxSize */), wordId, &updatedProbabilityEntry)) {
- AKLOGE("Cannot add new ngram entry. prevWordId: %d, wordId: %d",
- prevWordIds[0], wordId);
+ prevWordIds, wordId, &updatedProbabilityEntry)) {
+ AKLOGE("Cannot add new ngram entry. prevWordId[0]: %d, prevWordId.size(): %zd, wordId: %d",
+ prevWordIds[0], prevWordIds.size(), wordId);
return false;
}
if (!probabilityEntry.isValid() && outAddedNewBigram) {
@@ -234,11 +232,9 @@ bool Ver4PatriciaTrieNodeWriter::addNgramEntry(const WordIdArrayView prevWordIds
bool Ver4PatriciaTrieNodeWriter::removeNgramEntry(const WordIdArrayView prevWordIds,
const int wordId) {
- // TODO: Support n-gram.
LanguageModelDictContent *const languageModelDictContent =
mBuffers->getMutableLanguageModelDictContent();
- return languageModelDictContent->removeNgramProbabilityEntry(prevWordIds.limit(1 /* maxSize */),
- wordId);
+ return languageModelDictContent->removeNgramProbabilityEntry(prevWordIds, wordId);
}
// TODO: Remove when we stop supporting v402 format.
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
index 5b1907f49..8d4135679 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp
@@ -120,15 +120,15 @@ const WordAttributes Ver4PatriciaTriePolicy::getWordAttributesInContext(
const int ptNodePos =
mBuffers->getTerminalPositionLookupTable()->getTerminalPtNodePosition(wordId);
const PtNodeParams ptNodeParams = mNodeReader.fetchPtNodeParamsInBufferFromPtNodePos(ptNodePos);
- // TODO: Support n-gram.
- return WordAttributes(mBuffers->getLanguageModelDictContent()->getWordProbability(
- prevWordIds.limit(1 /* maxSize */), wordId), ptNodeParams.isBlacklisted(),
- ptNodeParams.isNotAWord(), ptNodeParams.getProbability() == 0);
+ const int probability = mBuffers->getLanguageModelDictContent()->getWordProbability(
+ prevWordIds, wordId, mHeaderPolicy);
+ return WordAttributes(probability, ptNodeParams.isBlacklisted(), ptNodeParams.isNotAWord(),
+ probability == 0);
}
int Ver4PatriciaTriePolicy::getProbabilityOfWord(const WordIdArrayView prevWordIds,
const int wordId) const {
- if (wordId == NOT_A_WORD_ID) {
+ if (wordId == NOT_A_WORD_ID || prevWordIds.contains(NOT_A_WORD_ID)) {
return NOT_A_PROBABILITY;
}
const int ptNodePos =
@@ -137,10 +137,8 @@ int Ver4PatriciaTriePolicy::getProbabilityOfWord(const WordIdArrayView prevWordI
if (ptNodeParams.isDeleted() || ptNodeParams.isBlacklisted() || ptNodeParams.isNotAWord()) {
return NOT_A_PROBABILITY;
}
- // TODO: Support n-gram.
const ProbabilityEntry probabilityEntry =
- mBuffers->getLanguageModelDictContent()->getNgramProbabilityEntry(
- prevWordIds.limit(1 /* maxSize */), wordId);
+ mBuffers->getLanguageModelDictContent()->getNgramProbabilityEntry(prevWordIds, wordId);
if (!probabilityEntry.isValid()) {
return NOT_A_PROBABILITY;
}
@@ -163,16 +161,18 @@ void Ver4PatriciaTriePolicy::iterateNgramEntries(const WordIdArrayView prevWordI
if (prevWordIds.empty()) {
return;
}
- // TODO: Support n-gram.
const auto languageModelDictContent = mBuffers->getLanguageModelDictContent();
- for (const auto entry : languageModelDictContent->getProbabilityEntries(
- prevWordIds.limit(1 /* maxSize */))) {
- const ProbabilityEntry &probabilityEntry = entry.getProbabilityEntry();
- const int probability = probabilityEntry.hasHistoricalInfo() ?
- ForgettingCurveUtils::decodeProbability(
- probabilityEntry.getHistoricalInfo(), mHeaderPolicy) :
- probabilityEntry.getProbability();
- listener->onVisitEntry(probability, entry.getWordId());
+ for (size_t i = 1; i <= prevWordIds.size(); ++i) {
+ for (const auto entry : languageModelDictContent->getProbabilityEntries(
+ prevWordIds.limit(i))) {
+ const ProbabilityEntry &probabilityEntry = entry.getProbabilityEntry();
+ const int probability = probabilityEntry.hasHistoricalInfo() ?
+ ForgettingCurveUtils::decodeProbability(
+ probabilityEntry.getHistoricalInfo(), mHeaderPolicy)
+ + ForgettingCurveUtils::getProbabilityBiasForNgram(i + 1 /* n */) :
+ probabilityEntry.getProbability();
+ listener->onVisitEntry(probability, entry.getWordId());
+ }
}
}
@@ -227,8 +227,8 @@ bool Ver4PatriciaTriePolicy::addUnigramEntry(const CodePointArrayView wordCodePo
return false;
}
const CodePointArrayView codePointArrayView(codePointsToAdd, codePointCountToAdd);
- if (mUpdatingHelper.addUnigramWord(&readingHelper, codePointArrayView.data(),
- codePointArrayView.size(), unigramProperty, &addedNewUnigram)) {
+ if (mUpdatingHelper.addUnigramWord(&readingHelper, codePointArrayView, unigramProperty,
+ &addedNewUnigram)) {
if (addedNewUnigram && !unigramProperty->representsBeginningOfSentence()) {
mUnigramCount++;
}
@@ -243,8 +243,8 @@ bool Ver4PatriciaTriePolicy::addUnigramEntry(const CodePointArrayView wordCodePo
mBuffers->getTerminalPositionLookupTable()->getTerminalPtNodePosition(wordId);
for (const auto &shortcut : unigramProperty->getShortcuts()) {
if (!mUpdatingHelper.addShortcutTarget(wordPos,
- shortcut.getTargetCodePoints()->data(),
- shortcut.getTargetCodePoints()->size(), shortcut.getProbability())) {
+ CodePointArrayView(*shortcut.getTargetCodePoints()),
+ shortcut.getProbability())) {
AKLOGE("Cannot add new shortcut target. PtNodePos: %d, length: %zd, "
"probability: %d", wordPos, shortcut.getTargetCodePoints()->size(),
shortcut.getProbability());
@@ -303,26 +303,31 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
"length: %zd", bigramProperty->getTargetCodePoints()->size());
return false;
}
- WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIds;
- prevWordsInfo->getPrevWordIds(this, prevWordIds.data(), false /* tryLowerCaseSearch */);
- // TODO: Support N-gram.
- if (prevWordIds[0] == NOT_A_WORD_ID) {
- if (prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)) {
- const std::vector<UnigramProperty::ShortcutProperty> shortcuts;
- const UnigramProperty beginningOfSentenceUnigramProperty(
- true /* representsBeginningOfSentence */, true /* isNotAWord */,
- false /* isBlacklisted */, MAX_PROBABILITY /* probability */,
- NOT_A_TIMESTAMP /* timestamp */, 0 /* level */, 0 /* count */, &shortcuts);
- if (!addUnigramEntry(prevWordsInfo->getNthPrevWordCodePoints(1 /* n */),
- &beginningOfSentenceUnigramProperty)) {
- AKLOGE("Cannot add unigram entry for the beginning-of-sentence.");
- return false;
- }
- // Refresh word ids.
- prevWordsInfo->getPrevWordIds(this, prevWordIds.data(), false /* tryLowerCaseSearch */);
- } else {
+ WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
+ const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds(this, &prevWordIdArray,
+ false /* tryLowerCaseSearch */);
+ if (prevWordIds.empty()) {
+ return false;
+ }
+ for (size_t i = 0; i < prevWordIds.size(); ++i) {
+ if (prevWordIds[i] != NOT_A_WORD_ID) {
+ continue;
+ }
+ if (!prevWordsInfo->isNthPrevWordBeginningOfSentence(i + 1 /* n */)) {
+ return false;
+ }
+ const std::vector<UnigramProperty::ShortcutProperty> shortcuts;
+ const UnigramProperty beginningOfSentenceUnigramProperty(
+ true /* representsBeginningOfSentence */, true /* isNotAWord */,
+ false /* isBlacklisted */, MAX_PROBABILITY /* probability */,
+ NOT_A_TIMESTAMP /* timestamp */, 0 /* level */, 0 /* count */, &shortcuts);
+ if (!addUnigramEntry(prevWordsInfo->getNthPrevWordCodePoints(1 /* n */),
+ &beginningOfSentenceUnigramProperty)) {
+ AKLOGE("Cannot add unigram entry for the beginning-of-sentence.");
return false;
}
+ // Refresh word ids.
+ prevWordsInfo->getPrevWordIds(this, &prevWordIdArray, false /* tryLowerCaseSearch */);
}
const int wordId = getWordId(CodePointArrayView(*bigramProperty->getTargetCodePoints()),
false /* forceLowerCaseSearch */);
@@ -330,15 +335,7 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
return false;
}
bool addedNewEntry = false;
- WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordsPtNodePos;
- for (size_t i = 0; i < prevWordsPtNodePos.size(); ++i) {
- prevWordsPtNodePos[i] = mBuffers->getTerminalPositionLookupTable()
- ->getTerminalPtNodePosition(prevWordIds[i]);
- }
- const int wordPtNodePos = mBuffers->getTerminalPositionLookupTable()
- ->getTerminalPtNodePosition(wordId);
- if (mUpdatingHelper.addNgramEntry(WordIdArrayView::fromArray(prevWordsPtNodePos),
- wordPtNodePos, bigramProperty, &addedNewEntry)) {
+ if (mNodeWriter.addNgramEntry(prevWordIds, wordId, bigramProperty, &addedNewEntry)) {
if (addedNewEntry) {
mBigramCount++;
}
@@ -367,25 +364,17 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor
AKLOGE("word is too long to remove n-gram entry form the dictionary. length: %zd",
wordCodePoints.size());
}
- WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIds;
- prevWordsInfo->getPrevWordIds(this, prevWordIds.data(), false /* tryLowerCaseSerch */);
- // TODO: Support N-gram.
- if (prevWordIds[0] == NOT_A_WORD_ID) {
+ WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
+ const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds(this, &prevWordIdArray,
+ false /* tryLowerCaseSerch */);
+ if (prevWordIds.empty() || prevWordIds.contains(NOT_A_WORD_ID)) {
return false;
}
const int wordId = getWordId(wordCodePoints, false /* forceLowerCaseSearch */);
if (wordId == NOT_A_WORD_ID) {
return false;
}
- std::array<int, MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordsPtNodePos;
- for (size_t i = 0; i < prevWordsPtNodePos.size(); ++i) {
- prevWordsPtNodePos[i] = mBuffers->getTerminalPositionLookupTable()
- ->getTerminalPtNodePosition(prevWordIds[i]);
- }
- const int wordPtNodePos = mBuffers->getTerminalPositionLookupTable()
- ->getTerminalPtNodePosition(wordId);
- if (mUpdatingHelper.removeNgramEntry(WordIdArrayView::fromArray(prevWordsPtNodePos),
- wordPtNodePos)) {
+ if (mNodeWriter.removeNgramEntry(prevWordIds, wordId)) {
mBigramCount--;
return true;
} else {
diff --git a/native/jni/src/utils/byte_array_view.h b/native/jni/src/utils/byte_array_view.h
index 10d7ae278..2b778af6f 100644
--- a/native/jni/src/utils/byte_array_view.h
+++ b/native/jni/src/utils/byte_array_view.h
@@ -42,6 +42,13 @@ class ReadOnlyByteArrayView {
return mPtr;
}
+ AK_FORCE_INLINE const ReadOnlyByteArrayView skip(const size_t n) const {
+ if (mSize <= n) {
+ return ReadOnlyByteArrayView();
+ }
+ return ReadOnlyByteArrayView(mPtr + n, mSize - n);
+ }
+
private:
DISALLOW_ASSIGNMENT_OPERATOR(ReadOnlyByteArrayView);
diff --git a/native/jni/src/utils/int_array_view.h b/native/jni/src/utils/int_array_view.h
index caa13d976..f3a8589ca 100644
--- a/native/jni/src/utils/int_array_view.h
+++ b/native/jni/src/utils/int_array_view.h
@@ -17,6 +17,7 @@
#ifndef LATINIME_INT_ARRAY_VIEW_H
#define LATINIME_INT_ARRAY_VIEW_H
+#include <algorithm>
#include <array>
#include <cstdint>
#include <cstring>
@@ -92,12 +93,16 @@ class IntArrayView {
return mPtr + mSize;
}
+ AK_FORCE_INLINE bool contains(const int value) const {
+ return std::find(begin(), end(), value) != end();
+ }
+
// Returns the view whose size is smaller than or equal to the given count.
- const IntArrayView limit(const size_t maxSize) const {
+ AK_FORCE_INLINE const IntArrayView limit(const size_t maxSize) const {
return IntArrayView(mPtr, std::min(maxSize, mSize));
}
- const IntArrayView skip(const size_t n) const {
+ AK_FORCE_INLINE const IntArrayView skip(const size_t n) const {
if (mSize <= n) {
return IntArrayView();
}
@@ -110,6 +115,20 @@ class IntArrayView {
memmove(buffer->data() + offset, mPtr, sizeof(int) * mSize);
}
+ AK_FORCE_INLINE int firstOrDefault(const int defaultValue) const {
+ if (empty()) {
+ return defaultValue;
+ }
+ return mPtr[0];
+ }
+
+ AK_FORCE_INLINE int lastOrDefault(const int defaultValue) const {
+ if (empty()) {
+ return defaultValue;
+ }
+ return mPtr[mSize - 1];
+ }
+
private:
DISALLOW_ASSIGNMENT_OPERATOR(IntArrayView);
diff --git a/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp b/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp
index 7608b45c2..06f82df52 100644
--- a/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp
+++ b/native/jni/tests/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content_test.cpp
@@ -29,7 +29,7 @@ namespace {
TEST(LanguageModelDictContentTest, TestUnigramProbability) {
LanguageModelDictContent languageModelDictContent(false /* useHistoricalInfo */);
- const int flag = 0xFF;
+ const int flag = 0xF0;
const int probability = 10;
const int wordId = 100;
const ProbabilityEntry probabilityEntry(flag, probability);
@@ -107,13 +107,15 @@ TEST(LanguageModelDictContentTest, TestGetWordProbability) {
languageModelDictContent.setProbabilityEntry(prevWordIds[0], &probabilityEntry);
languageModelDictContent.setNgramProbabilityEntry(prevWordIds.limit(1), wordId,
&bigramProbabilityEntry);
- EXPECT_EQ(bigramProbability, languageModelDictContent.getWordProbability(prevWordIds, wordId));
+ EXPECT_EQ(bigramProbability, languageModelDictContent.getWordProbability(prevWordIds, wordId,
+ nullptr /* headerPolicy */));
const ProbabilityEntry trigramProbabilityEntry(flag, trigramProbability);
languageModelDictContent.setNgramProbabilityEntry(prevWordIds.limit(1),
prevWordIds[1], &probabilityEntry);
languageModelDictContent.setNgramProbabilityEntry(prevWordIds.limit(2), wordId,
&trigramProbabilityEntry);
- EXPECT_EQ(trigramProbability, languageModelDictContent.getWordProbability(prevWordIds, wordId));
+ EXPECT_EQ(trigramProbability, languageModelDictContent.getWordProbability(prevWordIds, wordId,
+ nullptr /* headerPolicy */));
}
} // namespace
diff --git a/native/jni/tests/utils/int_array_view_test.cpp b/native/jni/tests/utils/int_array_view_test.cpp
index 3bc294cdd..487bd04b1 100644
--- a/native/jni/tests/utils/int_array_view_test.cpp
+++ b/native/jni/tests/utils/int_array_view_test.cpp
@@ -58,6 +58,19 @@ TEST(IntArrayViewTest, TestConstructFromObject) {
EXPECT_EQ(object, intArrayView[0]);
}
+TEST(IntArrayViewTest, TestContains) {
+ EXPECT_FALSE(IntArrayView().contains(0));
+ EXPECT_FALSE(IntArrayView().contains(1));
+
+ const std::vector<int> intVector = {3, 2, 1, 0, -1, -2};
+ IntArrayView intArrayView(intVector);
+ EXPECT_TRUE(intArrayView.contains(0));
+ EXPECT_TRUE(intArrayView.contains(3));
+ EXPECT_TRUE(intArrayView.contains(-2));
+ EXPECT_FALSE(intArrayView.contains(-3));
+ EXPECT_FALSE(intArrayView.limit(0).contains(3));
+}
+
TEST(IntArrayViewTest, TestLimit) {
const std::vector<int> intVector = {3, 2, 1, 0, -1, -2};
IntArrayView intArrayView(intVector);
@@ -111,5 +124,25 @@ TEST(IntArrayViewTest, TestCopyToArray) {
EXPECT_EQ(70, buffer[6]);
}
+TEST(IntArrayViewTest, TestFirstOrDefault) {
+ const std::vector<int> intVector = {3, 2, 1, 0, -1, -2};
+ IntArrayView intArrayView(intVector);
+
+ EXPECT_EQ(3, intArrayView.firstOrDefault(10));
+ EXPECT_EQ(10, intArrayView.limit(0).firstOrDefault(10));
+ EXPECT_EQ(-10, intArrayView.limit(0).firstOrDefault(-10));
+ EXPECT_EQ(10, intArrayView.skip(6).firstOrDefault(10));
+}
+
+TEST(IntArrayViewTest, TestLastOrDefault) {
+ const std::vector<int> intVector = {3, 2, 1, 0, -1, -2};
+ IntArrayView intArrayView(intVector);
+
+ EXPECT_EQ(-2, intArrayView.lastOrDefault(10));
+ EXPECT_EQ(10, intArrayView.limit(0).lastOrDefault(10));
+ EXPECT_EQ(-10, intArrayView.limit(0).lastOrDefault(-10));
+ EXPECT_EQ(10, intArrayView.skip(6).lastOrDefault(10));
+}
+
} // namespace
} // namespace latinime
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 4ca846be1..8a628cdac 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.inputmethod.latin.tests">
- <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19" />
+ <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
index 570865738..b64ab8c80 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutSetTestsBase.java
@@ -51,7 +51,7 @@ public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase {
protected void setUp() throws Exception {
super.setUp();
final KeyboardTheme keyboardTheme = KeyboardTheme.searchKeyboardThemeById(
- getKeyboardThemeForTests());
+ getKeyboardThemeForTests(), KeyboardTheme.KEYBOARD_THEMES);
setContext(new ContextThemeWrapper(getContext(), keyboardTheme.mStyleId));
KeyboardLayoutSet.onKeyboardThemeChanged();
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
index c20954f81..34cf4072f 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
@@ -28,6 +28,8 @@ import android.preference.PreferenceManager;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
+import java.util.Arrays;
+
@SmallTest
public class KeyboardThemeTests extends AndroidTestCase {
private SharedPreferences mPrefs;
@@ -77,7 +79,9 @@ public class KeyboardThemeTests extends AndroidTestCase {
}
private void assertKeyboardTheme(final int sdkVersion, final int expectedThemeId) {
- assertEquals(expectedThemeId, KeyboardTheme.getKeyboardTheme(mPrefs, sdkVersion).mThemeId);
+ final KeyboardTheme actualTheme = KeyboardTheme.getKeyboardTheme(
+ mPrefs, sdkVersion, KeyboardTheme.KEYBOARD_THEMES);
+ assertEquals(expectedThemeId, actualTheme.mThemeId);
}
/*
@@ -139,8 +143,8 @@ public class KeyboardThemeTests extends AndroidTestCase {
final String oldPrefKey = KeyboardTheme.KLP_KEYBOARD_THEME_KEY;
setKeyboardThemePreference(oldPrefKey, previousThemeId);
- final KeyboardTheme defaultTheme =
- KeyboardTheme.getDefaultKeyboardTheme(mPrefs, sdkVersion);
+ final KeyboardTheme defaultTheme = KeyboardTheme.getDefaultKeyboardTheme(
+ mPrefs, sdkVersion, KeyboardTheme.KEYBOARD_THEMES);
assertNotNull(defaultTheme);
assertEquals(expectedThemeId, defaultTheme.mThemeId);
@@ -194,7 +198,8 @@ public class KeyboardThemeTests extends AndroidTestCase {
// Clean up new keyboard theme preference to simulate "upgrade to LXX keyboard".
setKeyboardThemePreference(KeyboardTheme.LXX_KEYBOARD_THEME_KEY, THEME_ID_NULL);
- final KeyboardTheme theme = KeyboardTheme.getKeyboardTheme(mPrefs, sdkVersion);
+ final KeyboardTheme theme = KeyboardTheme.getKeyboardTheme(
+ mPrefs, sdkVersion, KeyboardTheme.KEYBOARD_THEMES);
assertNotNull(theme);
assertEquals(expectedThemeId, theme.mThemeId);
@@ -341,4 +346,60 @@ public class KeyboardThemeTests extends AndroidTestCase {
assertUpgradePlatformFromTo(
oldSdkVersion, newSdkVersion, THEME_ID_ILLEGAL, THEME_ID_LXX_LIGHT);
}
+
+ /*
+ * Test for missing selected theme.
+ */
+ private static KeyboardTheme[] LIMITED_THEMES = {
+ KeyboardTheme.searchKeyboardThemeById(THEME_ID_ICS, KeyboardTheme.KEYBOARD_THEMES),
+ KeyboardTheme.searchKeyboardThemeById(THEME_ID_KLP, KeyboardTheme.KEYBOARD_THEMES)
+ };
+ static {
+ Arrays.sort(LIMITED_THEMES);
+ }
+
+ public void testMissingSelectedThemeIcs() {
+ // Clean up preferences.
+ setKeyboardThemePreference(KeyboardTheme.KLP_KEYBOARD_THEME_KEY, THEME_ID_NULL);
+ setKeyboardThemePreference(KeyboardTheme.LXX_KEYBOARD_THEME_KEY, THEME_ID_NULL);
+
+ final int sdkVersion = VERSION_CODES.ICE_CREAM_SANDWICH;
+ final String oldPrefKey = KeyboardTheme.getPreferenceKey(sdkVersion);
+ setKeyboardThemePreference(oldPrefKey, THEME_ID_LXX_LIGHT);
+
+ final KeyboardTheme actualTheme = KeyboardTheme.getKeyboardTheme(
+ mPrefs, sdkVersion, LIMITED_THEMES);
+ // LXX_LIGHT is missing, fall-back to KLP.
+ assertEquals(THEME_ID_KLP, actualTheme.mThemeId);
+ }
+
+ public void testMissingSelectedThemeKlp() {
+ // Clean up preferences.
+ setKeyboardThemePreference(KeyboardTheme.KLP_KEYBOARD_THEME_KEY, THEME_ID_NULL);
+ setKeyboardThemePreference(KeyboardTheme.LXX_KEYBOARD_THEME_KEY, THEME_ID_NULL);
+
+ final int sdkVersion = VERSION_CODES.KITKAT;
+ final String oldPrefKey = KeyboardTheme.getPreferenceKey(sdkVersion);
+ setKeyboardThemePreference(oldPrefKey, THEME_ID_LXX_LIGHT);
+
+ final KeyboardTheme actualTheme = KeyboardTheme.getKeyboardTheme(
+ mPrefs, sdkVersion, LIMITED_THEMES);
+ // LXX_LIGHT is missing, fall-back to KLP.
+ assertEquals(THEME_ID_KLP, actualTheme.mThemeId);
+ }
+
+ public void testMissingSelectedThemeLxx() {
+ // Clean up preferences.
+ setKeyboardThemePreference(KeyboardTheme.KLP_KEYBOARD_THEME_KEY, THEME_ID_NULL);
+ setKeyboardThemePreference(KeyboardTheme.LXX_KEYBOARD_THEME_KEY, THEME_ID_NULL);
+
+ final int sdkVersion = VERSION_CODES_LXX;
+ final String oldPrefKey = KeyboardTheme.getPreferenceKey(sdkVersion);
+ setKeyboardThemePreference(oldPrefKey, THEME_ID_LXX_DARK);
+
+ final KeyboardTheme actualTheme = KeyboardTheme.getKeyboardTheme(
+ mPrefs, sdkVersion, LIMITED_THEMES);
+ // LXX_DARK is missing, fall-back to KLP.
+ assertEquals(THEME_ID_KLP, actualTheme.mThemeId);
+ }
}
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index d7a649a5b..6860bea45 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -183,6 +183,9 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
| InputType.TYPE_TEXT_FLAG_MULTI_LINE;
mEditText.setInputType(inputType);
mEditText.setEnabled(true);
+ if (null == Looper.myLooper()) {
+ Looper.prepare();
+ }
setupService();
mLatinIME = getService();
setDebugMode(true);
diff --git a/tests/src/com/android/inputmethod/latin/utils/DistracterFilterTest.java b/tests/src/com/android/inputmethod/latin/utils/DistracterFilterTest.java
index 5fbd36ac7..6ed912088 100644
--- a/tests/src/com/android/inputmethod/latin/utils/DistracterFilterTest.java
+++ b/tests/src/com/android/inputmethod/latin/utils/DistracterFilterTest.java
@@ -57,7 +57,7 @@ public class DistracterFilterTest extends AndroidTestCase {
mDistracterFilter.close();
}
- public void testIsDistractorToWordsInDictionaries() {
+ public void testIsDistracterToWordsInDictionaries() {
final PrevWordsInfo EMPTY_PREV_WORDS_INFO = PrevWordsInfo.EMPTY_PREV_WORDS_INFO;
final Locale localeEnUs = new Locale("en", "US");