aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/accounts/AccountStateChangedListener.java66
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/accounts/LoginAccountUtils.java13
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java2
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java13
-rw-r--r--java-overridable/src/com/android/inputmethod/latin/sync/BeanstalkManager.java55
-rw-r--r--java/res/drawable-hdpi/ic_add_circle_white_24dp.png (renamed from java/res/drawable-hdpi/ic_add_circle_wht_24dp.png)bin436 -> 436 bytes
-rw-r--r--java/res/drawable-mdpi/ic_add_circle_white_24dp.png (renamed from java/res/drawable-mdpi/ic_add_circle_wht_24dp.png)bin305 -> 305 bytes
-rw-r--r--java/res/drawable-xhdpi/ic_add_circle_white_24dp.png (renamed from java/res/drawable-xhdpi/ic_add_circle_wht_24dp.png)bin466 -> 466 bytes
-rw-r--r--java/res/drawable-xxhdpi/ic_add_circle_white_24dp.png (renamed from java/res/drawable-xxhdpi/ic_add_circle_wht_24dp.png)bin684 -> 684 bytes
-rw-r--r--java/res/layout/input_view.xml3
-rw-r--r--java/res/menu/add_style.xml4
-rw-r--r--java/res/values-af/strings.xml1
-rw-r--r--java/res/values-am/strings.xml1
-rw-r--r--java/res/values-ar/strings.xml1
-rw-r--r--java/res/values-az-rAZ/strings.xml1
-rw-r--r--java/res/values-bg/strings.xml1
-rw-r--r--java/res/values-ca/strings.xml1
-rw-r--r--java/res/values-cs/strings.xml1
-rw-r--r--java/res/values-da/strings.xml1
-rw-r--r--java/res/values-de/strings.xml1
-rw-r--r--java/res/values-el/strings.xml1
-rw-r--r--java/res/values-en-rGB/strings.xml1
-rw-r--r--java/res/values-en-rIN/strings.xml1
-rw-r--r--java/res/values-es-rUS/strings.xml1
-rw-r--r--java/res/values-es/strings.xml1
-rw-r--r--java/res/values-et-rEE/strings.xml1
-rw-r--r--java/res/values-fa/strings.xml1
-rw-r--r--java/res/values-fi/strings.xml1
-rw-r--r--java/res/values-fr-rCA/strings.xml1
-rw-r--r--java/res/values-fr/strings.xml1
-rw-r--r--java/res/values-hi/strings.xml1
-rw-r--r--java/res/values-hr/strings.xml1
-rw-r--r--java/res/values-hu/strings.xml1
-rw-r--r--java/res/values-hy-rAM/strings.xml1
-rw-r--r--java/res/values-in/strings.xml1
-rw-r--r--java/res/values-it/strings.xml1
-rw-r--r--java/res/values-iw/strings.xml1
-rw-r--r--java/res/values-ja/strings.xml1
-rw-r--r--java/res/values-ka-rGE/strings.xml1
-rw-r--r--java/res/values-km-rKH/strings.xml1
-rw-r--r--java/res/values-ko/strings.xml1
-rw-r--r--java/res/values-lo-rLA/strings.xml1
-rw-r--r--java/res/values-lt/strings.xml1
-rw-r--r--java/res/values-lv/strings.xml1
-rw-r--r--java/res/values-mn-rMN/strings.xml1
-rw-r--r--java/res/values-ms-rMY/strings.xml1
-rw-r--r--java/res/values-nb/strings.xml1
-rw-r--r--java/res/values-ne-rNP/strings.xml1
-rw-r--r--java/res/values-nl/strings.xml1
-rw-r--r--java/res/values-pl/strings.xml1
-rw-r--r--java/res/values-pt-rPT/strings.xml1
-rw-r--r--java/res/values-pt/strings.xml1
-rw-r--r--java/res/values-ro/strings.xml1
-rw-r--r--java/res/values-ru/strings.xml1
-rw-r--r--java/res/values-sk/strings.xml1
-rw-r--r--java/res/values-sl/strings.xml1
-rw-r--r--java/res/values-sr/strings.xml1
-rw-r--r--java/res/values-sv/strings.xml1
-rw-r--r--java/res/values-sw/strings.xml1
-rw-r--r--java/res/values-th/strings.xml1
-rw-r--r--java/res/values-tl/strings.xml1
-rw-r--r--java/res/values-tr/strings.xml1
-rw-r--r--java/res/values-uk/strings.xml1
-rw-r--r--java/res/values-v21/themes-lxx.xml28
-rw-r--r--java/res/values-vi/strings.xml1
-rw-r--r--java/res/values-zh-rCN/strings.xml1
-rw-r--r--java/res/values-zh-rHK/strings.xml1
-rw-r--r--java/res/values-zh-rTW/strings.xml1
-rw-r--r--java/res/values-zu/strings.xml1
-rw-r--r--java/res/values/attrs.xml2
-rw-r--r--java/res/values/donottranslate-debug-settings.xml2
-rw-r--r--java/res/values/strings.xml10
-rw-r--r--java/res/values/themes-common.xml1
-rw-r--r--java/res/values/themes-holo.xml4
-rw-r--r--java/res/values/themes-ics.xml1
-rw-r--r--java/res/values/themes-klp.xml1
-rw-r--r--java/res/values/themes-lxx-dark.xml1
-rw-r--r--java/res/values/themes-lxx-light.xml1
-rw-r--r--java/res/values/themes-lxx.xml4
-rw-r--r--java/res/xml/prefs_screen_accounts.xml13
-rw-r--r--java/res/xml/prefs_screen_advanced.xml6
-rw-r--r--java/res/xml/prefs_screen_debug.xml6
-rw-r--r--java/res/xml/rowkeys_telugu2.xml4
-rw-r--r--java/res/xml/rowkeys_telugu3.xml24
-rw-r--r--java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java186
-rw-r--r--java/src/com/android/inputmethod/compat/ViewCompatUtils.java7
-rw-r--r--java/src/com/android/inputmethod/compat/ViewOutlineProviderCompatUtils.java42
-rw-r--r--java/src/com/android/inputmethod/compat/ViewOutlineProviderCompatUtilsLXX.java72
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java86
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardTheme.java18
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java12
-rw-r--r--java/src/com/android/inputmethod/keyboard/TextDecorator.java10
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java4
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java4
-rw-r--r--java/src/com/android/inputmethod/latin/BackupAgent.java30
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java32
-rw-r--r--java/src/com/android/inputmethod/latin/Dictionary.java16
-rw-r--r--java/src/com/android/inputmethod/latin/DictionaryFacilitator.java6
-rw-r--r--java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java7
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java48
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputConnection.java3
-rw-r--r--java/src/com/android/inputmethod/latin/RichInputMethodManager.java20
-rw-r--r--java/src/com/android/inputmethod/latin/SubtypeSwitcher.java22
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java60
-rw-r--r--java/src/com/android/inputmethod/latin/SuggestedWords.java25
-rw-r--r--java/src/com/android/inputmethod/latin/accounts/AccountsChangedReceiver.java47
-rw-r--r--java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java44
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java5
-rw-r--r--java/src/com/android/inputmethod/latin/makedict/WordProperty.java17
-rw-r--r--java/src/com/android/inputmethod/latin/network/AuthException.java35
-rw-r--r--java/src/com/android/inputmethod/latin/network/BlockingHttpClient.java51
-rw-r--r--java/src/com/android/inputmethod/latin/network/HttpException.java46
-rw-r--r--java/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilder.java34
-rw-r--r--java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java153
-rw-r--r--java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java40
-rw-r--r--java/src/com/android/inputmethod/latin/settings/CustomInputStylePreference.java358
-rw-r--r--java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java449
-rw-r--r--java/src/com/android/inputmethod/latin/settings/DebugSettings.java25
-rw-r--r--java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java40
-rw-r--r--java/src/com/android/inputmethod/latin/settings/LocalSettingsConstants.java60
-rw-r--r--java/src/com/android/inputmethod/latin/settings/MultiLingualSettingsFragment.java1
-rw-r--r--java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java9
-rw-r--r--java/src/com/android/inputmethod/latin/settings/Settings.java8
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsFragment.java1
-rw-r--r--java/src/com/android/inputmethod/latin/settings/SettingsValues.java4
-rw-r--r--java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java4
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java36
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java6
-rw-r--r--java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java2
-rw-r--r--java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java34
-rw-r--r--java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java9
-rw-r--r--java/src/com/android/inputmethod/latin/utils/CursorAnchorInfoUtils.java31
-rw-r--r--java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java21
-rw-r--r--java/src/com/android/inputmethod/latin/utils/LeakGuardHandlerWrapper.java11
-rw-r--r--native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp53
-rw-r--r--native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.cpp17
-rw-r--r--native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp10
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary.cpp42
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary.h18
-rw-r--r--native/jni/src/suggest/core/dictionary/dictionary_utils.cpp8
-rw-r--r--native/jni/src/suggest/core/dictionary/property/historical_info.h10
-rw-r--r--native/jni/src/suggest/core/dictionary/property/ngram_property.h10
-rw-r--r--native/jni/src/suggest/core/dictionary/property/unigram_property.h20
-rw-r--r--native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h8
-rw-r--r--native/jni/src/suggest/core/policy/traversal.h2
-rw-r--r--native/jni/src/suggest/core/policy/weighting.cpp12
-rw-r--r--native/jni/src/suggest/core/session/dic_traverse_session.cpp6
-rw-r--r--native/jni/src/suggest/core/session/dic_traverse_session.h4
-rw-r--r--native/jni/src/suggest/core/session/ngram_context.h (renamed from native/jni/src/suggest/core/session/prev_words_info.h)31
-rw-r--r--native/jni/src/suggest/core/suggest.cpp8
-rw-r--r--native/jni/src/suggest/core/suggest_options.h9
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp8
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h2
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp2
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.cpp53
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h8
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.cpp2
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/patricia_trie_policy.h9
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.cpp2
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v2/ver2_patricia_trie_node_reader.h4
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.cpp125
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/language_model_dict_content.h22
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/content/probability_entry.h10
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.cpp33
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h13
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.cpp86
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h13
-rw-r--r--native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp10
-rw-r--r--native/jni/src/suggest/policyimpl/typing/scoring_params.cpp6
-rw-r--r--native/jni/src/suggest/policyimpl/typing/scoring_params.h4
-rw-r--r--native/jni/src/suggest/policyimpl/typing/typing_traversal.h26
-rw-r--r--native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp5
-rw-r--r--native/jni/src/utils/jni_data_utils.h6
-rw-r--r--tests/AndroidManifest.xml3
-rw-r--r--tests/res/drawable-hdpi/ic_app.pngbin0 -> 635 bytes
-rw-r--r--tests/res/values/strings.xml22
-rw-r--r--tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java26
-rw-r--r--tests/src/com/android/inputmethod/keyboard/layout/Telugu.java23
-rw-r--r--tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java99
-rw-r--r--tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java32
-rw-r--r--tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java20
-rw-r--r--tests/src/com/android/inputmethod/latin/InputLogicTests.java47
-rw-r--r--tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java4
-rw-r--r--tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java4
-rw-r--r--tests/src/com/android/inputmethod/latin/InputTestsBase.java59
-rw-r--r--tests/src/com/android/inputmethod/latin/PunctuationTests.java2
-rw-r--r--tests/src/com/android/inputmethod/latin/ShiftModeTests.java2
-rw-r--r--tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java45
-rw-r--r--tests/src/com/android/inputmethod/latin/accounts/AccountsChangedReceiverTests.java11
-rw-r--r--tests/src/com/android/inputmethod/latin/network/BlockingHttpClientTests.java82
-rw-r--r--tests/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilderTests.java9
-rw-r--r--tests/src/com/android/inputmethod/latin/utils/EditDistanceTests.java99
192 files changed, 2382 insertions, 1536 deletions
diff --git a/java-overridable/src/com/android/inputmethod/latin/accounts/AccountStateChangedListener.java b/java-overridable/src/com/android/inputmethod/latin/accounts/AccountStateChangedListener.java
new file mode 100644
index 000000000..c0a599c6e
--- /dev/null
+++ b/java-overridable/src/com/android/inputmethod/latin/accounts/AccountStateChangedListener.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.accounts;
+
+import android.support.annotation.NonNull;
+
+import javax.annotation.Nullable;
+
+/**
+ * Handles changes to account used to sign in to the keyboard.
+ * e.g. account switching/sign-in/sign-out from the keyboard
+ * user toggling the sync preference.
+ */
+public class AccountStateChangedListener {
+
+ /**
+ * Called when the current account being used in keyboard is signed out.
+ *
+ * @param oldAccount the account that was signed out of.
+ */
+ public static void onAccountSignedOut(@NonNull String oldAccount) {
+ }
+
+ /**
+ * Called when the user signs-in to the keyboard.
+ * This may be called when the user switches accounts to sign in with a different account.
+ *
+ * @param oldAccount the previous account that was being used for sign-in.
+ * May be null for a fresh sign-in.
+ * @param newAccount the account being used for sign-in.
+ */
+ public static void onAccountSignedIn(@Nullable String oldAccount, @NonNull String newAccount) {
+ }
+
+ /**
+ * Called when the user toggles the sync preference.
+ *
+ * @param account the account being used for sync.
+ * @param syncEnabled indicates whether sync has been enabled or not.
+ */
+ public static void onSyncPreferenceChanged(@Nullable String account, boolean syncEnabled) {
+ }
+
+ /**
+ * Forces an immediate sync to happen.
+ * This should only be used for debugging purposes.
+ *
+ * @param account the account to use for sync.
+ */
+ public static void forceSync(@Nullable String account) {
+ }
+}
diff --git a/java-overridable/src/com/android/inputmethod/latin/accounts/LoginAccountUtils.java b/java-overridable/src/com/android/inputmethod/latin/accounts/LoginAccountUtils.java
index 70f152acb..e07a9f358 100644
--- a/java-overridable/src/com/android/inputmethod/latin/accounts/LoginAccountUtils.java
+++ b/java-overridable/src/com/android/inputmethod/latin/accounts/LoginAccountUtils.java
@@ -16,16 +16,20 @@
package com.android.inputmethod.latin.accounts;
-import android.accounts.Account;
import android.content.Context;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
/**
* Utility class for retrieving accounts that may be used for login.
*/
public class LoginAccountUtils {
+ /**
+ * This defines the type of account this class deals with.
+ * This account type is used when listing the accounts available on the device for login.
+ */
+ public static final String ACCOUNT_TYPE = "";
+
private LoginAccountUtils() {
// This utility class is not publicly instantiable.
}
@@ -39,9 +43,4 @@ public class LoginAccountUtils {
public static String[] getAccountsForLogin(final Context context) {
return new String[0];
}
-
- @Nullable
- public static Account getCurrentAccount(final Context context) {
- return null;
- }
}
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 10fc612e7..99b958952 100644
--- a/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
+++ b/java-overridable/src/com/android/inputmethod/latin/define/ProductionFlags.java
@@ -46,5 +46,5 @@ public final class ProductionFlags {
/**
* When {@code true}, personal dictionary sync feature is ready to be enabled.
*/
- public static final boolean ENABLE_PERSONAL_DICTIONARY_SYNC = false;
+ public static final boolean ENABLE_PERSONAL_DICTIONARY_SYNC = ENABLE_ACCOUNT_SIGN_IN && false;
}
diff --git a/java-overridable/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java b/java-overridable/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java
index 1c02d7d63..1dfaf259e 100644
--- a/java-overridable/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java
+++ b/java-overridable/src/com/android/inputmethod/latin/settings/AdditionalFeaturesSettingUtils.java
@@ -19,6 +19,12 @@ package com.android.inputmethod.latin.settings;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceFragment;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.inputmethod.latin.RichInputMethodSubtype;
+import com.android.inputmethod.latin.RichInputMethodManager;
+
+import javax.annotation.Nonnull;
/**
* Utility class for managing additional features settings.
@@ -39,4 +45,11 @@ public class AdditionalFeaturesSettingUtils {
final SharedPreferences prefs, final int[] additionalFeaturesPreferences) {
// do nothing.
}
+
+ public static RichInputMethodSubtype createRichInputMethodSubtype(
+ @Nonnull final RichInputMethodManager imm,
+ @Nonnull final InputMethodSubtype subtype,
+ final Context context) {
+ return new RichInputMethodSubtype(subtype);
+ }
}
diff --git a/java-overridable/src/com/android/inputmethod/latin/sync/BeanstalkManager.java b/java-overridable/src/com/android/inputmethod/latin/sync/BeanstalkManager.java
deleted file mode 100644
index 2242d9244..000000000
--- a/java-overridable/src/com/android/inputmethod/latin/sync/BeanstalkManager.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.latin.sync;
-
-import android.content.Context;
-
-import javax.annotation.Nonnull;
-import javax.annotation.concurrent.GuardedBy;
-
-public class BeanstalkManager {
- private static final Object sLock = new Object();
-
- @GuardedBy("sLock")
- private static BeanstalkManager sInstance;
-
- /**
- * @return the singleton instance of {@link BeanstalkManager}.
- */
- @Nonnull
- public static BeanstalkManager getInstance(Context context) {
- synchronized(sLock) {
- if (sInstance == null) {
- sInstance = new BeanstalkManager(context.getApplicationContext());
- }
- }
- return sInstance;
- }
-
- private BeanstalkManager(final Context context) {
- // Intentional private constructor for singleton.
- }
-
- public void onCreate() {
- }
-
- public void requestSync() {
- }
-
- public void onDestroy() {
- }
-} \ No newline at end of file
diff --git a/java/res/drawable-hdpi/ic_add_circle_wht_24dp.png b/java/res/drawable-hdpi/ic_add_circle_white_24dp.png
index 314c52137..314c52137 100644
--- a/java/res/drawable-hdpi/ic_add_circle_wht_24dp.png
+++ b/java/res/drawable-hdpi/ic_add_circle_white_24dp.png
Binary files differ
diff --git a/java/res/drawable-mdpi/ic_add_circle_wht_24dp.png b/java/res/drawable-mdpi/ic_add_circle_white_24dp.png
index 11363b173..11363b173 100644
--- a/java/res/drawable-mdpi/ic_add_circle_wht_24dp.png
+++ b/java/res/drawable-mdpi/ic_add_circle_white_24dp.png
Binary files differ
diff --git a/java/res/drawable-xhdpi/ic_add_circle_wht_24dp.png b/java/res/drawable-xhdpi/ic_add_circle_white_24dp.png
index 32a5b05ba..32a5b05ba 100644
--- a/java/res/drawable-xhdpi/ic_add_circle_wht_24dp.png
+++ b/java/res/drawable-xhdpi/ic_add_circle_white_24dp.png
Binary files differ
diff --git a/java/res/drawable-xxhdpi/ic_add_circle_wht_24dp.png b/java/res/drawable-xxhdpi/ic_add_circle_white_24dp.png
index a22c463f9..a22c463f9 100644
--- a/java/res/drawable-xxhdpi/ic_add_circle_wht_24dp.png
+++ b/java/res/drawable-xxhdpi/ic_add_circle_white_24dp.png
Binary files differ
diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml
index 46551f63f..ae3c19db5 100644
--- a/java/res/layout/input_view.xml
+++ b/java/res/layout/input_view.xml
@@ -21,7 +21,8 @@
<com.android.inputmethod.latin.InputView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content">
+ android:layout_height="wrap_content"
+ style="?attr/inputViewStyle">
<include
android:id="@+id/main_keyboard_frame"
layout="@layout/main_keyboard_frame" />
diff --git a/java/res/menu/add_style.xml b/java/res/menu/add_style.xml
index d1cab4bb5..befa3f2aa 100644
--- a/java/res/menu/add_style.xml
+++ b/java/res/menu/add_style.xml
@@ -20,7 +20,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_add_style"
- android:icon="@drawable/ic_add_circle_wht_24dp"
+ android:icon="@drawable/ic_add_circle_white_24dp"
android:title="@string/add_style"
android:showAsAction="always" />
-</menu> \ No newline at end of file
+</menu>
diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml
index 5f3a0676c..cbdf434fa 100644
--- a/java/res/values-af/strings.xml
+++ b/java/res/values-af/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Dieselfde invoerstyl bestaan ​​reeds: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Sleuteldruk se vibrasie-tydsduur"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Sleuteldruk se klankvolume"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Vertraging van sleutellangdruk"</string>
<string name="button_default" msgid="3988017840431881491">"Verstek"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Welkom by <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"met Gebaar-tik"</string>
diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml
index 4e9c4ca7a..1ac1f8cbf 100644
--- a/java/res/values-am/strings.xml
+++ b/java/res/values-am/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"ተመሳሳዩ የግብዓት ቅጥ አስቀድሞ አለ፦ <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"የቁልፍ ጭነት ንዝረት ርዝመት"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"የቁልፍ ጭነት ድምጽ መጠን"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"የሰሌዳ ቁልፍ ጠቅታ በመጫን መዘግየት"</string>
<string name="button_default" msgid="3988017840431881491">"ነባሪ"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"እንኳን ወደ <xliff:g id="APPLICATION_NAME">%s</xliff:g> በደህና መጡ"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"በጣት ምልክት መተየብ"</string>
diff --git a/java/res/values-ar/strings.xml b/java/res/values-ar/strings.xml
index b5e9c5006..dbab0efe8 100644
--- a/java/res/values-ar/strings.xml
+++ b/java/res/values-ar/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"نمط الإدخال ذاته موجود من قبل: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"مدة اهتزاز الضغط على المفاتيح"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"مستوى صوت الضغط على المفاتيح"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"تأخير الضغط الطويل للمفاتيح"</string>
<string name="button_default" msgid="3988017840431881491">"الافتراضية"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"مرحبا بكم في <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"مع الكتابة بالإشارة"</string>
diff --git a/java/res/values-az-rAZ/strings.xml b/java/res/values-az-rAZ/strings.xml
index 238ed0f53..463faf505 100644
--- a/java/res/values-az-rAZ/strings.xml
+++ b/java/res/values-az-rAZ/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Eyni daxiletmə üslubu artıq mövcuddur: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Vibrasiyalı klikləmə müddəti"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Səsli klikləmə səsi"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Klavişi uzun müddət basmada gecikmə"</string>
<string name="button_default" msgid="3988017840431881491">"Defolt"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> təbiqinə xoş gəlmisiniz"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"Jest Yazısı ilə"</string>
diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml
index ed40074b1..21df08466 100644
--- a/java/res/values-bg/strings.xml
+++ b/java/res/values-bg/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Същият стил на въвеждане вече съществува: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Продълж. на вибриране при натискане"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Сила на звука при натиск. на клавиш"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Забавяне при продълж. натискане"</string>
<string name="button_default" msgid="3988017840431881491">"Стандартни"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Добре дошли в/ъв <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"с въвеждане чрез жест"</string>
diff --git a/java/res/values-ca/strings.xml b/java/res/values-ca/strings.xml
index e39247f21..da93a58cf 100644
--- a/java/res/values-ca/strings.xml
+++ b/java/res/values-ca/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Ja existeix aquest estil d\'entrada: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Durada vibració en prémer"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Volum del so en prémer tecles"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Retard en mantenir premut"</string>
<string name="button_default" msgid="3988017840431881491">"Predeterminat"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Et donem la benvinguda a <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"amb Escriptura gestual"</string>
diff --git a/java/res/values-cs/strings.xml b/java/res/values-cs/strings.xml
index f52755712..996bc7012 100644
--- a/java/res/values-cs/strings.xml
+++ b/java/res/values-cs/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Tento styl zadávání již existuje: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Délka vibrace u stisku klávesy"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Hlasitost stisknutí klávesy"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Prodleva dlouhého stisknutí"</string>
<string name="button_default" msgid="3988017840431881491">"Výchozí"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Vítá vás <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"s psaním gesty"</string>
diff --git a/java/res/values-da/strings.xml b/java/res/values-da/strings.xml
index 240250f56..fe1820b96 100644
--- a/java/res/values-da/strings.xml
+++ b/java/res/values-da/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Denne inputstil findes allerede: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Vibrationstid ved tastetryk"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Lydstyrke ved tastetryk"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Forsinket langt tastetryk"</string>
<string name="button_default" msgid="3988017840431881491">"Standard"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Velkommen til <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"med glidende indtastning"</string>
diff --git a/java/res/values-de/strings.xml b/java/res/values-de/strings.xml
index b59c5069c..13c012565 100644
--- a/java/res/values-de/strings.xml
+++ b/java/res/values-de/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Der gleiche Eingabestil ist bereits vorhanden: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Vibrationsdauer bei Tastendruck"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Tonlautstärke bei Tastendruck"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Verzögerung für langes Drücken"</string>
<string name="button_default" msgid="3988017840431881491">"Standard"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Willkommen bei <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"mit Bewegungseingabe"</string>
diff --git a/java/res/values-el/strings.xml b/java/res/values-el/strings.xml
index e519e4379..f4f58e115 100644
--- a/java/res/values-el/strings.xml
+++ b/java/res/values-el/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Το ίδιο στυλ εισόδου υπάρχει ήδη: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Διάρκεια δόνησης πατήμ. πλήκτ."</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Ένταση ήχου πατήματος πλήκτρου"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Καθυστέρηση παρατεταμένου πατήματος πλήκτρου"</string>
<string name="button_default" msgid="3988017840431881491">"Προεπιλογή"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Καλώς ορίσατε στο <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"με Πληκτρολόγηση με κίνηση"</string>
diff --git a/java/res/values-en-rGB/strings.xml b/java/res/values-en-rGB/strings.xml
index f31b0713c..249f8f30f 100644
--- a/java/res/values-en-rGB/strings.xml
+++ b/java/res/values-en-rGB/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"The same input style already exists: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Keypress vibration duration"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Keypress sound volume"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Key long press delay"</string>
<string name="button_default" msgid="3988017840431881491">"Default"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Welcome to <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"with Gesture Typing"</string>
diff --git a/java/res/values-en-rIN/strings.xml b/java/res/values-en-rIN/strings.xml
index f31b0713c..249f8f30f 100644
--- a/java/res/values-en-rIN/strings.xml
+++ b/java/res/values-en-rIN/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"The same input style already exists: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Keypress vibration duration"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Keypress sound volume"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Key long press delay"</string>
<string name="button_default" msgid="3988017840431881491">"Default"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Welcome to <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"with Gesture Typing"</string>
diff --git a/java/res/values-es-rUS/strings.xml b/java/res/values-es-rUS/strings.xml
index 79b0f922d..f0aebbeb8 100644
--- a/java/res/values-es-rUS/strings.xml
+++ b/java/res/values-es-rUS/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Ya existe el estilo de entrada <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>."</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Durac. vibrac. al presionar"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Vol. sonido al presionar tecla"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Demora de presión prolongada"</string>
<string name="button_default" msgid="3988017840431881491">"Predeterminado"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Te damos la bienvenida a <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"con escritura gestual"</string>
diff --git a/java/res/values-es/strings.xml b/java/res/values-es/strings.xml
index d099e4f4b..a470bc9c5 100644
--- a/java/res/values-es/strings.xml
+++ b/java/res/values-es/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Ya existe el estilo de entrada <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>."</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Duración de vibración al pulsar"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Volumen sonido al pulsar tecla"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Retraso de pulsación prolongada"</string>
<string name="button_default" msgid="3988017840431881491">"Predeterminado"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Te damos la bienvenida a <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"con escritura gestual"</string>
diff --git a/java/res/values-et-rEE/strings.xml b/java/res/values-et-rEE/strings.xml
index e7939e20a..ffbaba047 100644
--- a/java/res/values-et-rEE/strings.xml
+++ b/java/res/values-et-rEE/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Sama sisendstiil on juba olemas: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Klahvivajutuse vibreerimise kestus"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Klahvivajutuse helitugevus"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Pika klahvivajutuse viide"</string>
<string name="button_default" msgid="3988017840431881491">"Vaikeväärtus"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Tere tulemast rakendusse <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"joonistusega sisestamisega"</string>
diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml
index 336c8ed15..31627844c 100644
--- a/java/res/values-fa/strings.xml
+++ b/java/res/values-fa/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"سبک ورودی مشابهی در حال حاضر وجود دارد: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"طول مدت لرزش در اثر فشردن کلید"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"میزان صدای فشردن کلید"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"تأخیر فشار طولانی کلید"</string>
<string name="button_default" msgid="3988017840431881491">"پیش‌فرض"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"به <xliff:g id="APPLICATION_NAME">%s</xliff:g> خوش آمدید"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"با ورودی اشاره‌ای"</string>
diff --git a/java/res/values-fi/strings.xml b/java/res/values-fi/strings.xml
index d1bb592e4..3739cdf79 100644
--- a/java/res/values-fi/strings.xml
+++ b/java/res/values-fi/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Syöttötyyli on jo olemassa: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Painalluksen värinän kesto"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Näppäinpainalluksen äänenvoim."</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Pitkän painalluksen viive"</string>
<string name="button_default" msgid="3988017840431881491">"Oletusarvot"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Tervetuloa käyttämään sovellusta <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"ja piirtokirjoitus"</string>
diff --git a/java/res/values-fr-rCA/strings.xml b/java/res/values-fr-rCA/strings.xml
index 98796524b..e5492a1a4 100644
--- a/java/res/values-fr-rCA/strings.xml
+++ b/java/res/values-fr-rCA/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Le style de saisie suivant existe déjà : <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>."</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Durée vibration press. touche"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Volume pression de touche"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Délai appui prolongé sur touche"</string>
<string name="button_default" msgid="3988017840431881491">"Par défaut"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Bienvenue dans <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"avec la saisie gestuelle"</string>
diff --git a/java/res/values-fr/strings.xml b/java/res/values-fr/strings.xml
index a93c0efe1..df6167cd1 100644
--- a/java/res/values-fr/strings.xml
+++ b/java/res/values-fr/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Le style de saisie suivant existe déjà : <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>."</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Durée vibration press. touche"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Volume son pression de touche"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Délai appui prolongé sur touche"</string>
<string name="button_default" msgid="3988017840431881491">"Par défaut"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Bienvenue dans <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"avec la saisie gestuelle"</string>
diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml
index 5f1ca5c65..3cf27b58c 100644
--- a/java/res/values-hi/strings.xml
+++ b/java/res/values-hi/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"ऐसी ही इनपुट शैली पहले से मौजूद है: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"कुंजी-स्पर्श कंपन अवधि"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"कुंजी-स्पर्श ध्वनि आवाज़"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"कुंजी को देर तक दबाने का विलंब"</string>
<string name="button_default" msgid="3988017840431881491">"सामान्य"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> में आपका स्वागत है"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"हावभाव लेखन के साथ"</string>
diff --git a/java/res/values-hr/strings.xml b/java/res/values-hr/strings.xml
index 34449c289..b13a99734 100644
--- a/java/res/values-hr/strings.xml
+++ b/java/res/values-hr/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Već postoji isti stil unosa: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Trajanje vibracije pritiska"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Glasnoća pritiska tipke"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Odgoda dugog pritiska tipke"</string>
<string name="button_default" msgid="3988017840431881491">"Zadano"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Dobro došli u aplikaciju <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"s Pisanjem kretnjama"</string>
diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml
index 72b012b12..93099fee8 100644
--- a/java/res/values-hu/strings.xml
+++ b/java/res/values-hu/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Ugyanez a bemenetstílus már létezik: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Gombnyomás rezgési időtartama"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Gombnyomás hangereje"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Hosszú nyomás késleltetése"</string>
<string name="button_default" msgid="3988017840431881491">"Alapértelmezett"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Üdvözli a(z) <xliff:g id="APPLICATION_NAME">%s</xliff:g>!"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"kézmozdulatokkal történő bevitellel"</string>
diff --git a/java/res/values-hy-rAM/strings.xml b/java/res/values-hy-rAM/strings.xml
index 488bcc659..920867df8 100644
--- a/java/res/values-hy-rAM/strings.xml
+++ b/java/res/values-hy-rAM/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Մուտքագրման այսպիսի ոճ արդեն գոյություն ունի՝ <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Սեղմման թրթռոցի տևողություն"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Սեղմման ձայնի բարձրությունը"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Ստեղնի երկար սեղմման ուշացում"</string>
<string name="button_default" msgid="3988017840431881491">"Լռելյայնը"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Բարի գալուստ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"Ժեստային մուտքագրմամբ"</string>
diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml
index 1a67c3e5f..7381cd6fe 100644
--- a/java/res/values-in/strings.xml
+++ b/java/res/values-in/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Sudah ada gaya masukan yang sama: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Durasi getar saat tekan tombol"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Volume suara saat tekan tombol"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Penundaan tekan lama tombol"</string>
<string name="button_default" msgid="3988017840431881491">"Default"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Selamat datang di <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"dengan Ketikan Isyarat"</string>
diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml
index 473d71285..5572b2cde 100644
--- a/java/res/values-it/strings.xml
+++ b/java/res/values-it/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Esiste già uno stile di inuput uguale: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Durata vibraz. pressione tasto"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Volume audio a pressione tasto"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Ritardo pressione lunga tasti"</string>
<string name="button_default" msgid="3988017840431881491">"Predefinito"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Benvenuto in <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"con la Digitazione gestuale"</string>
diff --git a/java/res/values-iw/strings.xml b/java/res/values-iw/strings.xml
index 317282deb..468f7cb9d 100644
--- a/java/res/values-iw/strings.xml
+++ b/java/res/values-iw/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"סגנון קלט זהה כבר קיים: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"משך רטט של לחיצת מקש"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"עוצמת קול של לחיצת מקש"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"השהיית לחיצה ארוכה על מקש"</string>
<string name="button_default" msgid="3988017840431881491">"ברירת מחדל"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"ברוך הבא אל <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"עם הקלדת החלקה"</string>
diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml
index d3be98be6..5ae8fcce4 100644
--- a/java/res/values-ja/strings.xml
+++ b/java/res/values-ja/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"同じ入力スタイルが既に存在します: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"キー操作バイブの振動時間"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"キー操作音の音量"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"キーの長押し時間"</string>
<string name="button_default" msgid="3988017840431881491">"デフォルト"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>へようこそ"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"新しいジェスチャー入力をお試しください"</string>
diff --git a/java/res/values-ka-rGE/strings.xml b/java/res/values-ka-rGE/strings.xml
index f614ea08a..4f221a937 100644
--- a/java/res/values-ka-rGE/strings.xml
+++ b/java/res/values-ka-rGE/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"შეყვანის იგივე სტილი უკვე არსებობს: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"კლავიშზე დაჭერის ვიბრაციის ხანგრძლივობა"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"კლავიშზე დაჭერის ხმა"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"კლავიშზე გრძელი დაჭერის დაყოვნება"</string>
<string name="button_default" msgid="3988017840431881491">"ნაგულისხმევი"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"კეთილი იყოს თქვენი მობრძანება <xliff:g id="APPLICATION_NAME">%s</xliff:g>-ში"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"ჟესტებით წერით"</string>
diff --git a/java/res/values-km-rKH/strings.xml b/java/res/values-km-rKH/strings.xml
index e9a29af5f..f1a9ecbd0 100644
--- a/java/res/values-km-rKH/strings.xml
+++ b/java/res/values-km-rKH/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"មាន​រចនាប័ទ្ម​បញ្ចូល​ដូច​គ្នា​ដូច​ហើយ៖ <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"ថិរវេលា​​ញ័រ​​ពេល​ចុច​គ្រាប់ចុច"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"កម្រិត​សំឡេង​ពេល​ចុច​គ្រាប់​ចុច"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"ពន្យារពេល​​​ចុច​គ្រាប់​ចុច​ឲ្យ​​យូរ"</string>
<string name="button_default" msgid="3988017840431881491">"លំនាំដើម"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"សូម​ស្វាគមន៍​មក​កាន់ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"ជាមួយ​​​ការ​វាយ​បញ្ចូល​ដោយ​ប្រើ​​​កាយវិការ"</string>
diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml
index a778a49b8..1c4612009 100644
--- a/java/res/values-ko/strings.xml
+++ b/java/res/values-ko/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"같은 입력 스타일이 다음과 같이 이미 존재합니다. <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"키를 누를 때 진동 시간"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"키를 누를 때 소리 볼륨"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"키 길게 누르기 지연"</string>
<string name="button_default" msgid="3988017840431881491">"기본값"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"<xliff:g id="APPLICATION_NAME">%s</xliff:g>에 오신 것을 환영합니다."</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"제스처 타이핑 사용"</string>
diff --git a/java/res/values-lo-rLA/strings.xml b/java/res/values-lo-rLA/strings.xml
index bdc99fc9f..55f97c32d 100644
--- a/java/res/values-lo-rLA/strings.xml
+++ b/java/res/values-lo-rLA/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"ຮູບແບບການປ້ອນຂໍ້ມູນທີ່ຄືກັນມີຢູ່ແລ້ວ: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"ໄລຍະເວລາຂອງການສັ່ນໃນການກົດປຸ່ມ"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"ລະດັບສຽງຂອງການກົດປຸ່ມ"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"ໄລຍະເວລາຂອງການກົດປຸ່ມ"</string>
<string name="button_default" msgid="3988017840431881491">"ຄ່າເລີ່ມຕົ້ນ"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"ຍິນ​ດີ​ຕ້ອນ​ຮັບສູ່ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"ດ້ວຍການພິມແບບ Gesture"</string>
diff --git a/java/res/values-lt/strings.xml b/java/res/values-lt/strings.xml
index 147d706bb..d1782fa7f 100644
--- a/java/res/values-lt/strings.xml
+++ b/java/res/values-lt/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Toks pat įvesties stilius jau yra: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Vibrav. paspaudus mygt. trukmė"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Garso paspaudus mygt. garsumas"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Klavišo ilgo paspaudimo delsa"</string>
<string name="button_default" msgid="3988017840431881491">"Numatytieji"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Sveiki! Tai „<xliff:g id="APPLICATION_NAME">%s</xliff:g>“"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"naudojant įvestį gestais"</string>
diff --git a/java/res/values-lv/strings.xml b/java/res/values-lv/strings.xml
index 812cb9a0d..8de28bed6 100644
--- a/java/res/values-lv/strings.xml
+++ b/java/res/values-lv/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Šāds ievades stils jau pastāv: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Taust. nosp. vibrācijas ilgums"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Taustiņu nosp. skaņas skaļums"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Taustiņa ilgās nosp. noildze"</string>
<string name="button_default" msgid="3988017840431881491">"Noklusējums"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Laipni lūdzam pakalpojumā <xliff:g id="APPLICATION_NAME">%s</xliff:g>,"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"kurā varat izmantot ievadi ar žestiem"</string>
diff --git a/java/res/values-mn-rMN/strings.xml b/java/res/values-mn-rMN/strings.xml
index e61584b7e..4b1ef6280 100644
--- a/java/res/values-mn-rMN/strings.xml
+++ b/java/res/values-mn-rMN/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Ижилхэн оруулах загвар байна: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Товч дарах чичиргээний хугацаа"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Товчны дууны хэмжээ"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Товч удаан дарах хугацааны тохиргоо"</string>
<string name="button_default" msgid="3988017840431881491">"Үндсэн"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Та <xliff:g id="APPLICATION_NAME">%s</xliff:g>-д тавтай морилно уу"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"Зангаагаар бичихээр"</string>
diff --git a/java/res/values-ms-rMY/strings.xml b/java/res/values-ms-rMY/strings.xml
index 07d86c52b..01781a47a 100644
--- a/java/res/values-ms-rMY/strings.xml
+++ b/java/res/values-ms-rMY/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"The same input style already exists: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Tempoh getaran tekan kekunci"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Kelantangan bunyi tekan kekunci"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Kelewatan tekan lama kekunci"</string>
<string name="button_default" msgid="3988017840431881491">"Lalai"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Selamat datang ke <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"dengan Taipan Gerak Isyarat"</string>
diff --git a/java/res/values-nb/strings.xml b/java/res/values-nb/strings.xml
index 268d76a25..d69e1e991 100644
--- a/java/res/values-nb/strings.xml
+++ b/java/res/values-nb/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Inndatastilen finnes allerede: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Vibrasjonstid ved tastetrykk"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Lydstyrke ved tastetrykk"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Forsinkelse lange tastetrykk"</string>
<string name="button_default" msgid="3988017840431881491">"Standard"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Velkommen til <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"med Ordføring"</string>
diff --git a/java/res/values-ne-rNP/strings.xml b/java/res/values-ne-rNP/strings.xml
index 9f486fdb4..5afe6d19e 100644
--- a/java/res/values-ne-rNP/strings.xml
+++ b/java/res/values-ne-rNP/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"यस्तो इनपुट शैली पहिले नै अवस्थित छ: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"कुञ्जी थिचाइ भाइब्रेसन अवधि"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"कुञ्जी थिचाइ आवाज भोल्युम"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"कुञ्जी लामो थिचाइ ढिलाइ"</string>
<string name="button_default" msgid="3988017840431881491">"पूर्वनिर्धारित"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"तपाईँलाई स्वागत छ<xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"इशारा टाइप गर्नेसँग"</string>
diff --git a/java/res/values-nl/strings.xml b/java/res/values-nl/strings.xml
index ec5fa06f8..d5406a8e9 100644
--- a/java/res/values-nl/strings.xml
+++ b/java/res/values-nl/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Dezelfde invoerstijl bestaat al: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Trilingsduur bij toetsgebruik"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Geluidsvolume bij toetsgebruik"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Vertraging toets lang indrukkn"</string>
<string name="button_default" msgid="3988017840431881491">"Standaard"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Welkom bij <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"met Invoer met bewegingen"</string>
diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml
index 0bc3d4b15..30e87bc28 100644
--- a/java/res/values-pl/strings.xml
+++ b/java/res/values-pl/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Taki styl wprowadzania już istnieje: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Wibracja przy naciśniętym klawiszu"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Głośność przy naciśniętym klawiszu"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Opóźnienie przy długim naciśnięciu"</string>
<string name="button_default" msgid="3988017840431881491">"Domyślne"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Witamy w aplikacji <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"z pisaniem gestami"</string>
diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml
index 2c7ff8b40..512647ae6 100644
--- a/java/res/values-pt-rPT/strings.xml
+++ b/java/res/values-pt-rPT/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Já existe o mesmo estilo de introdução: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Duração vibr. ao premir teclas"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Volume do som ao premir teclas"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Atraso ao manter tecla premida"</string>
<string name="button_default" msgid="3988017840431881491">"Predefinido"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Bem-vindo(a) a <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"com a Escrita com Gestos"</string>
diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml
index f74072228..73ff94ace 100644
--- a/java/res/values-pt/strings.xml
+++ b/java/res/values-pt/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"O estilo de entrada já existe: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Duração da vibração ao tocar"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Volume ao tocar na tela"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Atraso ao pressionar teclas"</string>
<string name="button_default" msgid="3988017840431881491">"Padrão"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Bem-vindo ao <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"com entrada por gestos"</string>
diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml
index 007c61dfc..a87eeebf3 100644
--- a/java/res/values-ro/strings.xml
+++ b/java/res/values-ro/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Acelaşi stil de introducere există deja: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Vibrare după apăsarea tastei"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Sunet la apăsarea tastelor"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Timpul apăsării lungi a tastei"</string>
<string name="button_default" msgid="3988017840431881491">"Prestabilit"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Bun venit la <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"cu Tastarea gestuală"</string>
diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml
index 15ddb5ebf..3aef94dfc 100644
--- a/java/res/values-ru/strings.xml
+++ b/java/res/values-ru/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Такой стиль ввода уже существует: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Вибросигнал при нажатии клавиш"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Звук при нажатии клавиш"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Долгое нажатие"</string>
<string name="button_default" msgid="3988017840431881491">"По умолчанию"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Представляем приложение \"<xliff:g id="APPLICATION_NAME">%s</xliff:g>\""</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"с непрерывным вводом"</string>
diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml
index 2f428aee6..01e05004b 100644
--- a/java/res/values-sk/strings.xml
+++ b/java/res/values-sk/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Rovnaký štýl vstupu už existuje: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Trvanie vibrov. pri stlač. kl."</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Hlasitosť pri stlačení klávesu"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Oneskor. pri stlač. a podržaní"</string>
<string name="button_default" msgid="3988017840431881491">"Predvolené"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Vitajte v aplikácii <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"s funkciou Písanie gestami"</string>
diff --git a/java/res/values-sl/strings.xml b/java/res/values-sl/strings.xml
index 57d5d7268..8872b5656 100644
--- a/java/res/values-sl/strings.xml
+++ b/java/res/values-sl/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Isti slog vnosa že obstaja: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Trajanje vibr. ob prit. tipke"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Glasn. zvoka ob pritisku tipke"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Zakasn. za dolg pritisk tipke"</string>
<string name="button_default" msgid="3988017840431881491">"Privzeto"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Pozdravljeni v aplikaciji <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"s pisanjem s kretnjami"</string>
diff --git a/java/res/values-sr/strings.xml b/java/res/values-sr/strings.xml
index de2add40a..0d08933f6 100644
--- a/java/res/values-sr/strings.xml
+++ b/java/res/values-sr/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Исти стил уноса већ постоји: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Трајање вибрације при притиску"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Јачина звука при притиску"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Одлагање при дугом притиску"</string>
<string name="button_default" msgid="3988017840431881491">"Подразумевано"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Добро дошли у <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"помоћу Куцања покретима"</string>
diff --git a/java/res/values-sv/strings.xml b/java/res/values-sv/strings.xml
index f7a94d92b..f3945a3ad 100644
--- a/java/res/values-sv/strings.xml
+++ b/java/res/values-sv/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Samma indatastil finns redan: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Vibrationslängd för tangenter"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Ljudvolym för tangenter"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Fördröjning vid långt tryck"</string>
<string name="button_default" msgid="3988017840431881491">"Standard"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Välkommen till <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"med svepskrivning"</string>
diff --git a/java/res/values-sw/strings.xml b/java/res/values-sw/strings.xml
index 5f86d351b..10198ea0a 100644
--- a/java/res/values-sw/strings.xml
+++ b/java/res/values-sw/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Mfumo sawa wa maingizo tayari upo: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Bonyeza kitufe cha muda wa kutetema"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Bonyeza kitufe cha kiwango cha sauti"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Ubofyaji kitufe kunakochelewa"</string>
<string name="button_default" msgid="3988017840431881491">"Chaguo-msingi"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Karibu kwenye <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"kwa Kuandika kwa ishara"</string>
diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml
index 94374cf1a..674c03b06 100644
--- a/java/res/values-th/strings.xml
+++ b/java/res/values-th/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"รูปแบบการป้อนข้อมูลเดียวกันนี้มีอยู่แล้ว: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"ระยะเวลาการสั่นเมื่อกดแป้นพิมพ์"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"ระดับเสียงเมื่อกดแป้นพิมพ์"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"การหน่วงเวลาของการกดแป้นค้าง"</string>
<string name="button_default" msgid="3988017840431881491">"ค่าเริ่มต้น"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"ยินดีต้อนรับสู่ <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"พร้อมการป้อนข้อมูลด้วยท่าทาง"</string>
diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml
index d523e2e46..6fa06c913 100644
--- a/java/res/values-tl/strings.xml
+++ b/java/res/values-tl/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Umiiral na ang parehong estilo ng input: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Tagal ng vibration ng keypress"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Volume ng tunog ng keypress"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Key long press delay"</string>
<string name="button_default" msgid="3988017840431881491">"Default"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Maligayang pagdating sa <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"gamit ang Gesture na Pag-type"</string>
diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml
index 1db5ec182..5802d7960 100644
--- a/java/res/values-tr/strings.xml
+++ b/java/res/values-tr/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Aynı giriş stili zaten var: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Tuşa basma titreşim süresi"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Tuşa basma ses seviyesi"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Tuşa uzun basma gecikmesi"</string>
<string name="button_default" msgid="3988017840431881491">"Varsayılan"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> uygulamasına hoş geldiniz"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"Hareketle Yazmayı içerir"</string>
diff --git a/java/res/values-uk/strings.xml b/java/res/values-uk/strings.xml
index 29003d1be..639658d3e 100644
--- a/java/res/values-uk/strings.xml
+++ b/java/res/values-uk/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Такий стиль введення вже існує: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Вібрація при натисканні клавіш"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Гучність натискання клавіш"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Затримка довгого натискання"</string>
<string name="button_default" msgid="3988017840431881491">"За умовчанням"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Вітаємо в програмі <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"з функцією Ввід жестами"</string>
diff --git a/java/res/values-v21/themes-lxx.xml b/java/res/values-v21/themes-lxx.xml
new file mode 100644
index 000000000..5a6017cce
--- /dev/null
+++ b/java/res/values-v21/themes-lxx.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style
+ name="InputView.LXX"
+ parent="InputView"
+ >
+ <item name="android:elevation">8dp</item>
+ </style>
+</resources>
diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml
index 08d5eee17..3c803a366 100644
--- a/java/res/values-vi/strings.xml
+++ b/java/res/values-vi/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Đã tồn tại kiểu nhập tương tự: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Thời gian rung khi nhấn phím"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Âm lượng khi nhấn phím"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Tgian chờ cho nhấn và giữ phím"</string>
<string name="button_default" msgid="3988017840431881491">"Mặc định"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Chào mừng bạn đến với <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"với Nhập bằng cử chỉ"</string>
diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml
index 7e0a103f4..7524e324c 100644
--- a/java/res/values-zh-rCN/strings.xml
+++ b/java/res/values-zh-rCN/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"已经存在相同的输入风格:<xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"按键振动时长"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"按键音量"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"按键长按延迟"</string>
<string name="button_default" msgid="3988017840431881491">"默认"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"欢迎使用 <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"体验顺畅的滑行输入体验"</string>
diff --git a/java/res/values-zh-rHK/strings.xml b/java/res/values-zh-rHK/strings.xml
index 74a552421..3c013ad4f 100644
--- a/java/res/values-zh-rHK/strings.xml
+++ b/java/res/values-zh-rHK/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"已存在相同的輸入樣式:<xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"按鍵震動時間"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"按鍵音量"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"長按鍵延遲"</string>
<string name="button_default" msgid="3988017840431881491">"預設"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"歡迎使用「<xliff:g id="APPLICATION_NAME">%s</xliff:g>」"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"配備觸控輸入功能"</string>
diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml
index 3b999eaf5..28bbc8a46 100644
--- a/java/res/values-zh-rTW/strings.xml
+++ b/java/res/values-zh-rTW/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"已存在相同的輸入樣式:<xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"按鍵震動持續時間"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"按鍵音量"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"按鍵長按延遲"</string>
<string name="button_default" msgid="3988017840431881491">"預設"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"歡迎使用 <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"含滑行輸入功能"</string>
diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml
index 4d2afab9b..0c80aee61 100644
--- a/java/res/values-zu/strings.xml
+++ b/java/res/values-zu/strings.xml
@@ -124,6 +124,7 @@
<string name="custom_input_style_already_exists" msgid="8008728952215449707">"Isitayela sokufaka esifanayo sesivele sikhona: <xliff:g id="INPUT_STYLE_NAME">%s</xliff:g>"</string>
<string name="prefs_keypress_vibration_duration_settings" msgid="7918341459947439226">"Ubude besikhathi sokudlidliza ukucindezela ukhiye"</string>
<string name="prefs_keypress_sound_volume_settings" msgid="6027007337036891623">"Ivolumu yomsindo wokucindezela ukhiye"</string>
+ <string name="prefs_key_longpress_timeout_settings" msgid="6102240298932897873">"Ukulibazisa ukucindezela isikhashana ukhiye"</string>
<string name="button_default" msgid="3988017840431881491">"Okuzenzakalelayo"</string>
<string name="setup_welcome_title" msgid="6112821709832031715">"Siyakwamukela ku-<xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="setup_welcome_additional_description" msgid="8150252008545768953">"nokuthayipha ngokuthinta"</string>
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index f2072fd37..be35d131d 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -20,6 +20,8 @@
<resources>
<declare-styleable name="KeyboardTheme">
+ <!-- InputView style -->
+ <attr name="inputViewStyle" format="reference" />
<!-- Keyboard style -->
<attr name="keyboardStyle" format="reference" />
<!-- KeyboardView style -->
diff --git a/java/res/values/donottranslate-debug-settings.xml b/java/res/values/donottranslate-debug-settings.xml
index 199f9772b..cc8c1a01d 100644
--- a/java/res/values/donottranslate-debug-settings.xml
+++ b/java/res/values/donottranslate-debug-settings.xml
@@ -28,8 +28,6 @@
<string name="sliding_key_input_preview">Show slide indicator</string>
<!-- Option summary to enable sliding key input indicator. The user can see a rubber band-like effect during sliding key input. [CHAR LIMIT=66]-->
<string name="sliding_key_input_preview_summary">Display visual cue while sliding from Shift or Symbol keys</string>
- <!-- Title of the settings for key long press delay [CHAR LIMIT=35] -->
- <string name="prefs_key_longpress_timeout_settings">Key long press delay</string>
<!-- Title of the settings for customize key popup animation parameters [CHAR LIMIT=35] -->
<string name="prefs_customize_key_preview_animation">Customize key preview animation</string>
<!-- Title of the settings for key popup show up animation duration (in milliseconds) [CHAR LIMIT=35] -->
diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml
index 6aea637c5..54bfc51d3 100644
--- a/java/res/values/strings.xml
+++ b/java/res/values/strings.xml
@@ -56,9 +56,11 @@
<!-- Option for enabling or disabling the split keyboard layout. [CHAR LIMIT=65]-->
<string name="enable_split_keyboard">Enable split keyboard</string>
- <string name="sync_now_title" translatable="false">Sync Now</string>
- <string name="sync_now_summary" translatable="false">Sync your personal dictionary</string>
- <string name="sync_now_summary_disabled_signed_out" translatable="false">Select an account to enable sync</string>
+ <!-- TODO: Enable translation for user-visible strings -->
+ <string name="cloud_sync_title" translatable="false">Enable sync</string>
+ <string name="cloud_sync_summary" translatable="false">Sync your personal dictionary across devices</string>
+ <string name="cloud_sync_summary_disabled_signed_out" translatable="false">Select an account to enable sync</string>
+ <string name="sync_now_title" translatable="false">[DEBUG] Sync Now</string>
<!-- Option name for including other IMEs in the language switch list [CHAR LIMIT=30] -->
<string name="include_other_imes_in_language_switch_list">Switch to other input methods</string>
@@ -359,6 +361,8 @@ mobile devices. [CHAR LIMIT=25] -->
<string name="prefs_keypress_vibration_duration_settings">Keypress vibration duration</string>
<!-- Title of the settings for keypress sound volume [CHAR LIMIT=35] -->
<string name="prefs_keypress_sound_volume_settings">Keypress sound volume</string>
+ <!-- Title of the settings for key long press delay [CHAR LIMIT=35] -->
+ <string name="prefs_key_longpress_timeout_settings">Key long press delay</string>
<!-- Title of the button to revert to the default value of the device in the settings dialog [CHAR LIMIT=15] -->
<string name="button_default">Default</string>
diff --git a/java/res/values/themes-common.xml b/java/res/values/themes-common.xml
index 110f6b792..f7cb10f93 100644
--- a/java/res/values/themes-common.xml
+++ b/java/res/values/themes-common.xml
@@ -20,6 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="KeyboardIcons" />
+ <style name="InputView" />
<!-- Default theme values -->
<style name="Keyboard">
<item name="rowHeight">25%p</item>
diff --git a/java/res/values/themes-holo.xml b/java/res/values/themes-holo.xml
index 9f1bd2f78..efac65627 100644
--- a/java/res/values/themes-holo.xml
+++ b/java/res/values/themes-holo.xml
@@ -19,6 +19,10 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style
+ name="InputView.Holo"
+ parent="InputView"
+ />
<!-- Holo KeyboardView theme (ICS and KLP) -->
<style
name="KeyboardView.Holo"
diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml
index bfbac0a94..ecf40e4e6 100644
--- a/java/res/values/themes-ics.xml
+++ b/java/res/values/themes-ics.xml
@@ -20,6 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="KeyboardTheme.ICS" parent="KeyboardIcons.Holo">
+ <item name="inputViewStyle">@style/InputView.Holo</item>
<item name="keyboardStyle">@style/Keyboard.ICS</item>
<item name="keyboardViewStyle">@style/KeyboardView.ICS</item>
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.ICS</item>
diff --git a/java/res/values/themes-klp.xml b/java/res/values/themes-klp.xml
index 36b1fc117..de1cd9bf1 100644
--- a/java/res/values/themes-klp.xml
+++ b/java/res/values/themes-klp.xml
@@ -20,6 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="KeyboardTheme.KLP" parent="KeyboardIcons.Holo">
+ <item name="inputViewStyle">@style/InputView.Holo</item>
<item name="keyboardStyle">@style/Keyboard.KLP</item>
<item name="keyboardViewStyle">@style/KeyboardView.KLP</item>
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.KLP</item>
diff --git a/java/res/values/themes-lxx-dark.xml b/java/res/values/themes-lxx-dark.xml
index 67f94f329..b081772e9 100644
--- a/java/res/values/themes-lxx-dark.xml
+++ b/java/res/values/themes-lxx-dark.xml
@@ -20,6 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="KeyboardTheme.LXX_Dark" parent="KeyboardIcons.LXX_Dark">
+ <item name="inputViewStyle">@style/InputView.LXX</item>
<item name="keyboardStyle">@style/Keyboard.LXX_Dark</item>
<item name="keyboardViewStyle">@style/KeyboardView.LXX_Dark</item>
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Dark</item>
diff --git a/java/res/values/themes-lxx-light.xml b/java/res/values/themes-lxx-light.xml
index be817f46a..3d294e450 100644
--- a/java/res/values/themes-lxx-light.xml
+++ b/java/res/values/themes-lxx-light.xml
@@ -20,6 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="KeyboardTheme.LXX_Light" parent="KeyboardIcons.LXX_Light">
+ <item name="inputViewStyle">@style/InputView.LXX</item>
<item name="keyboardStyle">@style/Keyboard.LXX_Light</item>
<item name="keyboardViewStyle">@style/KeyboardView.LXX_Light</item>
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Light</item>
diff --git a/java/res/values/themes-lxx.xml b/java/res/values/themes-lxx.xml
index c72188871..463306b43 100644
--- a/java/res/values/themes-lxx.xml
+++ b/java/res/values/themes-lxx.xml
@@ -19,6 +19,10 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <style
+ name="InputView.LXX"
+ parent="InputView"
+ />
<!-- LXX KeyboardView theme (LXX_Light and LXX_Dark) -->
<style
name="KeyboardView.LXX"
diff --git a/java/res/xml/prefs_screen_accounts.xml b/java/res/xml/prefs_screen_accounts.xml
index 003a37ff7..41642bf08 100644
--- a/java/res/xml/prefs_screen_accounts.xml
+++ b/java/res/xml/prefs_screen_accounts.xml
@@ -28,7 +28,15 @@
android:title="@string/switch_accounts"
android:summary="@string/no_accounts_selected" />
- <!-- title will be set programmatically to embed application name -->
+ <!-- Summary will be set programmatically to reflect the account status -->
+ <CheckBoxPreference
+ android:key="pref_enable_cloud_sync"
+ android:title="@string/cloud_sync_title"
+ android:defaultValue="false"
+ android:persistent="true"
+ android:disableDependentsState="false" />
+
+ <!-- Title will be set programmatically to embed application name -->
<CheckBoxPreference
android:key="pref_enable_metrics_logging"
android:summary="@string/enable_metrics_logging_summary"
@@ -38,5 +46,6 @@
<!-- This preference (acts like a button) enables the user to initiate an one time sync. -->
<Preference android:key="pref_beanstalk"
android:persistent="false"
- android:title="@string/sync_now_title" />
+ android:title="@string/sync_now_title"
+ android:dependency="pref_enable_cloud_sync" />
</PreferenceScreen>
diff --git a/java/res/xml/prefs_screen_advanced.xml b/java/res/xml/prefs_screen_advanced.xml
index 5aefcc8d5..329822093 100644
--- a/java/res/xml/prefs_screen_advanced.xml
+++ b/java/res/xml/prefs_screen_advanced.xml
@@ -31,6 +31,12 @@
android:key="pref_keypress_sound_volume"
android:title="@string/prefs_keypress_sound_volume_settings"
latin:maxValue="100" /> <!-- percent -->
+ <com.android.inputmethod.latin.settings.SeekBarDialogPreference
+ android:key="pref_key_longpress_timeout"
+ android:title="@string/prefs_key_longpress_timeout_settings"
+ latin:minValue="@integer/config_min_longpress_timeout"
+ latin:maxValue="@integer/config_max_longpress_timeout"
+ latin:stepValue="@integer/config_longpress_timeout_step" />
<!-- The settings for showing setup wizard application icon shouldn't be persistent and
the default value is added programmatically. -->
<CheckBoxPreference
diff --git a/java/res/xml/prefs_screen_debug.xml b/java/res/xml/prefs_screen_debug.xml
index 25f7c6612..486d2367e 100644
--- a/java/res/xml/prefs_screen_debug.xml
+++ b/java/res/xml/prefs_screen_debug.xml
@@ -46,12 +46,6 @@
android:summary="@string/sliding_key_input_preview_summary"
android:defaultValue="true"
android:persistent="true" />
- <com.android.inputmethod.latin.settings.SeekBarDialogPreference
- android:key="pref_key_longpress_timeout"
- android:title="@string/prefs_key_longpress_timeout_settings"
- latin:minValue="@integer/config_min_longpress_timeout"
- latin:maxValue="@integer/config_max_longpress_timeout"
- latin:stepValue="@integer/config_longpress_timeout_step" />
<CheckBoxPreference
android:key="pref_has_custom_key_preview_animation_params"
android:title="@string/prefs_customize_key_preview_animation"
diff --git a/java/res/xml/rowkeys_telugu2.xml b/java/res/xml/rowkeys_telugu2.xml
index a472fd3f8..f1ce459e5 100644
--- a/java/res/xml/rowkeys_telugu2.xml
+++ b/java/res/xml/rowkeys_telugu2.xml
@@ -51,10 +51,10 @@
latin:moreKeys="&#x0C2B;" />
<!-- U+0C30: "ర" TELUGU LETTER RA
U+0C31: "ఱ" TELUGU LETTER RRA
- U+0C43: "ృ" TELUGU VOWEL SIGN VOCALIC R -->
+ U+0C4D/U+0C30: "్ర" TELUGU SIGN VIRAMA/TELUGU LETTER RA -->
<Key
latin:keySpec="&#x0C30;"
- latin:moreKeys="&#x0C31;,&#x0C43;" />
+ latin:moreKeys="&#x0C31;,&#x0C4D;&#x0C30;" />
<!-- U+0C15: "క" TELUGU LETTER KA
U+0C16: "ఖ" TELUGU LETTER KHA -->
<Key
diff --git a/java/res/xml/rowkeys_telugu3.xml b/java/res/xml/rowkeys_telugu3.xml
index 05755ec4d..2e3730ac7 100644
--- a/java/res/xml/rowkeys_telugu3.xml
+++ b/java/res/xml/rowkeys_telugu3.xml
@@ -19,24 +19,28 @@
-->
<merge xmlns:latin="http://schemas.android.com/apk/res/com.android.inputmethod.latin">
- <!-- U+0C46: "ె" TELUGU VOWEL SIGN E
+ <!-- U+0C4A: "ొ" TELUGU VOWEL SIGN O
U+0C12: "ఒ" TELUGU LETTER O -->
<Key
- latin:keySpec="&#x0C46;"
+ latin:keySpec="&#x0C4A;"
latin:moreKeys="&#x0C12;" />
- <!-- U+0C02: "ం" TELUGU SIGN ANUSVARA
+ <!-- U+0C46: "ె" TELUGU VOWEL SIGN E
U+0C0E: "ఎ" TELUGU LETTER E -->
<Key
- latin:keySpec="&#x0C02;"
+ latin:keySpec="&#x0C46;"
latin:moreKeys="&#x0C0E;" />
- <!-- U+0C2E: "మ" TELUGU LETTER MA -->
- <Key latin:keySpec="&#x0C2E;" />
+ <!-- U+0C2E: "మ" TELUGU LETTER MA
+ U+0C02: "ం" TELUGU SIGN ANUSVARA
+ U+0C01: "ఁ" TELUGU SIGN CANDRABINDU -->
+ <Key latin:keySpec="&#x0C2E;"
+ latin:moreKeys="&#x0C02;,&#x0C01;" />
<!-- U+0C28: "న" TELUGU LETTER NA
U+0C23: "ణ" TELUGU LETTER NNA
- U+0C19: "ఙ" TELUGU LETTER NGA -->
+ U+0C19: "ఙ" TELUGU LETTER NGA
+ U+0C1E: "ఞ" TELUGU LETTER NYA -->
<Key
latin:keySpec="&#x0C28;"
- latin:moreKeys="&#x0C23;,&#x0C19;" />
+ latin:moreKeys="&#x0C23;,&#x0C19;,&#x0C1E;" />
<!-- U+0C35: "వ" TELUGU LETTER VA -->
<Key latin:keySpec="&#x0C35;" />
<!-- U+0C32: "ల" TELUGU LETTER LA
@@ -50,10 +54,10 @@
latin:keySpec="&#x0C38;"
latin:moreKeys="&#x0C36;" />
<!-- U+0C0B: "ఋ" TELUGU LETTER VOCALIC R
- U+0C4D/U+0C30: "్ర" TELUGU SIGN VIRAMA/TELUGU LETTER RA -->
+ U+0C43: "ృ" TELUGU VOWEL SIGN VOCALIC R -->
<Key
latin:keySpec="&#x0C0B;"
- latin:moreKeys="&#x0C4D;&#x0C30;" />
+ latin:moreKeys="&#x0C43;" />
<!-- U+0C37: "ష" TELUGU LETTER SSA
U+0C15/U+0C4D/U+0C37: "క్ష" TELUGU LETTER KA/TELUGU SIGN VIRAMA/TELUGU LETTER SSA -->
<Key
diff --git a/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java
index 5af31795c..f4f54b624 100644
--- a/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java
+++ b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java
@@ -16,13 +16,20 @@
package com.android.inputmethod.compat;
+import android.annotation.TargetApi;
import android.graphics.Matrix;
import android.graphics.RectF;
+import android.os.Build;
+import android.view.inputmethod.CursorAnchorInfo;
-import com.android.inputmethod.annotations.UsedForTesting;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
-@UsedForTesting
-public final class CursorAnchorInfoCompatWrapper {
+/**
+ * A wrapper for {@link CursorAnchorInfo}, which has been introduced in API Level 21. You can use
+ * this wrapper to avoid direct dependency on newly introduced types.
+ */
+public class CursorAnchorInfoCompatWrapper {
/**
* The insertion marker or character bounds have at least one visible region.
@@ -39,123 +46,138 @@ public final class CursorAnchorInfoCompatWrapper {
*/
public static final int FLAG_IS_RTL = 0x04;
- // Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX).
- private static final CompatUtils.ClassWrapper sCursorAnchorInfoClass;
- private static final CompatUtils.ToIntMethodWrapper sGetSelectionStartMethod;
- private static final CompatUtils.ToIntMethodWrapper sGetSelectionEndMethod;
- private static final CompatUtils.ToObjectMethodWrapper<RectF> sGetCharacterBoundsMethod;
- private static final CompatUtils.ToIntMethodWrapper sGetCharacterBoundsFlagsMethod;
- private static final CompatUtils.ToObjectMethodWrapper<CharSequence> sGetComposingTextMethod;
- private static final CompatUtils.ToIntMethodWrapper sGetComposingTextStartMethod;
- private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerBaselineMethod;
- private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerBottomMethod;
- private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerHorizontalMethod;
- private static final CompatUtils.ToFloatMethodWrapper sGetInsertionMarkerTopMethod;
- private static final CompatUtils.ToObjectMethodWrapper<Matrix> sGetMatrixMethod;
- private static final CompatUtils.ToIntMethodWrapper sGetInsertionMarkerFlagsMethod;
-
- private static int INVALID_TEXT_INDEX = -1;
- static {
- sCursorAnchorInfoClass = CompatUtils.getClassWrapper(
- "android.view.inputmethod.CursorAnchorInfo");
- sGetSelectionStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
- "getSelectionStart", INVALID_TEXT_INDEX);
- sGetSelectionEndMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
- "getSelectionEnd", INVALID_TEXT_INDEX);
- sGetCharacterBoundsMethod = sCursorAnchorInfoClass.getMethod(
- "getCharacterBounds", (RectF)null, int.class);
- sGetCharacterBoundsFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
- "getCharacterBoundsFlags", 0, int.class);
- sGetComposingTextMethod = sCursorAnchorInfoClass.getMethod(
- "getComposingText", (CharSequence)null);
- sGetComposingTextStartMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
- "getComposingTextStart", INVALID_TEXT_INDEX);
- sGetInsertionMarkerBaselineMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
- "getInsertionMarkerBaseline", 0.0f);
- sGetInsertionMarkerBottomMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
- "getInsertionMarkerBottom", 0.0f);
- sGetInsertionMarkerHorizontalMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
- "getInsertionMarkerHorizontal", 0.0f);
- sGetInsertionMarkerTopMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
- "getInsertionMarkerTop", 0.0f);
- sGetMatrixMethod = sCursorAnchorInfoClass.getMethod("getMatrix", (Matrix)null);
- sGetInsertionMarkerFlagsMethod = sCursorAnchorInfoClass.getPrimitiveMethod(
- "getInsertionMarkerFlags", 0);
- }
-
- @UsedForTesting
- public boolean isAvailable() {
- return sCursorAnchorInfoClass.exists() && mInstance != null;
- }
-
- private Object mInstance;
-
- private CursorAnchorInfoCompatWrapper(final Object instance) {
- mInstance = instance;
+ private CursorAnchorInfoCompatWrapper() {
+ // This class is not publicly instantiable.
}
- @UsedForTesting
- public static CursorAnchorInfoCompatWrapper fromObject(final Object instance) {
- if (!sCursorAnchorInfoClass.exists()) {
- return new CursorAnchorInfoCompatWrapper(null);
+ @TargetApi(BuildCompatUtils.VERSION_CODES_LXX)
+ @Nullable
+ public static CursorAnchorInfoCompatWrapper wrap(@Nullable final CursorAnchorInfo instance) {
+ if (Build.VERSION.SDK_INT < BuildCompatUtils.VERSION_CODES_LXX) {
+ return null;
}
- return new CursorAnchorInfoCompatWrapper(instance);
- }
-
- private static final class FakeHolder {
- static CursorAnchorInfoCompatWrapper sInstance = new CursorAnchorInfoCompatWrapper(null);
- }
-
- @UsedForTesting
- public static CursorAnchorInfoCompatWrapper getFake() {
- return FakeHolder.sInstance;
+ if (instance == null) {
+ return null;
+ }
+ return new RealWrapper(instance);
}
public int getSelectionStart() {
- return sGetSelectionStartMethod.invoke(mInstance);
+ throw new UnsupportedOperationException("not supported.");
}
public int getSelectionEnd() {
- return sGetSelectionEndMethod.invoke(mInstance);
+ throw new UnsupportedOperationException("not supported.");
}
public CharSequence getComposingText() {
- return sGetComposingTextMethod.invoke(mInstance);
+ throw new UnsupportedOperationException("not supported.");
}
public int getComposingTextStart() {
- return sGetComposingTextStartMethod.invoke(mInstance);
+ throw new UnsupportedOperationException("not supported.");
}
public Matrix getMatrix() {
- return sGetMatrixMethod.invoke(mInstance);
+ throw new UnsupportedOperationException("not supported.");
}
public RectF getCharacterBounds(final int index) {
- return sGetCharacterBoundsMethod.invoke(mInstance, index);
+ throw new UnsupportedOperationException("not supported.");
}
public int getCharacterBoundsFlags(final int index) {
- return sGetCharacterBoundsFlagsMethod.invoke(mInstance, index);
+ throw new UnsupportedOperationException("not supported.");
}
public float getInsertionMarkerBaseline() {
- return sGetInsertionMarkerBaselineMethod.invoke(mInstance);
+ throw new UnsupportedOperationException("not supported.");
}
public float getInsertionMarkerBottom() {
- return sGetInsertionMarkerBottomMethod.invoke(mInstance);
+ throw new UnsupportedOperationException("not supported.");
}
public float getInsertionMarkerHorizontal() {
- return sGetInsertionMarkerHorizontalMethod.invoke(mInstance);
+ throw new UnsupportedOperationException("not supported.");
}
public float getInsertionMarkerTop() {
- return sGetInsertionMarkerTopMethod.invoke(mInstance);
+ throw new UnsupportedOperationException("not supported.");
}
public int getInsertionMarkerFlags() {
- return sGetInsertionMarkerFlagsMethod.invoke(mInstance);
+ throw new UnsupportedOperationException("not supported.");
+ }
+
+ @TargetApi(BuildCompatUtils.VERSION_CODES_LXX)
+ private static final class RealWrapper extends CursorAnchorInfoCompatWrapper {
+
+ @Nonnull
+ private final CursorAnchorInfo mInstance;
+
+ public RealWrapper(@Nonnull final CursorAnchorInfo info) {
+ mInstance = info;
+ }
+
+ @Override
+ public int getSelectionStart() {
+ return mInstance.getSelectionStart();
+ }
+
+ @Override
+ public int getSelectionEnd() {
+ return mInstance.getSelectionEnd();
+ }
+
+ @Override
+ public CharSequence getComposingText() {
+ return mInstance.getComposingText();
+ }
+
+ @Override
+ public int getComposingTextStart() {
+ return mInstance.getComposingTextStart();
+ }
+
+ @Override
+ public Matrix getMatrix() {
+ return mInstance.getMatrix();
+ }
+
+ @Override
+ public RectF getCharacterBounds(final int index) {
+ return mInstance.getCharacterBounds(index);
+ }
+
+ @Override
+ public int getCharacterBoundsFlags(final int index) {
+ return mInstance.getCharacterBoundsFlags(index);
+ }
+
+ @Override
+ public float getInsertionMarkerBaseline() {
+ return mInstance.getInsertionMarkerBaseline();
+ }
+
+ @Override
+ public float getInsertionMarkerBottom() {
+ return mInstance.getInsertionMarkerBottom();
+ }
+
+ @Override
+ public float getInsertionMarkerHorizontal() {
+ return mInstance.getInsertionMarkerHorizontal();
+ }
+
+ @Override
+ public float getInsertionMarkerTop() {
+ return mInstance.getInsertionMarkerTop();
+ }
+
+ @Override
+ public int getInsertionMarkerFlags() {
+ return mInstance.getInsertionMarkerFlags();
+ }
}
}
diff --git a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
index 0f00be133..16260ab6a 100644
--- a/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
+++ b/java/src/com/android/inputmethod/compat/ViewCompatUtils.java
@@ -31,9 +31,6 @@ public final class ViewCompatUtils {
private static final Method METHOD_setPaddingRelative = CompatUtils.getMethod(
View.class, "setPaddingRelative",
int.class, int.class, int.class, int.class);
- // Note that View.setElevation(float) has been introduced in API level 21.
- private static final Method METHOD_setElevation = CompatUtils.getMethod(
- View.class, "setElevation", float.class);
// Note that View.setTextAlignment(int) has been introduced in API level 17.
private static final Method METHOD_setTextAlignment = CompatUtils.getMethod(
View.class, "setTextAlignment", int.class);
@@ -58,10 +55,6 @@ public final class ViewCompatUtils {
CompatUtils.invoke(view, null, METHOD_setPaddingRelative, start, top, end, bottom);
}
- public static void setElevation(final View view, final float elevation) {
- CompatUtils.invoke(view, null, METHOD_setElevation, elevation);
- }
-
// These TEXT_ALIGNMENT_* constants have been introduced in API 17.
public static final int TEXT_ALIGNMENT_INHERIT = 0;
public static final int TEXT_ALIGNMENT_GRAVITY = 1;
diff --git a/java/src/com/android/inputmethod/compat/ViewOutlineProviderCompatUtils.java b/java/src/com/android/inputmethod/compat/ViewOutlineProviderCompatUtils.java
new file mode 100644
index 000000000..52b8b74e8
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/ViewOutlineProviderCompatUtils.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.compat;
+
+import android.inputmethodservice.InputMethodService;
+import android.view.View;
+
+public class ViewOutlineProviderCompatUtils {
+ private ViewOutlineProviderCompatUtils() {
+ // This utility class is not publicly instantiable.
+ }
+
+ public interface InsetsUpdater {
+ public void setInsets(final InputMethodService.Insets insets);
+ }
+
+ private static final InsetsUpdater EMPTY_INSETS_UPDATER = new InsetsUpdater() {
+ @Override
+ public void setInsets(final InputMethodService.Insets insets) {}
+ };
+
+ public static InsetsUpdater setInsetsOutlineProvider(final View view) {
+ if (BuildCompatUtils.EFFECTIVE_SDK_INT < BuildCompatUtils.VERSION_CODES_LXX) {
+ return EMPTY_INSETS_UPDATER;
+ }
+ return ViewOutlineProviderCompatUtilsLXX.setInsetsOutlineProvider(view);
+ }
+}
diff --git a/java/src/com/android/inputmethod/compat/ViewOutlineProviderCompatUtilsLXX.java b/java/src/com/android/inputmethod/compat/ViewOutlineProviderCompatUtilsLXX.java
new file mode 100644
index 000000000..5bbb5ce99
--- /dev/null
+++ b/java/src/com/android/inputmethod/compat/ViewOutlineProviderCompatUtilsLXX.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.compat;
+
+import android.annotation.TargetApi;
+import android.graphics.Outline;
+import android.inputmethodservice.InputMethodService;
+import android.os.Build;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater;
+
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+class ViewOutlineProviderCompatUtilsLXX {
+ private ViewOutlineProviderCompatUtilsLXX() {
+ // This utility class is not publicly instantiable.
+ }
+
+ static InsetsUpdater setInsetsOutlineProvider(final View view) {
+ final InsetsOutlineProvider provider = new InsetsOutlineProvider(view);
+ view.setOutlineProvider(provider);
+ return provider;
+ }
+
+ private static class InsetsOutlineProvider extends ViewOutlineProvider
+ implements InsetsUpdater {
+ private final View mView;
+ private static final int NO_DATA = -1;
+ private int mLastVisibleTopInsets = NO_DATA;
+
+ public InsetsOutlineProvider(final View view) {
+ mView = view;
+ view.setOutlineProvider(this);
+ }
+
+ @Override
+ public void setInsets(final InputMethodService.Insets insets) {
+ final int visibleTopInsets = insets.visibleTopInsets;
+ if (mLastVisibleTopInsets != visibleTopInsets) {
+ mLastVisibleTopInsets = visibleTopInsets;
+ mView.invalidateOutline();
+ }
+ }
+
+ @Override
+ public void getOutline(final View view, final Outline outline) {
+ if (mLastVisibleTopInsets == NO_DATA) {
+ // Call default implementation.
+ ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
+ return;
+ }
+ // TODO: Revisit this when floating/resize keyboard is supported.
+ outline.setRect(
+ view.getLeft(), mLastVisibleTopInsets, view.getRight(), view.getBottom());
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
index 52b9284be..1c66c37d3 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardLayoutSet.java
@@ -28,6 +28,7 @@ import android.util.Log;
import android.util.SparseArray;
import android.util.Xml;
import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.compat.EditorInfoCompatUtils;
import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
@@ -39,6 +40,7 @@ import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputMethodSubtype;
import com.android.inputmethod.latin.SubtypeSwitcher;
import com.android.inputmethod.latin.define.DebugFlags;
+import com.android.inputmethod.latin.utils.DebugLogUtils;
import com.android.inputmethod.latin.utils.InputTypeUtils;
import com.android.inputmethod.latin.utils.ScriptUtils;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
@@ -313,23 +315,78 @@ public final class KeyboardLayoutSet {
return this;
}
+ private final static HashMap<InputMethodSubtype, Integer> sScriptIdsForSubtypes =
+ new HashMap<>();
+ public static int getScriptId(final Resources resources, final InputMethodSubtype subtype) {
+ final Integer value = sScriptIdsForSubtypes.get(subtype);
+ if (null == value) {
+ final int scriptId = readScriptId(resources, subtype);
+ sScriptIdsForSubtypes.put(subtype, scriptId);
+ return scriptId;
+ }
+ return value;
+ }
+
+ // Super redux version of reading the script ID for some subtype from Xml.
+ private static int readScriptId(final Resources resources,
+ final InputMethodSubtype subtype) {
+ final String layoutSetName = KEYBOARD_LAYOUT_SET_RESOURCE_PREFIX
+ + SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype);
+ final int xmlId = getXmlId(resources, layoutSetName);
+ final XmlResourceParser parser = resources.getXml(xmlId);
+ try {
+ while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ // Bovinate through the XML stupidly searching for TAG_FEATURE, and read
+ // the script Id from it.
+ parser.next();
+ final String tag = parser.getName();
+ if (TAG_FEATURE.equals(tag)) {
+ return readScriptIdFromTagFeature(resources, parser);
+ }
+ }
+ } catch (final IOException | XmlPullParserException e) {
+ throw new RuntimeException(e.getMessage() + " in " + layoutSetName, e);
+ } finally {
+ parser.close();
+ }
+ // If the tag is not found, then the default script is Latin.
+ return ScriptUtils.SCRIPT_LATIN;
+ }
+
+ private static int readScriptIdFromTagFeature(final Resources resources,
+ final XmlPullParser parser) throws IOException, XmlPullParserException {
+ final TypedArray featureAttr = resources.obtainAttributes(Xml.asAttributeSet(parser),
+ R.styleable.KeyboardLayoutSet_Feature);
+ try {
+ final int scriptId =
+ featureAttr.getInt(R.styleable.KeyboardLayoutSet_Feature_supportedScript,
+ ScriptUtils.SCRIPT_UNKNOWN);
+ XmlParseUtils.checkEndTag(TAG_FEATURE, parser);
+ return scriptId;
+ } finally {
+ featureAttr.recycle();
+ }
+ }
+
public KeyboardLayoutSet build() {
if (mParams.mSubtype == null)
throw new RuntimeException("KeyboardLayoutSet subtype is not specified");
- final String packageName = mResources.getResourcePackageName(
- R.xml.keyboard_layout_set_qwerty);
- final String keyboardLayoutSetName = mParams.mKeyboardLayoutSetName;
- final int xmlId = mResources.getIdentifier(keyboardLayoutSetName, "xml", packageName);
+ final int xmlId = getXmlId(mResources, mParams.mKeyboardLayoutSetName);
try {
parseKeyboardLayoutSet(mResources, xmlId);
- } catch (final IOException e) {
- throw new RuntimeException(e.getMessage() + " in " + keyboardLayoutSetName, e);
- } catch (final XmlPullParserException e) {
- throw new RuntimeException(e.getMessage() + " in " + keyboardLayoutSetName, e);
+ } catch (final IOException | XmlPullParserException e) {
+ throw new RuntimeException(e.getMessage() + " in " + mParams.mKeyboardLayoutSetName,
+ e);
}
return new KeyboardLayoutSet(mContext, mParams);
}
+ private static int getXmlId(final Resources resources, final String keyboardLayoutSetName) {
+ final String packageName = resources.getResourcePackageName(
+ R.xml.keyboard_layout_set_qwerty);
+ return resources.getIdentifier(keyboardLayoutSetName, "xml", packageName);
+ }
+
private void parseKeyboardLayoutSet(final Resources res, final int resId)
throws XmlPullParserException, IOException {
final XmlResourceParser parser = res.getXml(resId);
@@ -407,17 +464,8 @@ public final class KeyboardLayoutSet {
private void parseKeyboardLayoutSetFeature(final XmlPullParser parser)
throws XmlPullParserException, IOException {
- final TypedArray a = mResources.obtainAttributes(Xml.asAttributeSet(parser),
- R.styleable.KeyboardLayoutSet_Feature);
- try {
- final int scriptId = a.getInt(
- R.styleable.KeyboardLayoutSet_Feature_supportedScript,
- ScriptUtils.SCRIPT_LATIN);
- XmlParseUtils.checkEndTag(TAG_FEATURE, parser);
- setScriptId(scriptId);
- } finally {
- a.recycle();
- }
+ final int scriptId = readScriptIdFromTagFeature(mResources, parser);
+ setScriptId(scriptId);
}
private static int getKeyboardMode(final EditorInfo editorInfo) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
index 6d8c8b76f..8a9688ac4 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java
@@ -22,7 +22,6 @@ 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;
@@ -45,7 +44,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
private static KeyboardTheme[] AVAILABLE_KEYBOARD_THEMES;
- @UsedForTesting
+ /* package private for testing */
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.
@@ -57,6 +56,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
// Default theme for LXX.
BuildCompatUtils.VERSION_CODES_LXX),
new KeyboardTheme(THEME_ID_LXX_DARK, "LXXDark", R.style.KeyboardTheme_LXX_Dark,
+ // This has never been selected as default theme.
VERSION_CODES.BASE),
};
@@ -68,7 +68,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
public final int mThemeId;
public final int mStyleId;
public final String mThemeName;
- private final int mMinApiVersion;
+ public final int mMinApiVersion;
// Note: The themeId should be aligned with "themeId" attribute of Keyboard style
// in values/themes-<style>.xml.
@@ -98,7 +98,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
return mThemeId;
}
- @UsedForTesting
+ /* package private for testing */
static KeyboardTheme searchKeyboardThemeById(final int themeId,
final KeyboardTheme[] availableThemeIds) {
// TODO: This search algorithm isn't optimal if there are many themes.
@@ -110,7 +110,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
return null;
}
- @UsedForTesting
+ /* package private for testing */
static KeyboardTheme getDefaultKeyboardTheme(final SharedPreferences prefs,
final int sdkVersion, final KeyboardTheme[] availableThemeArray) {
final String klpThemeIdString = prefs.getString(KLP_KEYBOARD_THEME_KEY, null);
@@ -150,7 +150,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
saveKeyboardThemeId(themeId, prefs, BuildCompatUtils.EFFECTIVE_SDK_INT);
}
- @UsedForTesting
+ /* package private for testing */
static String getPreferenceKey(final int sdkVersion) {
if (sdkVersion <= VERSION_CODES.KITKAT) {
return KLP_KEYBOARD_THEME_KEY;
@@ -158,7 +158,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
return LXX_KEYBOARD_THEME_KEY;
}
- @UsedForTesting
+ /* package private for testing */
static void saveKeyboardThemeId(final int themeId, final SharedPreferences prefs,
final int sdkVersion) {
final String prefKey = getPreferenceKey(sdkVersion);
@@ -171,6 +171,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
return getKeyboardTheme(prefs, BuildCompatUtils.EFFECTIVE_SDK_INT, availableThemeArray);
}
+ /* package private for testing */
static KeyboardTheme[] getAvailableThemeArray(final Context context) {
if (AVAILABLE_KEYBOARD_THEMES == null) {
final int[] availableThemeIdStringArray = context.getResources().getIntArray(
@@ -184,11 +185,12 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> {
}
AVAILABLE_KEYBOARD_THEMES = availableThemeList.toArray(
new KeyboardTheme[availableThemeList.size()]);
+ Arrays.sort(AVAILABLE_KEYBOARD_THEMES);
}
return AVAILABLE_KEYBOARD_THEMES;
}
- @UsedForTesting
+ /* package private for testing */
static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs, final int sdkVersion,
final KeyboardTheme[] availableThemeArray) {
final String lxxThemeIdString = prefs.getString(LXX_KEYBOARD_THEME_KEY, null);
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index e7be6de4c..06f9ced92 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -28,6 +28,7 @@ import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Typeface;
import android.preference.PreferenceManager;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
@@ -57,8 +58,10 @@ import com.android.inputmethod.latin.RichInputMethodSubtype;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.settings.DebugSettings;
import com.android.inputmethod.latin.utils.CoordinateUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
import com.android.inputmethod.latin.utils.TypefaceUtils;
+import java.util.Locale;
import java.util.WeakHashMap;
/**
@@ -855,8 +858,13 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private String layoutLanguageOnSpacebar(final Paint paint,
final RichInputMethodSubtype subtype, final int width) {
if (mLanguageOnSpacebarFormatType == LanguageOnSpacebarHelper.FORMAT_TYPE_MULTIPLE) {
- // TODO: return an appropriate string
- return "";
+ final Locale[] locales = subtype.getLocales();
+ final String[] languages = new String[locales.length];
+ for (int i = 0; i < locales.length; ++i) {
+ languages[i] = StringUtils.toUpperCaseOfStringForLocale(
+ locales[i].getLanguage(), true /* needsToUpperCase */, Locale.ROOT);
+ }
+ return TextUtils.join(" / ", languages);
}
// Choose appropriate language name to fit into the width.
diff --git a/java/src/com/android/inputmethod/keyboard/TextDecorator.java b/java/src/com/android/inputmethod/keyboard/TextDecorator.java
index c22717f95..2b7d2ce3c 100644
--- a/java/src/com/android/inputmethod/keyboard/TextDecorator.java
+++ b/java/src/com/android/inputmethod/keyboard/TextDecorator.java
@@ -30,6 +30,7 @@ import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
/**
* A controller class of the add-to-dictionary indicator (a.k.a. TextDecorator). This class
@@ -56,6 +57,7 @@ public class TextDecorator {
private String mWaitingWord = null;
private int mWaitingCursorStart = INVALID_CURSOR_INDEX;
private int mWaitingCursorEnd = INVALID_CURSOR_INDEX;
+ @Nullable
private CursorAnchorInfoCompatWrapper mCursorAnchorInfoWrapper = null;
@Nonnull
@@ -150,7 +152,7 @@ public class TextDecorator {
* mode.</p>
* @param info the compatibility wrapper object for the received {@link CursorAnchorInfo}.
*/
- public void onUpdateCursorAnchorInfo(final CursorAnchorInfoCompatWrapper info) {
+ public void onUpdateCursorAnchorInfo(@Nullable final CursorAnchorInfoCompatWrapper info) {
mCursorAnchorInfoWrapper = info;
// Do not use layoutLater() to minimize the latency.
layoutImmediately();
@@ -182,7 +184,7 @@ public class TextDecorator {
private void layoutMain() {
final CursorAnchorInfoCompatWrapper info = mCursorAnchorInfoWrapper;
- if (info == null || !info.isAvailable()) {
+ if (info == null) {
cancelLayoutInternalExpectedly("CursorAnchorInfo isn't available.");
return;
}
@@ -301,7 +303,7 @@ public class TextDecorator {
*/
private static final class LayoutInvalidator {
private final HandlerImpl mHandler;
- public LayoutInvalidator(final TextDecorator ownerInstance) {
+ public LayoutInvalidator(@Nonnull final TextDecorator ownerInstance) {
mHandler = new HandlerImpl(ownerInstance);
}
@@ -309,7 +311,7 @@ public class TextDecorator {
private static final class HandlerImpl
extends LeakGuardHandlerWrapper<TextDecorator> {
- public HandlerImpl(final TextDecorator ownerInstance) {
+ public HandlerImpl(@Nonnull final TextDecorator ownerInstance) {
super(ownerInstance);
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java b/java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java
index 4f8a105d5..1a55359f5 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/DrawingHandler.java
@@ -23,6 +23,8 @@ import com.android.inputmethod.keyboard.internal.DrawingHandler.Callbacks;
import com.android.inputmethod.latin.SuggestedWords;
import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
+import javax.annotation.Nonnull;
+
// TODO: Separate this class into KeyPreviewHandler and BatchInputPreviewHandler or so.
public class DrawingHandler extends LeakGuardHandlerWrapper<Callbacks> {
public interface Callbacks {
@@ -34,7 +36,7 @@ public class DrawingHandler extends LeakGuardHandlerWrapper<Callbacks> {
private static final int MSG_DISMISS_KEY_PREVIEW = 0;
private static final int MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1;
- public DrawingHandler(final Callbacks ownerInstance) {
+ public DrawingHandler(@Nonnull final Callbacks ownerInstance) {
super(ownerInstance);
}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java b/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java
index ec7b9b024..80b299bf5 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/TimerHandler.java
@@ -27,6 +27,8 @@ import com.android.inputmethod.keyboard.internal.TimerHandler.Callbacks;
import com.android.inputmethod.latin.Constants;
import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper;
+import javax.annotation.Nonnull;
+
// TODO: Separate this class into KeyTimerHandler and BatchInputTimerHandler or so.
public final class TimerHandler extends LeakGuardHandlerWrapper<Callbacks> implements TimerProxy {
public interface Callbacks {
@@ -45,7 +47,7 @@ public final class TimerHandler extends LeakGuardHandlerWrapper<Callbacks> imple
private final int mIgnoreAltCodeKeyTimeout;
private final int mGestureRecognitionUpdateTime;
- public TimerHandler(final Callbacks ownerInstance, final int ignoreAltCodeKeyTimeout,
+ public TimerHandler(@Nonnull final Callbacks ownerInstance, final int ignoreAltCodeKeyTimeout,
final int gestureRecognitionUpdateTime) {
super(ownerInstance);
mIgnoreAltCodeKeyTimeout = ignoreAltCodeKeyTimeout;
diff --git a/java/src/com/android/inputmethod/latin/BackupAgent.java b/java/src/com/android/inputmethod/latin/BackupAgent.java
index 1f044618a..b2d92b30c 100644
--- a/java/src/com/android/inputmethod/latin/BackupAgent.java
+++ b/java/src/com/android/inputmethod/latin/BackupAgent.java
@@ -17,15 +17,41 @@
package com.android.inputmethod.latin;
import android.app.backup.BackupAgentHelper;
+import android.app.backup.BackupDataInput;
import android.app.backup.SharedPreferencesBackupHelper;
+import android.content.SharedPreferences;
+import android.os.ParcelFileDescriptor;
+
+import com.android.inputmethod.latin.settings.LocalSettingsConstants;
+
+import java.io.IOException;
/**
- * Backs up the Latin IME shared preferences.
+ * Backup/restore agent for LatinIME.
+ * Currently it backs up the default shared preferences.
*/
public final class BackupAgent extends BackupAgentHelper {
+ private static final String PREF_SUFFIX = "_preferences";
+
@Override
public void onCreate() {
addHelper("shared_pref", new SharedPreferencesBackupHelper(this,
- getPackageName() + "_preferences"));
+ getPackageName() + PREF_SUFFIX));
+ }
+
+ @Override
+ public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+ throws IOException {
+ // Let the restore operation go through
+ super.onRestore(data, appVersionCode, newState);
+
+ // Remove the preferences that we don't want restored.
+ final SharedPreferences.Editor prefEditor = getSharedPreferences(
+ getPackageName() + PREF_SUFFIX, MODE_PRIVATE).edit();
+ for (final String key : LocalSettingsConstants.PREFS_TO_SKIP_RESTORING) {
+ prefEditor.remove(key);
+ }
+ // Flush the changes to disk.
+ prefEditor.commit();
}
}
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 10dea749d..2fece7c85 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -70,7 +70,7 @@ public final class BinaryDictionary extends Dictionary {
private static final int FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT = 5;
private static final int FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX = 0;
private static final int FORMAT_WORD_PROPERTY_IS_BLACKLISTED_INDEX = 1;
- private static final int FORMAT_WORD_PROPERTY_HAS_BIGRAMS_INDEX = 2;
+ private static final int FORMAT_WORD_PROPERTY_HAS_NGRAMS_INDEX = 2;
private static final int FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX = 3;
private static final int FORMAT_WORD_PROPERTY_IS_BEGINNING_OF_SENTENCE_INDEX = 4;
@@ -179,9 +179,10 @@ public final class BinaryDictionary extends Dictionary {
boolean[] isBeginningOfSentenceArray, int[] word);
private static native void getWordPropertyNative(long dict, int[] word,
boolean isBeginningOfSentence, int[] outCodePoints, boolean[] outFlags,
- int[] outProbabilityInfo, ArrayList<int[]> outBigramTargets,
- ArrayList<int[]> outBigramProbabilityInfo, ArrayList<int[]> outShortcutTargets,
- ArrayList<Integer> outShortcutProbabilities);
+ int[] outProbabilityInfo, ArrayList<int[][]> outNgramPrevWordsArray,
+ ArrayList<boolean[]> outNgramPrevWordIsBeginningOfSentenceArray,
+ ArrayList<int[]> outNgramTargets, ArrayList<int[]> outNgramProbabilityInfo,
+ ArrayList<int[]> outShortcutTargets, ArrayList<Integer> outShortcutProbabilities);
private static native int getNextWordNative(long dict, int token, int[] outCodePoints,
boolean[] outIsBeginningOfSentence);
private static native void getSuggestionsNative(long dict, long proximityInfo,
@@ -201,8 +202,7 @@ public final class BinaryDictionary extends Dictionary {
int[] word, int probability, int timestamp);
private static native boolean removeNgramEntryNative(long dict,
int[][] prevWordCodePointArrays, boolean[] isBeginningOfSentenceArray, int[] word);
- // TODO: Rename to updateEntriesForWordWithNgramContextNative.
- private static native boolean updateCounterNative(long dict,
+ private static native boolean updateEntriesForWordWithNgramContextNative(long dict,
int[][] prevWordCodePointArrays, boolean[] isBeginningOfSentenceArray,
int[] word, boolean isValidWord, int count, int timestamp);
private static native int addMultipleDictionaryEntriesNative(long dict,
@@ -292,6 +292,7 @@ public final class BinaryDictionary extends Dictionary {
settingsValuesForSuggestion.mSpaceAwareGestureEnabled);
session.mNativeSuggestOptions.setAdditionalFeaturesOptions(
settingsValuesForSuggestion.mAdditionalFeaturesSettingValues);
+ session.mNativeSuggestOptions.setWeightForLocale(weightForLocale);
if (inOutWeightOfLangModelVsSpatialModel != null) {
session.mInputOutputWeightOfLangModelVsSpatialModel[0] =
inOutWeightOfLangModelVsSpatialModel[0];
@@ -388,20 +389,25 @@ public final class BinaryDictionary extends Dictionary {
final boolean[] outFlags = new boolean[FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT];
final int[] outProbabilityInfo =
new int[FORMAT_WORD_PROPERTY_OUTPUT_PROBABILITY_INFO_COUNT];
- final ArrayList<int[]> outBigramTargets = new ArrayList<>();
- final ArrayList<int[]> outBigramProbabilityInfo = new ArrayList<>();
+ final ArrayList<int[][]> outNgramPrevWordsArray = new ArrayList<>();
+ final ArrayList<boolean[]> outNgramPrevWordIsBeginningOfSentenceArray =
+ new ArrayList<>();
+ final ArrayList<int[]> outNgramTargets = new ArrayList<>();
+ final ArrayList<int[]> outNgramProbabilityInfo = new ArrayList<>();
final ArrayList<int[]> outShortcutTargets = new ArrayList<>();
final ArrayList<Integer> outShortcutProbabilities = new ArrayList<>();
getWordPropertyNative(mNativeDict, codePoints, isBeginningOfSentence, outCodePoints,
- outFlags, outProbabilityInfo, outBigramTargets, outBigramProbabilityInfo,
- outShortcutTargets, outShortcutProbabilities);
+ outFlags, outProbabilityInfo, outNgramPrevWordsArray,
+ outNgramPrevWordIsBeginningOfSentenceArray, outNgramTargets,
+ outNgramProbabilityInfo, outShortcutTargets, outShortcutProbabilities);
return new WordProperty(codePoints,
outFlags[FORMAT_WORD_PROPERTY_IS_NOT_A_WORD_INDEX],
outFlags[FORMAT_WORD_PROPERTY_IS_BLACKLISTED_INDEX],
- outFlags[FORMAT_WORD_PROPERTY_HAS_BIGRAMS_INDEX],
+ outFlags[FORMAT_WORD_PROPERTY_HAS_NGRAMS_INDEX],
outFlags[FORMAT_WORD_PROPERTY_HAS_SHORTCUTS_INDEX],
outFlags[FORMAT_WORD_PROPERTY_IS_BEGINNING_OF_SENTENCE_INDEX], outProbabilityInfo,
- outBigramTargets, outBigramProbabilityInfo, outShortcutTargets,
+ outNgramPrevWordsArray, outNgramPrevWordIsBeginningOfSentenceArray,
+ outNgramTargets, outNgramProbabilityInfo, outShortcutTargets,
outShortcutProbabilities);
}
@@ -506,7 +512,7 @@ public final class BinaryDictionary extends Dictionary {
final boolean[] isBeginningOfSentenceArray = new boolean[ngramContext.getPrevWordCount()];
ngramContext.outputToArray(prevWordCodePointArrays, isBeginningOfSentenceArray);
final int[] wordCodePoints = StringUtils.toCodePointArray(word);
- if (!updateCounterNative(mNativeDict, prevWordCodePointArrays,
+ if (!updateEntriesForWordWithNgramContextNative(mNativeDict, prevWordCodePointArrays,
isBeginningOfSentenceArray, wordCodePoints, isValidWord, count, timestamp)) {
return false;
}
diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java
index 43561ba4b..e66847b56 100644
--- a/java/src/com/android/inputmethod/latin/Dictionary.java
+++ b/java/src/com/android/inputmethod/latin/Dictionary.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
+import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
@@ -36,19 +37,19 @@ public abstract class Dictionary {
// The following types do not actually come from real dictionary instances, so we create
// corresponding instances.
public static final String TYPE_USER_TYPED = "user_typed";
- public static final Dictionary DICTIONARY_USER_TYPED = new PhonyDictionary(TYPE_USER_TYPED);
+ public static final PhonyDictionary DICTIONARY_USER_TYPED = new PhonyDictionary(TYPE_USER_TYPED);
public static final String TYPE_APPLICATION_DEFINED = "application_defined";
- public static final Dictionary DICTIONARY_APPLICATION_DEFINED =
+ public static final PhonyDictionary DICTIONARY_APPLICATION_DEFINED =
new PhonyDictionary(TYPE_APPLICATION_DEFINED);
public static final String TYPE_HARDCODED = "hardcoded"; // punctuation signs and such
- public static final Dictionary DICTIONARY_HARDCODED =
+ public static final PhonyDictionary DICTIONARY_HARDCODED =
new PhonyDictionary(TYPE_HARDCODED);
// Spawned by resuming suggestions. Comes from a span that was in the TextView.
public static final String TYPE_RESUMED = "resumed";
- public static final Dictionary DICTIONARY_RESUMED =
+ public static final PhonyDictionary DICTIONARY_RESUMED =
new PhonyDictionary(TYPE_RESUMED);
// The following types of dictionary have actual functional instances. We don't need final
@@ -182,9 +183,10 @@ public abstract class Dictionary {
* Not a true dictionary. A placeholder used to indicate suggestions that don't come from any
* real dictionary.
*/
- private static class PhonyDictionary extends Dictionary {
- // This class is not publicly instantiable.
- private PhonyDictionary(final String type) {
+ @UsedForTesting
+ static class PhonyDictionary extends Dictionary {
+ @UsedForTesting
+ PhonyDictionary(final String type) {
super(type, null);
}
diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
index 6a63bfda7..08035dfd6 100644
--- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
+++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java
@@ -257,6 +257,12 @@ public class DictionaryFacilitator {
}
public void switchMostProbableLanguage(final Locale locale) {
+ if (null == locale) {
+ // In many cases, there is no locale to a committed word. For example, a typed word
+ // that does not auto-correct has no locale. In this case we simply do not change
+ // the most probable language.
+ return;
+ }
final DictionaryGroup newMostProbableDictionaryGroup =
findDictionaryGroupWithLocale(mDictionaryGroups, locale);
mMostProbableDictionaryGroup.mWeightForTypingInLocale =
diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
index d24f80a45..d58373ff6 100644
--- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java
@@ -64,9 +64,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
private static final int TIMEOUT_FOR_READ_OPS_IN_MILLISECONDS = 100;
- private static final int DEFAULT_MAX_UNIGRAM_COUNT = 10000;
- private static final int DEFAULT_MAX_BIGRAM_COUNT = 10000;
-
/**
* The maximum length of a word in this dictionary.
*/
@@ -225,10 +222,6 @@ abstract public class ExpandableBinaryDictionary extends Dictionary {
attributeMap.put(DictionaryHeader.DICTIONARY_LOCALE_KEY, mLocale.toString());
attributeMap.put(DictionaryHeader.DICTIONARY_VERSION_KEY,
String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())));
- attributeMap.put(DictionaryHeader.MAX_UNIGRAM_COUNT_KEY,
- String.valueOf(DEFAULT_MAX_UNIGRAM_COUNT));
- attributeMap.put(DictionaryHeader.MAX_BIGRAM_COUNT_KEY,
- String.valueOf(DEFAULT_MAX_BIGRAM_COUNT));
return attributeMap;
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index ec45462c4..91a4ec84c 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -60,6 +60,8 @@ import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
import com.android.inputmethod.compat.InputMethodServiceCompatUtils;
+import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils;
+import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater;
import com.android.inputmethod.dictionarypack.DictionaryPackConstants;
import com.android.inputmethod.event.Event;
import com.android.inputmethod.event.HardwareEventDecoder;
@@ -85,7 +87,6 @@ import com.android.inputmethod.latin.settings.SettingsActivity;
import com.android.inputmethod.latin.settings.SettingsValues;
import com.android.inputmethod.latin.suggestions.SuggestionStripView;
import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor;
-import com.android.inputmethod.latin.sync.BeanstalkManager;
import com.android.inputmethod.latin.touchinputconsumer.GestureConsumer;
import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.CapsModeUtils;
@@ -109,6 +110,8 @@ import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
+import javax.annotation.Nonnull;
+
/**
* Input method implementation for Qwerty'ish keyboard.
*/
@@ -154,6 +157,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// TODO: Move these {@link View}s to {@link KeyboardSwitcher}.
private View mInputView;
+ private InsetsUpdater mInsetsUpdater;
private SuggestionStripView mSuggestionStripView;
private TextView mExtractEditText;
@@ -206,7 +210,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private int mDelayInMillisecondsToUpdateSuggestions;
private int mDelayInMillisecondsToUpdateShiftState;
- public UIHandler(final LatinIME ownerInstance) {
+ public UIHandler(@Nonnull final LatinIME ownerInstance) {
super(ownerInstance);
}
@@ -558,7 +562,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
AudioAndHapticFeedbackManager.init(this);
AccessibilityUtils.init(this);
mStatsUtilsManager.onCreate(this /* context */);
- BeanstalkManager.getInstance(this /* context */).onCreate();
super.onCreate();
mHandler.onCreate();
@@ -567,6 +570,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// TODO: Resolve mutual dependencies of {@link #loadSettings()} and
// {@link #resetDictionaryFacilitatorIfNecessary()}.
loadSettings();
+ mSubtypeSwitcher.onSubtypeChanged(mRichImm.getCurrentRawSubtype());
resetDictionaryFacilitatorIfNecessary();
// Register to receive ringer mode change and network state change.
@@ -706,7 +710,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
unregisterReceiver(mDictionaryPackInstallReceiver);
unregisterReceiver(mDictionaryDumpBroadcastReceiver);
mStatsUtilsManager.onDestroy();
- BeanstalkManager.getInstance(this /* context */).onDestroy();
super.onDestroy();
}
@@ -754,6 +757,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void setInputView(final View view) {
super.setInputView(view);
mInputView = view;
+ mInsetsUpdater = ViewOutlineProviderCompatUtils.setInsetsOutlineProvider(view);
updateSoftInputWindowLayoutParameters();
mSuggestionStripView = (SuggestionStripView)view.findViewById(R.id.suggestion_strip_view);
if (hasSuggestionStripView()) {
@@ -791,23 +795,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
- onExtractTextViewPreDraw();
+ // CursorAnchorInfo is used on L and later.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ if (isFullscreenMode() && mExtractEditText != null) {
+ mInputLogic.onUpdateCursorAnchorInfo(
+ CursorAnchorInfoUtils.extractFromTextView(mExtractEditText));
+ }
+ }
return true;
}
};
- private void onExtractTextViewPreDraw() {
- // CursorAnchorInfo is available on L and later.
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.L) {
- return;
- }
- if (!isFullscreenMode() || mExtractEditText == null) {
- return;
- }
- final CursorAnchorInfo info = CursorAnchorInfoUtils.getCursorAnchorInfo(mExtractEditText);
- mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info));
- }
-
@Override
public void setCandidatesView(final View view) {
// To ensure that CandidatesView will never be set.
@@ -842,8 +840,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
public void onCurrentInputMethodSubtypeChanged(final InputMethodSubtype subtype) {
// Note that the calling sequence of onCreate() and onCurrentInputMethodSubtypeChanged()
// is not guaranteed. It may even be called at the same time on a different thread.
- final RichInputMethodSubtype richSubtype = new RichInputMethodSubtype(subtype);
- mSubtypeSwitcher.onSubtypeChanged(richSubtype);
+ mSubtypeSwitcher.onSubtypeChanged(subtype);
mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype),
mSettings.getCurrent());
loadKeyboard();
@@ -860,6 +857,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// also wouldn't be consuming gesture data.
mGestureConsumer = GestureConsumer.NULL_GESTURE_CONSUMER;
mRichImm.clearSubtypeCaches();
+ mSubtypeSwitcher.refreshSubtypeInfo();
final KeyboardSwitcher switcher = mKeyboardSwitcher;
switcher.updateKeyboardTheme();
final MainKeyboardView mainKeyboardView = switcher.getMainKeyboardView();
@@ -1078,7 +1076,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// with cursor movement when we have a hardware keyboard since we are not in charge.
final SettingsValues settingsValues = mSettings.getCurrent();
if ((!settingsValues.mHasHardwareKeyboard || ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED)
- && mInputLogic.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd)) {
+ && mInputLogic.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,
+ settingsValues)) {
mKeyboardSwitcher.requestUpdatingShiftState(getCurrentAutoCapsState(),
getCurrentRecapitalizeState());
}
@@ -1090,7 +1089,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
if (isFullscreenMode()) {
return;
}
- mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.fromObject(info));
+ mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.wrap(info));
}
/**
@@ -1191,6 +1190,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
// no visual element will be shown on the screen.
outInsets.touchableInsets = inputHeight;
outInsets.visibleTopInsets = inputHeight;
+ mInsetsUpdater.setInsets(outInsets);
return;
}
final int suggestionsHeight = (!mKeyboardSwitcher.isShowingEmojiPalettes()
@@ -1211,6 +1211,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
outInsets.contentTopInsets = visibleTopY;
outInsets.visibleTopInsets = visibleTopY;
+ mInsetsUpdater.setInsets(outInsets);
}
public void startShowingInputView(final boolean needsToLoadKeyboard) {
@@ -1627,7 +1628,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
}
@Override
- public void showAddToDictionaryHint(final String word) {
+ public void suggestAddingToDictionary(final String word, final boolean isFromSuggestionStrip) {
if (!hasSuggestionStripView()) {
return;
}
@@ -1637,7 +1638,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} else {
wordToShow = word;
}
- mSuggestionStripView.showAddToDictionaryHint(wordToShow);
+ mSuggestionStripView.showAddToDictionaryHint(wordToShow,
+ isFromSuggestionStrip /* shouldShowWordToSave */);
}
// This will show either an empty suggestion strip (if prediction is enabled) or
diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java
index 62a258b20..a3f7bb4d6 100644
--- a/java/src/com/android/inputmethod/latin/RichInputConnection.java
+++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java
@@ -860,9 +860,10 @@ public final class RichInputConnection implements PrivateCommandPerformer {
* than it really is.
*/
public void tryFixLyingCursorPosition() {
+ mIC = mParent.getCurrentInputConnection();
final CharSequence textBeforeCursor = getTextBeforeCursor(
Constants.EDITOR_CONTENTS_CACHE_SIZE, 0);
- final CharSequence selectedText = mIC.getSelectedText(0 /* flags */);
+ final CharSequence selectedText = null == mIC ? null : mIC.getSelectedText(0 /* flags */);
if (null == textBeforeCursor ||
(!TextUtils.isEmpty(selectedText) && mExpectedSelEnd == mExpectedSelStart)) {
// If textBeforeCursor is null, we have no idea what kind of text field we have or if
diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
index 0d5ce7d6d..e6df35bea 100644
--- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
+++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java
@@ -20,6 +20,7 @@ import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE;
import android.content.Context;
import android.content.SharedPreferences;
+import android.content.res.Resources;
import android.os.Build;
import android.os.IBinder;
import android.preference.PreferenceManager;
@@ -29,6 +30,7 @@ import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
+import com.android.inputmethod.latin.settings.AdditionalFeaturesSettingUtils;
import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
@@ -50,6 +52,7 @@ public class RichInputMethodManager {
private static final RichInputMethodManager sInstance = new RichInputMethodManager();
+ private Context mContext;
private InputMethodManagerCompatWrapper mImmWrapper;
private InputMethodInfoCache mInputMethodInfoCache;
final HashMap<InputMethodInfo, List<InputMethodSubtype>>
@@ -83,6 +86,7 @@ public class RichInputMethodManager {
return;
}
mImmWrapper = new InputMethodManagerCompatWrapper(context);
+ mContext = context;
mInputMethodInfoCache = new InputMethodInfoCache(
mImmWrapper.mImm, context.getPackageName());
@@ -298,14 +302,14 @@ public class RichInputMethodManager {
return INDEX_NOT_FOUND;
}
- public RichInputMethodSubtype getCurrentInputMethodSubtype(
- final RichInputMethodSubtype defaultSubtype) {
- final InputMethodSubtype currentSubtype = mImmWrapper.mImm.getCurrentInputMethodSubtype();
- if (currentSubtype == null) {
- return defaultSubtype;
- }
- // TODO: Determine locales to use for multi-lingual use.
- return new RichInputMethodSubtype(currentSubtype);
+ public InputMethodSubtype getCurrentRawSubtype() {
+ return mImmWrapper.mImm.getCurrentInputMethodSubtype();
+ }
+
+ public RichInputMethodSubtype createCurrentRichInputMethodSubtype(
+ final InputMethodSubtype rawSubtype) {
+ return AdditionalFeaturesSettingUtils.createRichInputMethodSubtype(this, rawSubtype,
+ mContext);
}
public boolean hasMultipleEnabledIMEsOrSubtypes(final boolean shouldIncludeAuxiliarySubtypes) {
diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
index c339e96fb..6fc549549 100644
--- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java
@@ -36,7 +36,6 @@ import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
import com.android.inputmethod.keyboard.KeyboardSwitcher;
import com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper;
import com.android.inputmethod.latin.define.DebugFlags;
-import com.android.inputmethod.latin.utils.LocaleUtils;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
import java.util.HashSet;
@@ -58,6 +57,7 @@ public final class SubtypeSwitcher {
new LanguageOnSpacebarHelper();
private InputMethodInfo mShortcutInputMethodInfo;
private InputMethodSubtype mShortcutSubtype;
+ private RichInputMethodSubtype mCurrentRichInputMethodSubtype;
private RichInputMethodSubtype mNoLanguageSubtype;
private RichInputMethodSubtype mEmojiSubtype;
private boolean mIsNetworkConnected;
@@ -117,10 +117,14 @@ public final class SubtypeSwitcher {
final NetworkInfo info = connectivityManager.getActiveNetworkInfo();
mIsNetworkConnected = (info != null && info.isConnected());
- onSubtypeChanged(getCurrentSubtype());
+ refreshSubtypeInfo();
updateParametersOnStartInputView();
}
+ public void refreshSubtypeInfo() {
+ onSubtypeChanged(mRichImm.getCurrentRawSubtype());
+ }
+
/**
* Update parameters which are changed outside LatinIME. This parameters affect UI so that they
* should be updated every time onStartInputView is called.
@@ -165,12 +169,14 @@ public final class SubtypeSwitcher {
}
// Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function.
- public void onSubtypeChanged(final RichInputMethodSubtype newSubtype) {
+ public void onSubtypeChanged(final InputMethodSubtype newSubtype) {
+ final RichInputMethodSubtype richSubtype =
+ mRichImm.createCurrentRichInputMethodSubtype(newSubtype);
if (DBG) {
- Log.w(TAG, "onSubtypeChanged: " + newSubtype.getNameForLogging());
+ Log.w(TAG, "onSubtypeChanged: " + richSubtype.getNameForLogging());
}
-
- final Locale[] newLocales = newSubtype.getLocales();
+ mCurrentRichInputMethodSubtype = richSubtype;
+ final Locale[] newLocales = richSubtype.getLocales();
if (newLocales.length > 1) {
// In multi-locales mode, the system language is never the same as the input language
// because there is no single input language.
@@ -181,7 +187,7 @@ public final class SubtypeSwitcher {
final boolean sameLocale = systemLocale.equals(newLocale);
final boolean sameLanguage = systemLocale.getLanguage().equals(newLocale.getLanguage());
final boolean implicitlyEnabled = mRichImm
- .checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype.getRawSubtype());
+ .checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(newSubtype);
mLanguageOnSpacebarHelper.updateIsSystemLanguageSameAsInputLanguage(
sameLocale || (sameLanguage && implicitlyEnabled));
}
@@ -301,7 +307,7 @@ public final class SubtypeSwitcher {
if (null != sForcedSubtypeForTesting) {
return sForcedSubtypeForTesting;
}
- return mRichImm.getCurrentInputMethodSubtype(getNoLanguageSubtype());
+ return mCurrentRichInputMethodSubtype;
}
public RichInputMethodSubtype getNoLanguageSubtype() {
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index e181237a6..e6c138407 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -28,6 +28,7 @@ import com.android.inputmethod.latin.utils.StringUtils;
import com.android.inputmethod.latin.utils.SuggestionResults;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Locale;
/**
@@ -49,6 +50,16 @@ public final class Suggest {
private static final boolean DBG = DebugFlags.DEBUG_ENABLED;
private final DictionaryFacilitator mDictionaryFacilitator;
+ private static final int MAXIMUM_AUTO_CORRECT_LENGTH_FOR_GERMAN = 12;
+ private static final HashMap<String, Integer> sLanguageToMaximumAutoCorrectionWithSpaceLength =
+ new HashMap<>();
+ static {
+ // TODO: should we add Finnish here?
+ // TODO: This should not be hardcoded here but be written in the dictionary header
+ sLanguageToMaximumAutoCorrectionWithSpaceLength.put(Locale.GERMAN.getLanguage(),
+ MAXIMUM_AUTO_CORRECT_LENGTH_FOR_GERMAN);
+ }
+
private float mAutoCorrectionThreshold;
public Suggest(final DictionaryFacilitator dictionaryFacilitator) {
@@ -168,8 +179,18 @@ public final class Suggest {
// TODO: we may want to have shortcut-only entries auto-correct in the future.
hasAutoCorrection = false;
} else {
- hasAutoCorrection = AutoCorrectionUtils.suggestionExceedsAutoCorrectionThreshold(
- suggestionResults.first(), consideredWord, mAutoCorrectionThreshold);
+ final SuggestedWordInfo firstSuggestion = suggestionResults.first();
+ if (!AutoCorrectionUtils.suggestionExceedsAutoCorrectionThreshold(
+ firstSuggestion, consideredWord, mAutoCorrectionThreshold)) {
+ // Score is too low for autocorrect
+ hasAutoCorrection = false;
+ } else {
+ // We have a high score, so we need to check if this suggestion is in the correct
+ // form to allow auto-correcting to it in this language. For details of how this
+ // is determined, see #isAllowedByAutoCorrectionWithSpaceFilter.
+ // TODO: this should not have its own logic here but be handled by the dictionary.
+ hasAutoCorrection = isAllowedByAutoCorrectionWithSpaceFilter(firstSuggestion);
+ }
}
if (!TextUtils.isEmpty(typedWord)) {
@@ -287,6 +308,41 @@ public final class Suggest {
return suggestionsList;
}
+ /**
+ * Computes whether this suggestion should be blocked or not in this language
+ *
+ * This function implements a filter that avoids auto-correcting to suggestions that contain
+ * spaces that are above a certain language-dependent character limit. In languages like German
+ * where it's possible to concatenate many words, it often happens our dictionary does not
+ * have the longer words. In this case, we offer a lot of unhelpful suggestions that contain
+ * one or several spaces. Ideally we should understand what the user wants and display useful
+ * suggestions by improving the dictionary and possibly having some specific logic. Until
+ * that's possible we should avoid displaying unhelpful suggestions. But it's hard to tell
+ * whether a suggestion is useful or not. So at least for the time being we block
+ * auto-correction when the suggestion is long and contains a space, which should avoid the
+ * worst damage.
+ * This function is implementing that filter. If the language enforces no such limit, then it
+ * always returns true. If the suggestion contains no space, it also returns true. Otherwise,
+ * it checks the length against the language-specific limit.
+ *
+ * @param info the suggestion info
+ * @return whether it's fine to auto-correct to this.
+ */
+ private boolean isAllowedByAutoCorrectionWithSpaceFilter(final SuggestedWordInfo info) {
+ final Locale locale = info.mSourceDict.mLocale;
+ if (null == locale) {
+ return true;
+ }
+ final Integer maximumLengthForThisLanguage =
+ sLanguageToMaximumAutoCorrectionWithSpaceLength.get(locale.getLanguage());
+ if (null == maximumLengthForThisLanguage) {
+ // This language does not enforce a maximum length to auto-correction
+ return true;
+ }
+ return info.mWord.length() <= maximumLengthForThisLanguage
+ || -1 == info.mWord.indexOf(Constants.CODE_SPACE);
+ }
+
/* package for test */ static SuggestedWordInfo getTransformedSuggestedWordInfo(
final SuggestedWordInfo wordInfo, final Locale locale, final boolean isAllUpperCase,
final boolean isOnlyFirstCharCapitalized, final int trailingSingleQuotesCount) {
diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java
index 466576465..e5bf25d5f 100644
--- a/java/src/com/android/inputmethod/latin/SuggestedWords.java
+++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java
@@ -243,7 +243,8 @@ public class SuggestedWords {
return candidate.isEligibleForAutoCommit() ? candidate : null;
}
- public static final class SuggestedWordInfo {
+ // non-final for testability.
+ public static class SuggestedWordInfo {
public static final int NOT_AN_INDEX = -1;
public static final int NOT_A_CONFIDENCE = -1;
public static final int MAX_SCORE = Integer.MAX_VALUE;
@@ -413,28 +414,6 @@ public class SuggestedWords {
return isPrediction(mInputStyle);
}
- // SuggestedWords is an immutable object, as much as possible. We must not just remove
- // words from the member ArrayList as some other parties may expect the object to never change.
- // This is only ever called by recorrection at the moment, hence the ForRecorrection moniker.
- public SuggestedWords getSuggestedWordsExcludingTypedWordForRecorrection() {
- final ArrayList<SuggestedWordInfo> newSuggestions = new ArrayList<>();
- String typedWord = null;
- for (int i = 0; i < mSuggestedWordInfoList.size(); ++i) {
- final SuggestedWordInfo info = mSuggestedWordInfoList.get(i);
- if (!info.isKindOf(SuggestedWordInfo.KIND_TYPED)) {
- newSuggestions.add(info);
- } else {
- assert(null == typedWord);
- typedWord = info.mWord;
- }
- }
- // We should never autocorrect, so we say the typed word is valid. Also, in this case,
- // no auto-correction should take place hence willAutoCorrect = false.
- return new SuggestedWords(newSuggestions, null /* rawSuggestions */, typedWord,
- true /* typedWordValid */, false /* willAutoCorrect */, mIsObsoleteSuggestions,
- SuggestedWords.INPUT_STYLE_RECORRECTION, NOT_A_SEQUENCE_NUMBER);
- }
-
// Creates a new SuggestedWordInfo from the currently suggested words that removes all but the
// last word of all suggestions, separated by a space. This is necessary because when we commit
// a multiple-word suggestion, the IME only retains the last word as the composing word, and
diff --git a/java/src/com/android/inputmethod/latin/accounts/AccountsChangedReceiver.java b/java/src/com/android/inputmethod/latin/accounts/AccountsChangedReceiver.java
index 9445ce4c3..00bcecf52 100644
--- a/java/src/com/android/inputmethod/latin/accounts/AccountsChangedReceiver.java
+++ b/java/src/com/android/inputmethod/latin/accounts/AccountsChangedReceiver.java
@@ -26,7 +26,7 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.inputmethod.annotations.UsedForTesting;
-import com.android.inputmethod.latin.settings.Settings;
+import com.android.inputmethod.latin.settings.LocalSettingsConstants;
/**
* {@link BroadcastReceiver} for {@link AccountManager#LOGIN_ACCOUNTS_CHANGED_ACTION}.
@@ -41,25 +41,14 @@ public class AccountsChangedReceiver extends BroadcastReceiver {
return;
}
+ // Ideally the account preference could live in a different preferences file
+ // that wasn't being backed up and restored, however the preference fragments
+ // currently only deal with the default shared preferences which is why
+ // separating this out into a different file is not trivial currently.
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
- final String currentAccount = prefs.getString(Settings.PREF_ACCOUNT_NAME, null);
- if (currentAccount != null) {
- final String[] accounts = getAccountsForLogin(context);
- boolean accountFound = false;
- for (String account : accounts) {
- if (TextUtils.equals(currentAccount, account)) {
- accountFound = true;
- break;
- }
- }
- // The current account was not found in the list of accounts, remove it.
- if (!accountFound) {
- Log.i(TAG, "The current account was removed from the system: " + currentAccount);
- prefs.edit()
- .remove(Settings.PREF_ACCOUNT_NAME)
- .apply();
- }
- }
+ final String currentAccount = prefs.getString(
+ LocalSettingsConstants.PREF_ACCOUNT_NAME, null);
+ removeUnknownAccountFromPreference(prefs, getAccountsForLogin(context), currentAccount);
}
/**
@@ -69,4 +58,24 @@ public class AccountsChangedReceiver extends BroadcastReceiver {
protected String[] getAccountsForLogin(Context context) {
return LoginAccountUtils.getAccountsForLogin(context);
}
+
+ /**
+ * Removes the currentAccount from preferences if it's not found
+ * in the list of current accounts.
+ */
+ private static void removeUnknownAccountFromPreference(final SharedPreferences prefs,
+ final String[] accounts, final String currentAccount) {
+ if (currentAccount == null) {
+ return;
+ }
+ for (final String account : accounts) {
+ if (TextUtils.equals(currentAccount, account)) {
+ return;
+ }
+ }
+ Log.i(TAG, "The current account was removed from the system: " + currentAccount);
+ prefs.edit()
+ .remove(LocalSettingsConstants.PREF_ACCOUNT_NAME)
+ .apply();
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index 07f2ed3db..5cc61db79 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -305,6 +305,7 @@ public final class InputLogic {
currentKeyboardScriptId, handler);
}
+ mDictionaryFacilitator.switchMostProbableLanguage(suggestionInfo.mSourceDict.mLocale);
final Event event = Event.createSuggestionPickedEvent(suggestionInfo);
final InputTransaction inputTransaction = new InputTransaction(settingsValues,
event, SystemClock.uptimeMillis(), mSpaceState, keyboardShiftState);
@@ -348,7 +349,8 @@ public final class InputLogic {
inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW);
if (shouldShowAddToDictionaryHint) {
- mSuggestionStripViewAccessor.showAddToDictionaryHint(suggestion);
+ mSuggestionStripViewAccessor.suggestAddingToDictionary(suggestion,
+ true /* isFromSuggestionStrip */);
} else {
// If we're not showing the "Touch again to save", then update the suggestion strip.
// That's going to be predictions (or punctuation suggestions), so INPUT_STYLE_NONE.
@@ -369,10 +371,11 @@ public final class InputLogic {
* @param oldSelEnd old selection end
* @param newSelStart new selection start
* @param newSelEnd new selection end
+ * @param settingsValues the current values of the settings.
* @return whether the cursor has moved as a result of user interaction.
*/
public boolean onUpdateSelection(final int oldSelStart, final int oldSelEnd,
- final int newSelStart, final int newSelEnd) {
+ final int newSelStart, final int newSelEnd, final SettingsValues settingsValues) {
if (mConnection.isBelatedExpectedUpdate(oldSelStart, newSelStart, oldSelEnd, newSelEnd)) {
return false;
}
@@ -397,8 +400,9 @@ public final class InputLogic {
// should be true, but that is if the framework had taken that wrong cursor position
// into account, which means we have to reset the entire composing state whenever there
// is or was a selection regardless of whether it changed or not.
- if (hasOrHadSelection || (selectionChangedOrSafeToReset
- && !mWordComposer.moveCursorByAndReturnIfInsideComposingWord(moveAmount))) {
+ if (hasOrHadSelection || !settingsValues.needsToLookupSuggestions()
+ || (selectionChangedOrSafeToReset
+ && !mWordComposer.moveCursorByAndReturnIfInsideComposingWord(moveAmount))) {
// If we are composing a word and moving the cursor, we would want to set a
// suggestion span for recorrection to work correctly. Unfortunately, that
// would involve the keyboard committing some new text, which would move the
@@ -1484,6 +1488,11 @@ public final class InputLogic {
if (numberOfCharsInWordBeforeCursor > expectedCursorPosition) return;
final ArrayList<SuggestedWordInfo> suggestions = new ArrayList<>();
final String typedWord = range.mWord.toString();
+ suggestions.add(new SuggestedWordInfo(typedWord,
+ SuggestedWords.MAX_SUGGESTIONS + 1,
+ SuggestedWordInfo.KIND_TYPED, Dictionary.DICTIONARY_USER_TYPED,
+ SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
+ SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
if (!isResumableWord(settingsValues, typedWord)) {
mSuggestionStripViewAccessor.setNeutralSuggestionStrip();
return;
@@ -1516,30 +1525,14 @@ public final class InputLogic {
mConnection.maybeMoveTheCursorAroundAndRestoreToWorkaroundABug();
mConnection.setComposingRegion(expectedCursorPosition - numberOfCharsInWordBeforeCursor,
expectedCursorPosition + range.getNumberOfCharsInWordAfterCursor());
- if (suggestions.size() <= 0) {
+ if (suggestions.size() <= 1) {
// If there weren't any suggestion spans on this word, suggestions#size() will be 1
// if shouldIncludeResumedWordInSuggestions is true, 0 otherwise. In this case, we
// have no useful suggestions, so we will try to compute some for it instead.
mInputLogicHandler.getSuggestedWords(Suggest.SESSION_ID_TYPING,
SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() {
@Override
- public void onGetSuggestedWords(
- final SuggestedWords suggestedWordsIncludingTypedWord) {
- final SuggestedWords suggestedWords;
- if (suggestedWordsIncludingTypedWord.size() > 1) {
- // We were able to compute new suggestions for this word.
- // Remove the typed word, since we don't want to display it in this
- // case. The #getSuggestedWordsExcludingTypedWordForRecorrection()
- // method sets willAutoCorrect to false.
- suggestedWords = suggestedWordsIncludingTypedWord
- .getSuggestedWordsExcludingTypedWordForRecorrection();
- } else {
- // No saved suggestions, and we were unable to compute any good one
- // either. Rather than displaying an empty suggestion strip, we'll
- // display the original word alone in the middle.
- // Since there is only one word, willAutoCorrect is false.
- suggestedWords = suggestedWordsIncludingTypedWord;
- }
+ public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
mIsAutoCorrectionIndicatorOn = false;
mLatinIME.mHandler.showSuggestionStrip(suggestedWords);
}});
@@ -1683,7 +1676,8 @@ public final class InputLogic {
mConnection.getExpectedSelectionStart(),
mConnection.getExpectedSelectionEnd());
}
- mSuggestionStripViewAccessor.showAddToDictionaryHint(originallyTypedWordString);
+ mSuggestionStripViewAccessor.suggestAddingToDictionary(originallyTypedWordString,
+ false /* isFromSuggestionStrip */);
} else {
// We have a separator between the word and the cursor: we should show predictions.
inputTransaction.setRequiresUpdateSuggestions();
@@ -2100,6 +2094,10 @@ public final class InputLogic {
final boolean isBatchMode = mWordComposer.isBatchMode();
commitChosenWord(settingsValues, stringToCommit,
LastComposedWord.COMMIT_TYPE_DECIDED_WORD, separator);
+ if (null != autoCorrectionOrNull) {
+ mDictionaryFacilitator.switchMostProbableLanguage(
+ autoCorrectionOrNull.mSourceDict.mLocale);
+ }
if (!typedWord.equals(stringToCommit)) {
// This will make the correction flash for a short while as a visual clue
// to the user that auto-correction happened. It has no other effect; in particular
diff --git a/java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java b/java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java
index fa7c2c417..644818ba6 100644
--- a/java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java
+++ b/java/src/com/android/inputmethod/latin/makedict/DictionaryHeader.java
@@ -40,8 +40,9 @@ public final class DictionaryHeader {
public static final String USES_FORGETTING_CURVE_KEY = "USES_FORGETTING_CURVE";
public static final String FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID_KEY =
"FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID";
- public static final String MAX_UNIGRAM_COUNT_KEY = "MAX_UNIGRAM_COUNT";
- public static final String MAX_BIGRAM_COUNT_KEY = "MAX_BIGRAM_COUNT";
+ public static final String MAX_UNIGRAM_COUNT_KEY = "MAX_UNIGRAM_ENTRY_COUNT";
+ public static final String MAX_BIGRAM_COUNT_KEY = "MAX_BIGRAM_ENTRY_COUNT";
+ public static final String MAX_TRIGRAM_COUNT_KEY = "MAX_TRIGRAM_ENTRY_COUNT";
public static final String ATTRIBUTE_VALUE_TRUE = "1";
public static final String CODE_POINT_TABLE_KEY = "codePointTable";
diff --git a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java
index a180d060e..1e6cadf03 100644
--- a/java/src/com/android/inputmethod/latin/makedict/WordProperty.java
+++ b/java/src/com/android/inputmethod/latin/makedict/WordProperty.java
@@ -26,6 +26,8 @@ import com.android.inputmethod.latin.utils.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
+import javax.annotation.Nullable;
+
/**
* Utility class for a word with a probability.
*
@@ -49,7 +51,7 @@ public final class WordProperty implements Comparable<WordProperty> {
@UsedForTesting
public WordProperty(final String word, final ProbabilityInfo probabilityInfo,
final ArrayList<WeightedString> shortcutTargets,
- final ArrayList<WeightedString> bigrams,
+ @Nullable final ArrayList<WeightedString> bigrams,
final boolean isNotAWord, final boolean isBlacklistEntry) {
mWord = word;
mProbabilityInfo = probabilityInfo;
@@ -85,7 +87,9 @@ public final class WordProperty implements Comparable<WordProperty> {
public WordProperty(final int[] codePoints, final boolean isNotAWord,
final boolean isBlacklisted, final boolean hasBigram, final boolean hasShortcuts,
final boolean isBeginningOfSentence, final int[] probabilityInfo,
- final ArrayList<int[]> bigramTargets, final ArrayList<int[]> bigramProbabilityInfo,
+ final ArrayList<int[][]> ngramPrevWordsArray,
+ final ArrayList<boolean[]> outNgramPrevWordIsBeginningOfSentenceArray,
+ final ArrayList<int[]> ngramTargets, final ArrayList<int[]> ngramProbabilityInfo,
final ArrayList<int[]> shortcutTargets,
final ArrayList<Integer> shortcutProbabilities) {
mWord = StringUtils.getStringFromNullTerminatedCodePointArray(codePoints);
@@ -98,15 +102,15 @@ public final class WordProperty implements Comparable<WordProperty> {
mHasShortcuts = hasShortcuts;
mHasNgrams = hasBigram;
- final int relatedNgramCount = bigramTargets.size();
+ final int relatedNgramCount = ngramTargets.size();
final WordInfo currentWordInfo =
mIsBeginningOfSentence ? WordInfo.BEGINNING_OF_SENTENCE : new WordInfo(mWord);
final NgramContext ngramContext = new NgramContext(currentWordInfo);
for (int i = 0; i < relatedNgramCount; i++) {
final String ngramTargetString =
- StringUtils.getStringFromNullTerminatedCodePointArray(bigramTargets.get(i));
+ StringUtils.getStringFromNullTerminatedCodePointArray(ngramTargets.get(i));
final WeightedString ngramTarget = new WeightedString(ngramTargetString,
- createProbabilityInfoFromArray(bigramProbabilityInfo.get(i)));
+ createProbabilityInfoFromArray(ngramProbabilityInfo.get(i)));
// TODO: Support n-gram.
ngrams.add(new NgramProperty(ngramTarget, ngramContext));
}
@@ -180,7 +184,8 @@ public final class WordProperty implements Comparable<WordProperty> {
&& mHasNgrams == w.mHasNgrams && mHasShortcuts && w.mHasNgrams;
}
- private <T> boolean equals(final ArrayList<T> a, final ArrayList<T> b) {
+ // TDOO: Have a utility method like java.util.Objects.equals.
+ private static <T> boolean equals(final ArrayList<T> a, final ArrayList<T> b) {
if (null == a) {
return null == b;
}
diff --git a/java/src/com/android/inputmethod/latin/network/AuthException.java b/java/src/com/android/inputmethod/latin/network/AuthException.java
new file mode 100644
index 000000000..1bce4c156
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/network/AuthException.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.network;
+
+/**
+ * Authentication exception. When this exception is thrown, the client may
+ * try to refresh the authentication token and try again.
+ */
+public class AuthException extends Exception {
+ public AuthException() {
+ super();
+ }
+
+ public AuthException(Throwable throwable) {
+ super(throwable);
+ }
+
+ public AuthException(String detailMessage) {
+ super(detailMessage);
+ }
+} \ No newline at end of file
diff --git a/java/src/com/android/inputmethod/latin/network/BlockingHttpClient.java b/java/src/com/android/inputmethod/latin/network/BlockingHttpClient.java
index 0d0cbe169..e2d24fd0a 100644
--- a/java/src/com/android/inputmethod/latin/network/BlockingHttpClient.java
+++ b/java/src/com/android/inputmethod/latin/network/BlockingHttpClient.java
@@ -16,7 +16,7 @@
package com.android.inputmethod.latin.network;
-import com.android.inputmethod.annotations.UsedForTesting;
+import android.util.Log;
import java.io.BufferedOutputStream;
import java.io.IOException;
@@ -30,25 +30,17 @@ import javax.annotation.Nullable;
/**
* A client for executing HTTP requests synchronously.
* This must never be called from the main thread.
- *
- * TODO: Remove @UsedForTesting after this is actually used.
*/
-@UsedForTesting
public class BlockingHttpClient {
+ private static final boolean DEBUG = false;
+ private static final String TAG = BlockingHttpClient.class.getSimpleName();
+
private final HttpURLConnection mConnection;
/**
* Interface that handles processing the response for a request.
*/
- public interface ResponseProcessor {
- /**
- * Called when the HTTP request fails with an error.
- *
- * @param httpStatusCode The status code of the HTTP response.
- * @param message The HTTP response message, if any, or null.
- */
- void onError(int httpStatusCode, @Nullable String message);
-
+ public interface ResponseProcessor<T> {
/**
* Called when the HTTP request finishes successfully.
* The {@link InputStream} is closed by the client after the method finishes,
@@ -56,13 +48,9 @@ public class BlockingHttpClient {
*
* @param response An input stream that can be used to read the HTTP response.
*/
- void onSuccess(InputStream response);
+ T onSuccess(InputStream response) throws IOException;
}
- /**
- * TODO: Remove @UsedForTesting after this is actually used.
- */
- @UsedForTesting
public BlockingHttpClient(HttpURLConnection connection) {
mConnection = connection;
}
@@ -70,16 +58,19 @@ public class BlockingHttpClient {
/**
* Executes the request on the underlying {@link HttpURLConnection}.
*
- * TODO: Remove @UsedForTesting after this is actually used.
- *
* @param request The request payload, if any, or null.
- * @param responeProcessor A processor for the HTTP response.
+ * @param responseProcessor A processor for the HTTP response.
*/
- @UsedForTesting
- public void execute(@Nullable byte[] request, @Nonnull ResponseProcessor responseProcessor)
- throws IOException {
+ public <T> T execute(@Nullable byte[] request, @Nonnull ResponseProcessor<T> responseProcessor)
+ throws IOException, AuthException, HttpException {
+ if (DEBUG) {
+ Log.d(TAG, "execute: " + mConnection.getURL());
+ }
try {
if (request != null) {
+ if (DEBUG) {
+ Log.d(TAG, "request size: " + request.length);
+ }
OutputStream out = new BufferedOutputStream(mConnection.getOutputStream());
out.write(request);
out.flush();
@@ -88,9 +79,17 @@ public class BlockingHttpClient {
final int responseCode = mConnection.getResponseCode();
if (responseCode != HttpURLConnection.HTTP_OK) {
- responseProcessor.onError(responseCode, mConnection.getResponseMessage());
+ Log.w(TAG, "Response error: " + responseCode + ", Message: "
+ + mConnection.getResponseMessage());
+ if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
+ throw new AuthException(mConnection.getResponseMessage());
+ }
+ throw new HttpException(responseCode);
} else {
- responseProcessor.onSuccess(mConnection.getInputStream());
+ if (DEBUG) {
+ Log.d(TAG, "request executed successfully");
+ }
+ return responseProcessor.onSuccess(mConnection.getInputStream());
}
} finally {
mConnection.disconnect();
diff --git a/java/src/com/android/inputmethod/latin/network/HttpException.java b/java/src/com/android/inputmethod/latin/network/HttpException.java
new file mode 100644
index 000000000..b9d8b6372
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/network/HttpException.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.network;
+
+import com.android.inputmethod.annotations.UsedForTesting;
+
+/**
+ * The HttpException exception represents a XML/HTTP fault with a HTTP status code.
+ */
+public class HttpException extends Exception {
+
+ /**
+ * The HTTP status code.
+ */
+ private final int mStatusCode;
+
+ /**
+ * @param statusCode int HTTP status code.
+ */
+ public HttpException(int statusCode) {
+ super("Response Code: " + statusCode);
+ mStatusCode = statusCode;
+ }
+
+ /**
+ * @return the HTTP status code related to this exception.
+ */
+ @UsedForTesting
+ public int getHttpStatusCode() {
+ return mStatusCode;
+ }
+} \ No newline at end of file
diff --git a/java/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilder.java b/java/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilder.java
index 35b65be56..502f72f17 100644
--- a/java/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilder.java
+++ b/java/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilder.java
@@ -37,6 +37,11 @@ public class HttpUrlConnectionBuilder {
private static final int DEFAULT_TIMEOUT_MILLIS = 5 * 1000;
/**
+ * Request header key for authentication.
+ */
+ public static final String HTTP_HEADER_AUTHORIZATION = "Authorization";
+
+ /**
* Request header key for cache control.
*/
public static final String KEY_CACHE_CONTROL = "Cache-Control";
@@ -78,7 +83,7 @@ public class HttpUrlConnectionBuilder {
* Sets the URL that'll be used for the request.
* This *must* be set before calling {@link #build()}
*
- * TODO: Remove @UsedForTesting after this is actually used.
+ * TODO: Remove @UsedForTesting after this method is actually used.
*/
@UsedForTesting
public HttpUrlConnectionBuilder setUrl(String url) throws MalformedURLException {
@@ -92,7 +97,7 @@ public class HttpUrlConnectionBuilder {
/**
* Sets the connect timeout. Defaults to {@value #DEFAULT_TIMEOUT} milliseconds.
*
- * TODO: Remove @UsedForTesting after this is actually used.
+ * TODO: Remove @UsedForTesting after this method is actually used.
*/
@UsedForTesting
public HttpUrlConnectionBuilder setConnectTimeout(int timeoutMillis) {
@@ -107,7 +112,7 @@ public class HttpUrlConnectionBuilder {
/**
* Sets the read timeout. Defaults to {@value #DEFAULT_TIMEOUT} milliseconds.
*
- * TODO: Remove @UsedForTesting after this is actually used.
+ * TODO: Remove @UsedForTesting after this method is actually used.
*/
@UsedForTesting
public HttpUrlConnectionBuilder setReadTimeout(int timeoutMillis) {
@@ -122,7 +127,7 @@ public class HttpUrlConnectionBuilder {
/**
* Adds an entry to the request header.
*
- * TODO: Remove @UsedForTesting after this is actually used.
+ * TODO: Remove @UsedForTesting after this method is actually used.
*/
@UsedForTesting
public HttpUrlConnectionBuilder addHeader(String key, String value) {
@@ -131,10 +136,21 @@ public class HttpUrlConnectionBuilder {
}
/**
+ * Sets an authentication token.
+ *
+ * TODO: Remove @UsedForTesting after this method is actually used.
+ */
+ @UsedForTesting
+ public HttpUrlConnectionBuilder setAuthToken(String value) {
+ mHeaderMap.put(HTTP_HEADER_AUTHORIZATION, value);
+ return this;
+ }
+
+ /**
* Sets the request to be executed such that the input is not buffered.
* This may be set when the request size is known beforehand.
*
- * TODO: Remove @UsedForTesting after this is actually used.
+ * TODO: Remove @UsedForTesting after this method is actually used.
*/
@UsedForTesting
public HttpUrlConnectionBuilder setFixedLengthForStreaming(int length) {
@@ -145,7 +161,7 @@ public class HttpUrlConnectionBuilder {
/**
* Indicates if the request can use cached responses or not.
*
- * TODO: Remove @UsedForTesting after this is actually used.
+ * TODO: Remove @UsedForTesting after this method is actually used.
*/
@UsedForTesting
public HttpUrlConnectionBuilder setUseCache(boolean useCache) {
@@ -161,7 +177,7 @@ public class HttpUrlConnectionBuilder {
* @see #MODE_DOWNLOAD_ONLY
* @see #MODE_BI_DIRECTIONAL
*
- * TODO: Remove @UsedForTesting after this is actually used.
+ * TODO: Remove @UsedForTesting after this method is actually used
*/
@UsedForTesting
public HttpUrlConnectionBuilder setMode(int mode) {
@@ -177,7 +193,7 @@ public class HttpUrlConnectionBuilder {
/**
* Builds the {@link HttpURLConnection} instance that can be used to execute the request.
*
- * TODO: Remove @UsedForTesting after this is actually used.
+ * TODO: Remove @UsedForTesting after this method is actually used.
*/
@UsedForTesting
public HttpURLConnection build() throws IOException {
@@ -210,4 +226,4 @@ public class HttpUrlConnectionBuilder {
}
return connection;
}
-}
+} \ No newline at end of file
diff --git a/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java
index 32880038f..4bd15d037 100644
--- a/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/AccountsSettingsFragment.java
@@ -16,6 +16,9 @@
package com.android.inputmethod.latin.settings;
+import static com.android.inputmethod.latin.settings.LocalSettingsConstants.PREF_ACCOUNT_NAME;
+import static com.android.inputmethod.latin.settings.LocalSettingsConstants.PREF_ENABLE_CLOUD_SYNC;
+
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
@@ -32,8 +35,8 @@ import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.SubtypeSwitcher;
import com.android.inputmethod.latin.accounts.LoginAccountUtils;
+import com.android.inputmethod.latin.accounts.AccountStateChangedListener;
import com.android.inputmethod.latin.define.ProductionFlags;
-import com.android.inputmethod.latin.sync.BeanstalkManager;
import javax.annotation.Nullable;
@@ -41,19 +44,17 @@ import javax.annotation.Nullable;
* "Accounts & Privacy" settings sub screen.
*
* This settings sub screen handles the following preferences:
- * <li> Account selection/management for IME
- * <li> TODO: Sync preferences
- * <li> TODO: Privacy preferences
- * <li> Sync now
+ * <li> Account selection/management for IME </li>
+ * <li> Sync preferences </li>
+ * <li> Privacy preferences </li>
*/
public final class AccountsSettingsFragment extends SubScreenFragment {
+ private static final String PREF_SYNC_NOW = "pref_beanstalk";
+
static final String PREF_ACCCOUNT_SWITCHER = "account_switcher";
- static final String PREF_SYNC_NOW = "pref_beanstalk";
- private final DialogInterface.OnClickListener mAccountSelectedListener =
- new AccountSelectedListener();
- private final DialogInterface.OnClickListener mAccountSignedOutListener =
- new AccountSignedOutListener();
+ private final DialogInterface.OnClickListener mAccountChangedListener =
+ new AccountChangedListener();
private final Preference.OnPreferenceClickListener mSyncNowListener = new SyncNowListener();
@Override
@@ -81,47 +82,56 @@ public final class AccountsSettingsFragment extends SubScreenFragment {
removePreference(Settings.PREF_ENABLE_METRICS_LOGGING);
}
+ if (!ProductionFlags.ENABLE_ACCOUNT_SIGN_IN) {
+ removePreference(PREF_ACCCOUNT_SWITCHER);
+ removePreference(PREF_ENABLE_CLOUD_SYNC);
+ removePreference(PREF_SYNC_NOW);
+ }
if (!ProductionFlags.ENABLE_PERSONAL_DICTIONARY_SYNC) {
+ removePreference(PREF_ENABLE_CLOUD_SYNC);
removePreference(PREF_SYNC_NOW);
} else {
final Preference syncNowPreference = findPreference(PREF_SYNC_NOW);
- if (syncNowPreference != null) {
- syncNowPreference.setOnPreferenceClickListener(mSyncNowListener);
- }
+ syncNowPreference.setOnPreferenceClickListener(mSyncNowListener);
}
}
@Override
public void onResume() {
super.onResume();
- refreshUi();
+ refreshAccountAndDependentPreferences(getSignedInAccountName());
}
@Override
public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
- // TODO: Look at the preference that changed before refreshing the view.
- refreshUi();
- }
-
- private void refreshUi() {
- refreshAccountSelection();
- refreshSyncNow();
+ if (TextUtils.equals(key, PREF_ACCOUNT_NAME)) {
+ refreshAccountAndDependentPreferences(
+ prefs.getString(PREF_ACCOUNT_NAME, null));
+ } else if (TextUtils.equals(key, PREF_ENABLE_CLOUD_SYNC)) {
+ final boolean syncEnabled = prefs.getBoolean(PREF_ENABLE_CLOUD_SYNC, false);
+ AccountStateChangedListener.onSyncPreferenceChanged(
+ getSignedInAccountName(), syncEnabled);
+ }
}
- private void refreshAccountSelection() {
+ private void refreshAccountAndDependentPreferences(@Nullable final String currentAccount) {
if (!ProductionFlags.ENABLE_ACCOUNT_SIGN_IN) {
return;
}
- final String currentAccount = getCurrentlySelectedAccount();
final Preference accountSwitcher = findPreference(PREF_ACCCOUNT_SWITCHER);
if (currentAccount == null) {
// No account is currently selected.
accountSwitcher.setSummary(getString(R.string.no_accounts_selected));
+ // Disable the sync preference UI.
+ disableSyncPreference();
} else {
// Set the currently selected account.
accountSwitcher.setSummary(getString(R.string.account_selected, currentAccount));
+ // Enable the sync preference UI.
+ enableSyncPreference();
}
+ // Set up onClick listener for the account picker preference.
final Context context = getActivity();
final String[] accountsForLogin = LoginAccountUtils.getAccountsForLogin(context);
accountSwitcher.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@@ -129,45 +139,50 @@ public final class AccountsSettingsFragment extends SubScreenFragment {
public boolean onPreferenceClick(Preference preference) {
if (accountsForLogin.length == 0) {
// TODO: Handle account addition.
- Toast.makeText(getActivity(),
- getString(R.string.account_select_cancel), Toast.LENGTH_SHORT).show();
+ Toast.makeText(getActivity(), getString(R.string.account_select_cancel),
+ Toast.LENGTH_SHORT).show();
} else {
createAccountPicker(accountsForLogin, currentAccount).show();
}
return true;
}
});
-
- // TODO: Depending on the account selection, enable/disable preferences that
- // depend on an account.
}
/**
- * Refreshes the "Sync Now" feature
+ * Enables the Sync preference UI and updates its summary.
*/
- private void refreshSyncNow() {
+ private void enableSyncPreference() {
if (!ProductionFlags.ENABLE_PERSONAL_DICTIONARY_SYNC) {
return;
}
- final Preference syncNowPreference = findPreference(PREF_SYNC_NOW);
- if (syncNowPreference == null) {
+ final Preference syncPreference = findPreference(PREF_ENABLE_CLOUD_SYNC);
+ syncPreference.setEnabled(true);
+ syncPreference.setSummary(R.string.cloud_sync_summary);
+ }
+
+ /**
+ * Disables the Sync preference UI and updates its summary to indicate
+ * the fact that an account needs to be selected for sync.
+ */
+ private void disableSyncPreference() {
+ if (!ProductionFlags.ENABLE_PERSONAL_DICTIONARY_SYNC) {
return;
}
- final String currentAccount = getCurrentlySelectedAccount();
- if (currentAccount == null) {
- syncNowPreference.setEnabled(false);
- syncNowPreference.setSummary(R.string.sync_now_summary);
- } else {
- syncNowPreference.setEnabled(true);
- syncNowPreference.setSummary(R.string.sync_now_summary_disabled_signed_out);
- }
+ final Preference syncPreference = findPreference(PREF_ENABLE_CLOUD_SYNC);
+ syncPreference.setEnabled(false);
+ syncPreference.setSummary(R.string.cloud_sync_summary_disabled_signed_out);
}
@Nullable
- private String getCurrentlySelectedAccount() {
- return getSharedPreferences().getString(Settings.PREF_ACCOUNT_NAME, null);
+ String getSignedInAccountName() {
+ return getSharedPreferences().getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, null);
+ }
+
+ boolean isSyncEnabled() {
+ return getSharedPreferences().getBoolean(PREF_ENABLE_CLOUD_SYNC, false);
}
/**
@@ -200,51 +215,51 @@ public final class AccountsSettingsFragment extends SubScreenFragment {
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
.setTitle(R.string.account_select_title)
.setSingleChoiceItems(accounts, index, null)
- .setPositiveButton(R.string.account_select_ok, mAccountSelectedListener)
+ .setPositiveButton(R.string.account_select_ok, mAccountChangedListener)
.setNegativeButton(R.string.account_select_cancel, null);
if (isSignedIn) {
- builder.setNeutralButton(R.string.account_select_sign_out, mAccountSignedOutListener);
+ builder.setNeutralButton(R.string.account_select_sign_out, mAccountChangedListener);
}
return builder.create();
}
/**
- * Listener for an account being selected from the picker.
- * Persists the account to shared preferences.
- */
- class AccountSelectedListener implements DialogInterface.OnClickListener {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- final ListView lv = ((AlertDialog)dialog).getListView();
- final Object selectedItem = lv.getItemAtPosition(lv.getCheckedItemPosition());
- getSharedPreferences()
- .edit()
- .putString(Settings.PREF_ACCOUNT_NAME, (String) selectedItem)
- .apply();
- }
- }
-
- /**
- * Listener for sign-out being initiated from from the picker.
- * Removed the account from shared preferences.
+ * Listener for a account selection changes from the picker.
+ * Persists/removes the account to/from shared preferences and sets up sync if required.
*/
- class AccountSignedOutListener implements DialogInterface.OnClickListener {
+ class AccountChangedListener implements DialogInterface.OnClickListener {
@Override
public void onClick(DialogInterface dialog, int which) {
- getSharedPreferences()
- .edit()
- .remove(Settings.PREF_ACCOUNT_NAME)
- .apply();
+ final String oldAccount = getSignedInAccountName();
+ switch (which) {
+ case DialogInterface.BUTTON_POSITIVE: // Signed in
+ final ListView lv = ((AlertDialog)dialog).getListView();
+ final String newAccount =
+ (String) lv.getItemAtPosition(lv.getCheckedItemPosition());
+ getSharedPreferences()
+ .edit()
+ .putString(PREF_ACCOUNT_NAME, newAccount)
+ .apply();
+ AccountStateChangedListener.onAccountSignedIn(oldAccount, newAccount);
+ break;
+ case DialogInterface.BUTTON_NEUTRAL: // Signed out
+ AccountStateChangedListener.onAccountSignedOut(oldAccount);
+ getSharedPreferences()
+ .edit()
+ .remove(PREF_ACCOUNT_NAME)
+ .apply();
+ break;
+ }
}
}
/**
- * Listener that initates the process of sync in the background.
+ * Listener that initiates the process of sync in the background.
*/
class SyncNowListener implements Preference.OnPreferenceClickListener {
@Override
public boolean onPreferenceClick(final Preference preference) {
- BeanstalkManager.getInstance(getActivity() /* context */).requestSync();
+ AccountStateChangedListener.forceSync(getSignedInAccountName());
return true;
}
}
diff --git a/java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java
index 3303ab093..d2c9dbbe9 100644
--- a/java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/AdvancedSettingsFragment.java
@@ -113,6 +113,7 @@ public final class AdvancedSettingsFragment extends SubScreenFragment {
setupKeypressVibrationDurationSettings();
setupKeypressSoundVolumeSettings();
+ setupKeyLongpressTimeoutSettings();
refreshEnablingsOfKeypressSoundAndVibrationSettings();
}
@@ -249,4 +250,43 @@ public final class AdvancedSettingsFragment extends SubScreenFragment {
}
});
}
+
+ private void setupKeyLongpressTimeoutSettings() {
+ final SharedPreferences prefs = getSharedPreferences();
+ final Resources res = getResources();
+ final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
+ Settings.PREF_KEY_LONGPRESS_TIMEOUT);
+ if (pref == null) {
+ return;
+ }
+ pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
+ @Override
+ public void writeValue(final int value, final String key) {
+ prefs.edit().putInt(key, value).apply();
+ }
+
+ @Override
+ public void writeDefaultValue(final String key) {
+ prefs.edit().remove(key).apply();
+ }
+
+ @Override
+ public int readValue(final String key) {
+ return Settings.readKeyLongpressTimeout(prefs, res);
+ }
+
+ @Override
+ public int readDefaultValue(final String key) {
+ return Settings.readDefaultKeyLongpressTimeout(res);
+ }
+
+ @Override
+ public String getValueText(final int value) {
+ return res.getString(R.string.abbreviation_unit_milliseconds, value);
+ }
+
+ @Override
+ public void feedbackValue(final int value) {}
+ });
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/settings/CustomInputStylePreference.java b/java/src/com/android/inputmethod/latin/settings/CustomInputStylePreference.java
new file mode 100644
index 000000000..c07b60a0b
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/CustomInputStylePreference.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.settings;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.preference.DialogPreference;
+import android.preference.Preference;
+import android.util.Log;
+import android.view.View;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
+
+import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
+import com.android.inputmethod.compat.ViewCompatUtils;
+import com.android.inputmethod.latin.R;
+import com.android.inputmethod.latin.RichInputMethodManager;
+import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
+import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
+
+import java.util.TreeSet;
+
+final class CustomInputStylePreference extends DialogPreference
+ implements DialogInterface.OnCancelListener {
+ private static final boolean DEBUG_SUBTYPE_ID = false;
+
+ interface Listener {
+ public void onRemoveCustomInputStyle(CustomInputStylePreference stylePref);
+ public void onSaveCustomInputStyle(CustomInputStylePreference stylePref);
+ public void onAddCustomInputStyle(CustomInputStylePreference stylePref);
+ public SubtypeLocaleAdapter getSubtypeLocaleAdapter();
+ public KeyboardLayoutSetAdapter getKeyboardLayoutSetAdapter();
+ }
+
+ private static final String KEY_PREFIX = "subtype_pref_";
+ private static final String KEY_NEW_SUBTYPE = KEY_PREFIX + "new";
+
+ private InputMethodSubtype mSubtype;
+ private InputMethodSubtype mPreviousSubtype;
+
+ private final Listener mProxy;
+ private Spinner mSubtypeLocaleSpinner;
+ private Spinner mKeyboardLayoutSetSpinner;
+
+ public static CustomInputStylePreference newIncompleteSubtypePreference(
+ final Context context, final Listener proxy) {
+ return new CustomInputStylePreference(context, null, proxy);
+ }
+
+ public CustomInputStylePreference(final Context context, final InputMethodSubtype subtype,
+ final Listener proxy) {
+ super(context, null);
+ setDialogLayoutResource(R.layout.additional_subtype_dialog);
+ setPersistent(false);
+ mProxy = proxy;
+ setSubtype(subtype);
+ }
+
+ public void show() {
+ showDialog(null);
+ }
+
+ public final boolean isIncomplete() {
+ return mSubtype == null;
+ }
+
+ public InputMethodSubtype getSubtype() {
+ return mSubtype;
+ }
+
+ public void setSubtype(final InputMethodSubtype subtype) {
+ mPreviousSubtype = mSubtype;
+ mSubtype = subtype;
+ if (isIncomplete()) {
+ setTitle(null);
+ setDialogTitle(R.string.add_style);
+ setKey(KEY_NEW_SUBTYPE);
+ } else {
+ final String displayName =
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype);
+ setTitle(displayName);
+ setDialogTitle(displayName);
+ setKey(KEY_PREFIX + subtype.getLocale() + "_"
+ + SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype));
+ }
+ }
+
+ public void revert() {
+ setSubtype(mPreviousSubtype);
+ }
+
+ public boolean hasBeenModified() {
+ return mSubtype != null && !mSubtype.equals(mPreviousSubtype);
+ }
+
+ @Override
+ protected View onCreateDialogView() {
+ final View v = super.onCreateDialogView();
+ mSubtypeLocaleSpinner = (Spinner) v.findViewById(R.id.subtype_locale_spinner);
+ mSubtypeLocaleSpinner.setAdapter(mProxy.getSubtypeLocaleAdapter());
+ mKeyboardLayoutSetSpinner = (Spinner) v.findViewById(R.id.keyboard_layout_set_spinner);
+ mKeyboardLayoutSetSpinner.setAdapter(mProxy.getKeyboardLayoutSetAdapter());
+ // All keyboard layout names are in the Latin script and thus left to right. That means
+ // the view would align them to the left even if the system locale is RTL, but that
+ // would look strange. To fix this, we align them to the view's start, which will be
+ // natural for any direction.
+ ViewCompatUtils.setTextAlignment(
+ mKeyboardLayoutSetSpinner, ViewCompatUtils.TEXT_ALIGNMENT_VIEW_START);
+ return v;
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(final AlertDialog.Builder builder) {
+ builder.setCancelable(true).setOnCancelListener(this);
+ if (isIncomplete()) {
+ builder.setPositiveButton(R.string.add, this)
+ .setNegativeButton(android.R.string.cancel, this);
+ } else {
+ builder.setPositiveButton(R.string.save, this)
+ .setNeutralButton(android.R.string.cancel, this)
+ .setNegativeButton(R.string.remove, this);
+ final SubtypeLocaleItem localeItem = new SubtypeLocaleItem(mSubtype);
+ final KeyboardLayoutSetItem layoutItem = new KeyboardLayoutSetItem(mSubtype);
+ setSpinnerPosition(mSubtypeLocaleSpinner, localeItem);
+ setSpinnerPosition(mKeyboardLayoutSetSpinner, layoutItem);
+ }
+ }
+
+ private static void setSpinnerPosition(final Spinner spinner, final Object itemToSelect) {
+ final SpinnerAdapter adapter = spinner.getAdapter();
+ final int count = adapter.getCount();
+ for (int i = 0; i < count; i++) {
+ final Object item = spinner.getItemAtPosition(i);
+ if (item.equals(itemToSelect)) {
+ spinner.setSelection(i);
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void onCancel(final DialogInterface dialog) {
+ if (isIncomplete()) {
+ mProxy.onRemoveCustomInputStyle(this);
+ }
+ }
+
+ @Override
+ public void onClick(final DialogInterface dialog, final int which) {
+ super.onClick(dialog, which);
+ switch (which) {
+ case DialogInterface.BUTTON_POSITIVE:
+ final boolean isEditing = !isIncomplete();
+ final SubtypeLocaleItem locale =
+ (SubtypeLocaleItem) mSubtypeLocaleSpinner.getSelectedItem();
+ final KeyboardLayoutSetItem layout =
+ (KeyboardLayoutSetItem) mKeyboardLayoutSetSpinner.getSelectedItem();
+ final InputMethodSubtype subtype =
+ AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
+ locale.mLocaleString, layout.mLayoutName);
+ setSubtype(subtype);
+ notifyChanged();
+ if (isEditing) {
+ mProxy.onSaveCustomInputStyle(this);
+ } else {
+ mProxy.onAddCustomInputStyle(this);
+ }
+ break;
+ case DialogInterface.BUTTON_NEUTRAL:
+ // Nothing to do
+ break;
+ case DialogInterface.BUTTON_NEGATIVE:
+ mProxy.onRemoveCustomInputStyle(this);
+ break;
+ }
+ }
+
+ private static int getSpinnerPosition(final Spinner spinner) {
+ if (spinner == null) return -1;
+ return spinner.getSelectedItemPosition();
+ }
+
+ private static void setSpinnerPosition(final Spinner spinner, final int position) {
+ if (spinner == null || position < 0) return;
+ spinner.setSelection(position);
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ final Parcelable superState = super.onSaveInstanceState();
+ final Dialog dialog = getDialog();
+ if (dialog == null || !dialog.isShowing()) {
+ return superState;
+ }
+
+ final SavedState myState = new SavedState(superState);
+ myState.mSubtype = mSubtype;
+ myState.mSubtypeLocaleSelectedPos = getSpinnerPosition(mSubtypeLocaleSpinner);
+ myState.mKeyboardLayoutSetSelectedPos = getSpinnerPosition(mKeyboardLayoutSetSpinner);
+ return myState;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(final Parcelable state) {
+ if (!(state instanceof SavedState)) {
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ final SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ setSpinnerPosition(mSubtypeLocaleSpinner, myState.mSubtypeLocaleSelectedPos);
+ setSpinnerPosition(mKeyboardLayoutSetSpinner, myState.mKeyboardLayoutSetSelectedPos);
+ setSubtype(myState.mSubtype);
+ }
+
+ static final class SavedState extends Preference.BaseSavedState {
+ InputMethodSubtype mSubtype;
+ int mSubtypeLocaleSelectedPos;
+ int mKeyboardLayoutSetSelectedPos;
+
+ public SavedState(final Parcelable superState) {
+ super(superState);
+ }
+
+ @Override
+ public void writeToParcel(final Parcel dest, final int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeInt(mSubtypeLocaleSelectedPos);
+ dest.writeInt(mKeyboardLayoutSetSelectedPos);
+ dest.writeParcelable(mSubtype, 0);
+ }
+
+ public SavedState(final Parcel source) {
+ super(source);
+ mSubtypeLocaleSelectedPos = source.readInt();
+ mKeyboardLayoutSetSelectedPos = source.readInt();
+ mSubtype = (InputMethodSubtype)source.readParcelable(null);
+ }
+
+ public static final Parcelable.Creator<SavedState> CREATOR =
+ new Parcelable.Creator<SavedState>() {
+ @Override
+ public SavedState createFromParcel(final Parcel source) {
+ return new SavedState(source);
+ }
+
+ @Override
+ public SavedState[] newArray(final int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+
+ static final class SubtypeLocaleItem implements Comparable<SubtypeLocaleItem> {
+ public final String mLocaleString;
+ private final String mDisplayName;
+
+ public SubtypeLocaleItem(final InputMethodSubtype subtype) {
+ mLocaleString = subtype.getLocale();
+ mDisplayName = SubtypeLocaleUtils.getSubtypeLocaleDisplayNameInSystemLocale(
+ mLocaleString);
+ }
+
+ // {@link ArrayAdapter<T>} that hosts the instance of this class needs {@link #toString()}
+ // to get display name.
+ @Override
+ public String toString() {
+ return mDisplayName;
+ }
+
+ @Override
+ public int compareTo(final SubtypeLocaleItem o) {
+ return mLocaleString.compareTo(o.mLocaleString);
+ }
+ }
+
+ static final class SubtypeLocaleAdapter extends ArrayAdapter<SubtypeLocaleItem> {
+ private static final String TAG_SUBTYPE = SubtypeLocaleAdapter.class.getSimpleName();
+
+ public SubtypeLocaleAdapter(final Context context) {
+ super(context, android.R.layout.simple_spinner_item);
+ setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+
+ final TreeSet<SubtypeLocaleItem> items = new TreeSet<>();
+ final InputMethodInfo imi = RichInputMethodManager.getInstance()
+ .getInputMethodInfoOfThisIme();
+ final int count = imi.getSubtypeCount();
+ for (int i = 0; i < count; i++) {
+ final InputMethodSubtype subtype = imi.getSubtypeAt(i);
+ if (DEBUG_SUBTYPE_ID) {
+ Log.d(TAG_SUBTYPE, String.format("%-6s 0x%08x %11d %s",
+ subtype.getLocale(), subtype.hashCode(), subtype.hashCode(),
+ SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype)));
+ }
+ if (InputMethodSubtypeCompatUtils.isAsciiCapable(subtype)) {
+ items.add(new SubtypeLocaleItem(subtype));
+ }
+ }
+ // TODO: Should filter out already existing combinations of locale and layout.
+ addAll(items);
+ }
+ }
+
+ static final class KeyboardLayoutSetItem {
+ public final String mLayoutName;
+ private final String mDisplayName;
+
+ public KeyboardLayoutSetItem(final InputMethodSubtype subtype) {
+ mLayoutName = SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype);
+ mDisplayName = SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype);
+ }
+
+ // {@link ArrayAdapter<T>} that hosts the instance of this class needs {@link #toString()}
+ // to get display name.
+ @Override
+ public String toString() {
+ return mDisplayName;
+ }
+ }
+
+ static final class KeyboardLayoutSetAdapter extends ArrayAdapter<KeyboardLayoutSetItem> {
+ public KeyboardLayoutSetAdapter(final Context context) {
+ super(context, android.R.layout.simple_spinner_item);
+ setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+
+ // TODO: Should filter out already existing combinations of locale and layout.
+ for (final String layout : SubtypeLocaleUtils.getPredefinedKeyboardLayoutSet()) {
+ // This is a dummy subtype with NO_LANGUAGE, only for display.
+ final InputMethodSubtype subtype =
+ AdditionalSubtypeUtils.createDummyAdditionalSubtype(
+ SubtypeLocaleUtils.NO_LANGUAGE, layout);
+ add(new KeyboardLayoutSetItem(subtype));
+ }
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java
index c633fc167..46fcc7106 100644
--- a/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/CustomInputStyleSettingsFragment.java
@@ -17,16 +17,12 @@
package com.android.inputmethod.latin.settings;
import android.app.AlertDialog;
-import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.preference.DialogPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
@@ -39,15 +35,9 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
-import android.widget.ArrayAdapter;
-import android.widget.Spinner;
-import android.widget.SpinnerAdapter;
import android.widget.Toast;
-import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
-import com.android.inputmethod.compat.ViewCompatUtils;
import com.android.inputmethod.latin.R;
import com.android.inputmethod.latin.RichInputMethodManager;
import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
@@ -56,19 +46,18 @@ import com.android.inputmethod.latin.utils.IntentUtils;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
import java.util.ArrayList;
-import java.util.TreeSet;
-public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
+public final class CustomInputStyleSettingsFragment extends PreferenceFragment
+ implements CustomInputStylePreference.Listener {
private static final String TAG = CustomInputStyleSettingsFragment.class.getSimpleName();
- private static final boolean DEBUG_SUBTYPE_ID = false;
// Note: We would like to turn this debug flag true in order to see what input styles are
// defined in a bug-report.
private static final boolean DEBUG_CUSTOM_INPUT_STYLES = true;
private RichInputMethodManager mRichImm;
private SharedPreferences mPrefs;
- private SubtypeLocaleAdapter mSubtypeLocaleAdapter;
- private KeyboardLayoutSetAdapter mKeyboardLayoutSetAdapter;
+ private CustomInputStylePreference.SubtypeLocaleAdapter mSubtypeLocaleAdapter;
+ private CustomInputStylePreference.KeyboardLayoutSetAdapter mKeyboardLayoutSetAdapter;
private boolean mIsAddingNewSubtype;
private AlertDialog mSubtypeEnablerNotificationDialog;
@@ -79,320 +68,6 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
"is_subtype_enabler_notification_dialog_open";
private static final String KEY_SUBTYPE_FOR_SUBTYPE_ENABLER = "subtype_for_subtype_enabler";
- static final class SubtypeLocaleItem implements Comparable<SubtypeLocaleItem> {
- public final String mLocaleString;
- private final String mDisplayName;
-
- public SubtypeLocaleItem(final InputMethodSubtype subtype) {
- mLocaleString = subtype.getLocale();
- mDisplayName = SubtypeLocaleUtils.getSubtypeLocaleDisplayNameInSystemLocale(
- mLocaleString);
- }
-
- // {@link ArrayAdapter<T>} that hosts the instance of this class needs {@link #toString()}
- // to get display name.
- @Override
- public String toString() {
- return mDisplayName;
- }
-
- @Override
- public int compareTo(final SubtypeLocaleItem o) {
- return mLocaleString.compareTo(o.mLocaleString);
- }
- }
-
- static final class SubtypeLocaleAdapter extends ArrayAdapter<SubtypeLocaleItem> {
- private static final String TAG_SUBTYPE = SubtypeLocaleAdapter.class.getSimpleName();
-
- public SubtypeLocaleAdapter(final Context context) {
- super(context, android.R.layout.simple_spinner_item);
- setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-
- final TreeSet<SubtypeLocaleItem> items = new TreeSet<>();
- final InputMethodInfo imi = RichInputMethodManager.getInstance()
- .getInputMethodInfoOfThisIme();
- final int count = imi.getSubtypeCount();
- for (int i = 0; i < count; i++) {
- final InputMethodSubtype subtype = imi.getSubtypeAt(i);
- if (DEBUG_SUBTYPE_ID) {
- Log.d(TAG_SUBTYPE, String.format("%-6s 0x%08x %11d %s",
- subtype.getLocale(), subtype.hashCode(), subtype.hashCode(),
- SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype)));
- }
- if (InputMethodSubtypeCompatUtils.isAsciiCapable(subtype)) {
- items.add(new SubtypeLocaleItem(subtype));
- }
- }
- // TODO: Should filter out already existing combinations of locale and layout.
- addAll(items);
- }
- }
-
- static final class KeyboardLayoutSetItem {
- public final String mLayoutName;
- private final String mDisplayName;
-
- public KeyboardLayoutSetItem(final InputMethodSubtype subtype) {
- mLayoutName = SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype);
- mDisplayName = SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(subtype);
- }
-
- // {@link ArrayAdapter<T>} that hosts the instance of this class needs {@link #toString()}
- // to get display name.
- @Override
- public String toString() {
- return mDisplayName;
- }
- }
-
- static final class KeyboardLayoutSetAdapter extends ArrayAdapter<KeyboardLayoutSetItem> {
- public KeyboardLayoutSetAdapter(final Context context) {
- super(context, android.R.layout.simple_spinner_item);
- setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-
- // TODO: Should filter out already existing combinations of locale and layout.
- for (final String layout : SubtypeLocaleUtils.getPredefinedKeyboardLayoutSet()) {
- // This is a dummy subtype with NO_LANGUAGE, only for display.
- final InputMethodSubtype subtype =
- AdditionalSubtypeUtils.createDummyAdditionalSubtype(
- SubtypeLocaleUtils.NO_LANGUAGE, layout);
- add(new KeyboardLayoutSetItem(subtype));
- }
- }
- }
-
- private interface SubtypeDialogProxy {
- public void onRemovePressed(SubtypePreference subtypePref);
- public void onSavePressed(SubtypePreference subtypePref);
- public void onAddPressed(SubtypePreference subtypePref);
- public SubtypeLocaleAdapter getSubtypeLocaleAdapter();
- public KeyboardLayoutSetAdapter getKeyboardLayoutSetAdapter();
- }
-
- static final class SubtypePreference extends DialogPreference
- implements DialogInterface.OnCancelListener {
- private static final String KEY_PREFIX = "subtype_pref_";
- private static final String KEY_NEW_SUBTYPE = KEY_PREFIX + "new";
-
- private InputMethodSubtype mSubtype;
- private InputMethodSubtype mPreviousSubtype;
-
- private final SubtypeDialogProxy mProxy;
- private Spinner mSubtypeLocaleSpinner;
- private Spinner mKeyboardLayoutSetSpinner;
-
- public static SubtypePreference newIncompleteSubtypePreference(final Context context,
- final SubtypeDialogProxy proxy) {
- return new SubtypePreference(context, null, proxy);
- }
-
- public SubtypePreference(final Context context, final InputMethodSubtype subtype,
- final SubtypeDialogProxy proxy) {
- super(context, null);
- setDialogLayoutResource(R.layout.additional_subtype_dialog);
- setPersistent(false);
- mProxy = proxy;
- setSubtype(subtype);
- }
-
- public void show() {
- showDialog(null);
- }
-
- public final boolean isIncomplete() {
- return mSubtype == null;
- }
-
- public InputMethodSubtype getSubtype() {
- return mSubtype;
- }
-
- public void setSubtype(final InputMethodSubtype subtype) {
- mPreviousSubtype = mSubtype;
- mSubtype = subtype;
- if (isIncomplete()) {
- setTitle(null);
- setDialogTitle(R.string.add_style);
- setKey(KEY_NEW_SUBTYPE);
- } else {
- final String displayName =
- SubtypeLocaleUtils.getSubtypeDisplayNameInSystemLocale(subtype);
- setTitle(displayName);
- setDialogTitle(displayName);
- setKey(KEY_PREFIX + subtype.getLocale() + "_"
- + SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype));
- }
- }
-
- public void revert() {
- setSubtype(mPreviousSubtype);
- }
-
- public boolean hasBeenModified() {
- return mSubtype != null && !mSubtype.equals(mPreviousSubtype);
- }
-
- @Override
- protected View onCreateDialogView() {
- final View v = super.onCreateDialogView();
- mSubtypeLocaleSpinner = (Spinner) v.findViewById(R.id.subtype_locale_spinner);
- mSubtypeLocaleSpinner.setAdapter(mProxy.getSubtypeLocaleAdapter());
- mKeyboardLayoutSetSpinner = (Spinner) v.findViewById(R.id.keyboard_layout_set_spinner);
- mKeyboardLayoutSetSpinner.setAdapter(mProxy.getKeyboardLayoutSetAdapter());
- // All keyboard layout names are in the Latin script and thus left to right. That means
- // the view would align them to the left even if the system locale is RTL, but that
- // would look strange. To fix this, we align them to the view's start, which will be
- // natural for any direction.
- ViewCompatUtils.setTextAlignment(
- mKeyboardLayoutSetSpinner, ViewCompatUtils.TEXT_ALIGNMENT_VIEW_START);
- return v;
- }
-
- @Override
- protected void onPrepareDialogBuilder(final AlertDialog.Builder builder) {
- builder.setCancelable(true).setOnCancelListener(this);
- if (isIncomplete()) {
- builder.setPositiveButton(R.string.add, this)
- .setNegativeButton(android.R.string.cancel, this);
- } else {
- builder.setPositiveButton(R.string.save, this)
- .setNeutralButton(android.R.string.cancel, this)
- .setNegativeButton(R.string.remove, this);
- final SubtypeLocaleItem localeItem = new SubtypeLocaleItem(mSubtype);
- final KeyboardLayoutSetItem layoutItem = new KeyboardLayoutSetItem(mSubtype);
- setSpinnerPosition(mSubtypeLocaleSpinner, localeItem);
- setSpinnerPosition(mKeyboardLayoutSetSpinner, layoutItem);
- }
- }
-
- private static void setSpinnerPosition(final Spinner spinner, final Object itemToSelect) {
- final SpinnerAdapter adapter = spinner.getAdapter();
- final int count = adapter.getCount();
- for (int i = 0; i < count; i++) {
- final Object item = spinner.getItemAtPosition(i);
- if (item.equals(itemToSelect)) {
- spinner.setSelection(i);
- return;
- }
- }
- }
-
- @Override
- public void onCancel(final DialogInterface dialog) {
- if (isIncomplete()) {
- mProxy.onRemovePressed(this);
- }
- }
-
- @Override
- public void onClick(final DialogInterface dialog, final int which) {
- super.onClick(dialog, which);
- switch (which) {
- case DialogInterface.BUTTON_POSITIVE:
- final boolean isEditing = !isIncomplete();
- final SubtypeLocaleItem locale =
- (SubtypeLocaleItem) mSubtypeLocaleSpinner.getSelectedItem();
- final KeyboardLayoutSetItem layout =
- (KeyboardLayoutSetItem) mKeyboardLayoutSetSpinner.getSelectedItem();
- final InputMethodSubtype subtype =
- AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
- locale.mLocaleString, layout.mLayoutName);
- setSubtype(subtype);
- notifyChanged();
- if (isEditing) {
- mProxy.onSavePressed(this);
- } else {
- mProxy.onAddPressed(this);
- }
- break;
- case DialogInterface.BUTTON_NEUTRAL:
- // Nothing to do
- break;
- case DialogInterface.BUTTON_NEGATIVE:
- mProxy.onRemovePressed(this);
- break;
- }
- }
-
- private static int getSpinnerPosition(final Spinner spinner) {
- if (spinner == null) return -1;
- return spinner.getSelectedItemPosition();
- }
-
- private static void setSpinnerPosition(final Spinner spinner, final int position) {
- if (spinner == null || position < 0) return;
- spinner.setSelection(position);
- }
-
- @Override
- protected Parcelable onSaveInstanceState() {
- final Parcelable superState = super.onSaveInstanceState();
- final Dialog dialog = getDialog();
- if (dialog == null || !dialog.isShowing()) {
- return superState;
- }
-
- final SavedState myState = new SavedState(superState);
- myState.mSubtype = mSubtype;
- myState.mSubtypeLocaleSelectedPos = getSpinnerPosition(mSubtypeLocaleSpinner);
- myState.mKeyboardLayoutSetSelectedPos = getSpinnerPosition(mKeyboardLayoutSetSpinner);
- return myState;
- }
-
- @Override
- protected void onRestoreInstanceState(final Parcelable state) {
- if (!(state instanceof SavedState)) {
- super.onRestoreInstanceState(state);
- return;
- }
-
- final SavedState myState = (SavedState) state;
- super.onRestoreInstanceState(myState.getSuperState());
- setSpinnerPosition(mSubtypeLocaleSpinner, myState.mSubtypeLocaleSelectedPos);
- setSpinnerPosition(mKeyboardLayoutSetSpinner, myState.mKeyboardLayoutSetSelectedPos);
- setSubtype(myState.mSubtype);
- }
-
- static final class SavedState extends Preference.BaseSavedState {
- InputMethodSubtype mSubtype;
- int mSubtypeLocaleSelectedPos;
- int mKeyboardLayoutSetSelectedPos;
-
- public SavedState(final Parcelable superState) {
- super(superState);
- }
-
- @Override
- public void writeToParcel(final Parcel dest, final int flags) {
- super.writeToParcel(dest, flags);
- dest.writeInt(mSubtypeLocaleSelectedPos);
- dest.writeInt(mKeyboardLayoutSetSelectedPos);
- dest.writeParcelable(mSubtype, 0);
- }
-
- public SavedState(final Parcel source) {
- super(source);
- mSubtypeLocaleSelectedPos = source.readInt();
- mKeyboardLayoutSetSelectedPos = source.readInt();
- mSubtype = (InputMethodSubtype)source.readParcelable(null);
- }
-
- public static final Parcelable.Creator<SavedState> CREATOR =
- new Parcelable.Creator<SavedState>() {
- @Override
- public SavedState createFromParcel(final Parcel source) {
- return new SavedState(source);
- }
-
- @Override
- public SavedState[] newArray(final int size) {
- return new SavedState[size];
- }
- };
- }
- }
-
public CustomInputStyleSettingsFragment() {
// Empty constructor for fragment generation.
}
@@ -440,8 +115,9 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
final Context context = getActivity();
- mSubtypeLocaleAdapter = new SubtypeLocaleAdapter(context);
- mKeyboardLayoutSetAdapter = new KeyboardLayoutSetAdapter(context);
+ mSubtypeLocaleAdapter = new CustomInputStylePreference.SubtypeLocaleAdapter(context);
+ mKeyboardLayoutSetAdapter =
+ new CustomInputStylePreference.KeyboardLayoutSetAdapter(context);
final String prefSubtypes =
Settings.readPrefAdditionalSubtypes(mPrefs, getResources());
@@ -454,7 +130,7 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
&& savedInstanceState.containsKey(KEY_IS_ADDING_NEW_SUBTYPE);
if (mIsAddingNewSubtype) {
getPreferenceScreen().addPreference(
- SubtypePreference.newIncompleteSubtypePreference(context, mSubtypeProxy));
+ CustomInputStylePreference.newIncompleteSubtypePreference(context, this));
}
super.onActivityCreated(savedInstanceState);
@@ -482,62 +158,60 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
}
}
- private final SubtypeDialogProxy mSubtypeProxy = new SubtypeDialogProxy() {
- @Override
- public void onRemovePressed(final SubtypePreference subtypePref) {
- mIsAddingNewSubtype = false;
- final PreferenceGroup group = getPreferenceScreen();
- group.removePreference(subtypePref);
+ @Override
+ public void onRemoveCustomInputStyle(final CustomInputStylePreference stylePref) {
+ mIsAddingNewSubtype = false;
+ final PreferenceGroup group = getPreferenceScreen();
+ group.removePreference(stylePref);
+ mRichImm.setAdditionalInputMethodSubtypes(getSubtypes());
+ }
+
+ @Override
+ public void onSaveCustomInputStyle(final CustomInputStylePreference stylePref) {
+ final InputMethodSubtype subtype = stylePref.getSubtype();
+ if (!stylePref.hasBeenModified()) {
+ return;
+ }
+ if (findDuplicatedSubtype(subtype) == null) {
mRichImm.setAdditionalInputMethodSubtypes(getSubtypes());
+ return;
}
- @Override
- public void onSavePressed(final SubtypePreference subtypePref) {
- final InputMethodSubtype subtype = subtypePref.getSubtype();
- if (!subtypePref.hasBeenModified()) {
- return;
- }
- if (findDuplicatedSubtype(subtype) == null) {
- mRichImm.setAdditionalInputMethodSubtypes(getSubtypes());
- return;
- }
+ // Saved subtype is duplicated.
+ final PreferenceGroup group = getPreferenceScreen();
+ group.removePreference(stylePref);
+ stylePref.revert();
+ group.addPreference(stylePref);
+ showSubtypeAlreadyExistsToast(subtype);
+ }
- // Saved subtype is duplicated.
- final PreferenceGroup group = getPreferenceScreen();
- group.removePreference(subtypePref);
- subtypePref.revert();
- group.addPreference(subtypePref);
- showSubtypeAlreadyExistsToast(subtype);
+ @Override
+ public void onAddCustomInputStyle(final CustomInputStylePreference stylePref) {
+ mIsAddingNewSubtype = false;
+ final InputMethodSubtype subtype = stylePref.getSubtype();
+ if (findDuplicatedSubtype(subtype) == null) {
+ mRichImm.setAdditionalInputMethodSubtypes(getSubtypes());
+ mSubtypePreferenceKeyForSubtypeEnabler = stylePref.getKey();
+ mSubtypeEnablerNotificationDialog = createDialog();
+ mSubtypeEnablerNotificationDialog.show();
+ return;
}
- @Override
- public void onAddPressed(final SubtypePreference subtypePref) {
- mIsAddingNewSubtype = false;
- final InputMethodSubtype subtype = subtypePref.getSubtype();
- if (findDuplicatedSubtype(subtype) == null) {
- mRichImm.setAdditionalInputMethodSubtypes(getSubtypes());
- mSubtypePreferenceKeyForSubtypeEnabler = subtypePref.getKey();
- mSubtypeEnablerNotificationDialog = createDialog();
- mSubtypeEnablerNotificationDialog.show();
- return;
- }
-
- // Newly added subtype is duplicated.
- final PreferenceGroup group = getPreferenceScreen();
- group.removePreference(subtypePref);
- showSubtypeAlreadyExistsToast(subtype);
- }
+ // Newly added subtype is duplicated.
+ final PreferenceGroup group = getPreferenceScreen();
+ group.removePreference(stylePref);
+ showSubtypeAlreadyExistsToast(subtype);
+ }
- @Override
- public SubtypeLocaleAdapter getSubtypeLocaleAdapter() {
- return mSubtypeLocaleAdapter;
- }
+ @Override
+ public CustomInputStylePreference.SubtypeLocaleAdapter getSubtypeLocaleAdapter() {
+ return mSubtypeLocaleAdapter;
+ }
- @Override
- public KeyboardLayoutSetAdapter getKeyboardLayoutSetAdapter() {
- return mKeyboardLayoutSetAdapter;
- }
- };
+ @Override
+ public CustomInputStylePreference.KeyboardLayoutSetAdapter getKeyboardLayoutSetAdapter() {
+ return mKeyboardLayoutSetAdapter;
+ }
private void showSubtypeAlreadyExistsToast(final InputMethodSubtype subtype) {
final Context context = getActivity();
@@ -555,6 +229,7 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
}
private AlertDialog createDialog() {
+ final String imeId = mRichImm.getInputMethodIdOfThisIme();
final AlertDialog.Builder builder = new AlertDialog.Builder(
DialogUtils.getPlatformDialogThemeContext(getActivity()));
builder.setTitle(R.string.custom_input_styles_title)
@@ -564,7 +239,7 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
@Override
public void onClick(DialogInterface dialog, int which) {
final Intent intent = IntentUtils.getInputLanguageSelectionIntent(
- mRichImm.getInputMethodIdOfThisIme(),
+ imeId,
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -584,8 +259,8 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
final InputMethodSubtype[] subtypesArray =
AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefSubtypes);
for (final InputMethodSubtype subtype : subtypesArray) {
- final SubtypePreference pref = new SubtypePreference(
- context, subtype, mSubtypeProxy);
+ final CustomInputStylePreference pref =
+ new CustomInputStylePreference(context, subtype, this);
group.addPreference(pref);
}
}
@@ -596,8 +271,8 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
final int count = group.getPreferenceCount();
for (int i = 0; i < count; i++) {
final Preference pref = group.getPreference(i);
- if (pref instanceof SubtypePreference) {
- final SubtypePreference subtypePref = (SubtypePreference)pref;
+ if (pref instanceof CustomInputStylePreference) {
+ final CustomInputStylePreference subtypePref = (CustomInputStylePreference)pref;
// We should not save newly adding subtype to preference because it is incomplete.
if (subtypePref.isIncomplete()) continue;
subtypes.add(subtypePref.getSubtype());
@@ -631,8 +306,8 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment {
public boolean onOptionsItemSelected(final MenuItem item) {
final int itemId = item.getItemId();
if (itemId == R.id.action_add_style) {
- final SubtypePreference newSubtype =
- SubtypePreference.newIncompleteSubtypePreference(getActivity(), mSubtypeProxy);
+ final CustomInputStylePreference newSubtype =
+ CustomInputStylePreference.newIncompleteSubtypePreference(getActivity(), this);
getPreferenceScreen().addPreference(newSubtype);
newSubtype.show();
mIsAddingNewSubtype = true;
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
index 091ca43c6..768cba9b2 100644
--- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
+++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java
@@ -16,29 +16,36 @@
package com.android.inputmethod.latin.settings;
+/**
+ * Debug settings for the application.
+ *
+ * Note: Even though these settings are stored in the default shared preferences file,
+ * they shouldn't be restored across devices.
+ * If a new key is added here, it should also be blacklisted for restore in
+ * {@link LocalSettingsConstants}.
+ */
public final class DebugSettings {
public static final String PREF_DEBUG_MODE = "debug_mode";
public static final String PREF_FORCE_NON_DISTINCT_MULTITOUCH = "force_non_distinct_multitouch";
public static final String PREF_FORCE_PHYSICAL_KEYBOARD_SPECIAL_KEY =
"force_physical_keyboard_special_key";
- public static final String PREF_SHOULD_SHOW_LXX_SUGGESTION_UI =
- "pref_should_show_lxx_suggestion_ui";
public static final String PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS =
"pref_has_custom_key_preview_animation_params";
- public static final String PREF_KEY_PREVIEW_SHOW_UP_START_X_SCALE =
- "pref_key_preview_show_up_start_x_scale";
- public static final String PREF_KEY_PREVIEW_SHOW_UP_START_Y_SCALE =
- "pref_key_preview_show_up_start_y_scale";
+ public static final String PREF_KEY_PREVIEW_DISMISS_DURATION =
+ "pref_key_preview_dismiss_duration";
public static final String PREF_KEY_PREVIEW_DISMISS_END_X_SCALE =
"pref_key_preview_dismiss_end_x_scale";
public static final String PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE =
"pref_key_preview_dismiss_end_y_scale";
public static final String PREF_KEY_PREVIEW_SHOW_UP_DURATION =
"pref_key_preview_show_up_duration";
- public static final String PREF_KEY_PREVIEW_DISMISS_DURATION =
- "pref_key_preview_dismiss_duration";
+ public static final String PREF_KEY_PREVIEW_SHOW_UP_START_X_SCALE =
+ "pref_key_preview_show_up_start_x_scale";
+ public static final String PREF_KEY_PREVIEW_SHOW_UP_START_Y_SCALE =
+ "pref_key_preview_show_up_start_y_scale";
+ public static final String PREF_SHOULD_SHOW_LXX_SUGGESTION_UI =
+ "pref_should_show_lxx_suggestion_ui";
public static final String PREF_SLIDING_KEY_INPUT_PREVIEW = "pref_sliding_key_input_preview";
- public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout";
private DebugSettings() {
// This class is not publicly instantiable.
diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java
index e9f8d45aa..475f1def7 100644
--- a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java
@@ -73,7 +73,6 @@ public final class DebugSettingsFragment extends SubScreenFragment
dictDumpPreferenceGroup.addPreference(pref);
}
final Resources res = getResources();
- setupKeyLongpressTimeoutSettings();
setupKeyPreviewAnimationDuration(DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_DURATION,
res.getInteger(R.integer.config_key_preview_show_up_duration));
setupKeyPreviewAnimationDuration(DebugSettings.PREF_KEY_PREVIEW_DISMISS_DURATION,
@@ -163,45 +162,6 @@ public final class DebugSettingsFragment extends SubScreenFragment
}
}
- private void setupKeyLongpressTimeoutSettings() {
- final SharedPreferences prefs = getSharedPreferences();
- final Resources res = getResources();
- final SeekBarDialogPreference pref = (SeekBarDialogPreference)findPreference(
- DebugSettings.PREF_KEY_LONGPRESS_TIMEOUT);
- if (pref == null) {
- return;
- }
- pref.setInterface(new SeekBarDialogPreference.ValueProxy() {
- @Override
- public void writeValue(final int value, final String key) {
- prefs.edit().putInt(key, value).apply();
- }
-
- @Override
- public void writeDefaultValue(final String key) {
- prefs.edit().remove(key).apply();
- }
-
- @Override
- public int readValue(final String key) {
- return Settings.readKeyLongpressTimeout(prefs, res);
- }
-
- @Override
- public int readDefaultValue(final String key) {
- return Settings.readDefaultKeyLongpressTimeout(res);
- }
-
- @Override
- public String getValueText(final int value) {
- return res.getString(R.string.abbreviation_unit_milliseconds, value);
- }
-
- @Override
- public void feedbackValue(final int value) {}
- });
- }
-
private void setupKeyPreviewAnimationScale(final String prefKey, final float defaultValue) {
final SharedPreferences prefs = getSharedPreferences();
final Resources res = getResources();
diff --git a/java/src/com/android/inputmethod/latin/settings/LocalSettingsConstants.java b/java/src/com/android/inputmethod/latin/settings/LocalSettingsConstants.java
new file mode 100644
index 000000000..c9e9dc8d9
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/settings/LocalSettingsConstants.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin.settings;
+
+/**
+ * Collection of device specific preference constants.
+ */
+public class LocalSettingsConstants {
+ // Preference file for storing preferences that are tied to a device
+ // and are not backed up.
+ public static final String PREFS_FILE = "local_prefs";
+
+ // Preference key for the current account.
+ // Do not restore.
+ public static final String PREF_ACCOUNT_NAME = "pref_account_name";
+ // Preference key for enabling cloud sync feature.
+ // Do not restore.
+ public static final String PREF_ENABLE_CLOUD_SYNC = "pref_enable_cloud_sync";
+
+ // List of preference keys to skip from being restored by backup agent.
+ // These preferences are tied to a device and hence should not be restored.
+ // e.g. account name.
+ // Ideally they could have been kept in a separate file that wasn't backed up
+ // however the preference UI currently only deals with the default
+ // shared preferences which makes it non-trivial to move these out to
+ // a different shared preferences file.
+ public static final String[] PREFS_TO_SKIP_RESTORING = new String[] {
+ PREF_ACCOUNT_NAME,
+ PREF_ENABLE_CLOUD_SYNC,
+ // The debug settings are not restored on a new device.
+ // If a feature relies on these, it should ensure that the defaults are
+ // correctly set for it to work on a new device.
+ DebugSettings.PREF_DEBUG_MODE,
+ DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH,
+ DebugSettings.PREF_FORCE_PHYSICAL_KEYBOARD_SPECIAL_KEY,
+ DebugSettings.PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS,
+ DebugSettings.PREF_KEY_PREVIEW_DISMISS_DURATION,
+ DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_X_SCALE,
+ DebugSettings.PREF_KEY_PREVIEW_DISMISS_END_Y_SCALE,
+ DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_DURATION,
+ DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_X_SCALE,
+ DebugSettings.PREF_KEY_PREVIEW_SHOW_UP_START_Y_SCALE,
+ DebugSettings.PREF_SHOULD_SHOW_LXX_SUGGESTION_UI,
+ DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW
+ };
+}
diff --git a/java/src/com/android/inputmethod/latin/settings/MultiLingualSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/MultiLingualSettingsFragment.java
index b073c50a4..b71f8829b 100644
--- a/java/src/com/android/inputmethod/latin/settings/MultiLingualSettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/MultiLingualSettingsFragment.java
@@ -38,5 +38,6 @@ public final class MultiLingualSettingsFragment extends SubScreenFragment {
removePreference(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY);
removePreference(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST);
}
+ AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(getActivity(), this);
}
}
diff --git a/java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java b/java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java
index 31a20c4db..7603dbba5 100644
--- a/java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java
+++ b/java/src/com/android/inputmethod/latin/settings/NativeSuggestOptions.java
@@ -22,7 +22,8 @@ public class NativeSuggestOptions {
private static final int USE_FULL_EDIT_DISTANCE = 1;
private static final int BLOCK_OFFENSIVE_WORDS = 2;
private static final int SPACE_AWARE_GESTURE_ENABLED = 3;
- private static final int OPTIONS_SIZE = 4;
+ private static final int WEIGHT_FOR_LOCALE_IN_THOUSANDS = 4;
+ private static final int OPTIONS_SIZE = 5;
private final int[] mOptions = new int[OPTIONS_SIZE
+ AdditionalFeaturesSettingUtils.ADDITIONAL_FEATURES_SETTINGS_SIZE];
@@ -43,6 +44,12 @@ public class NativeSuggestOptions {
setBooleanOption(SPACE_AWARE_GESTURE_ENABLED, value);
}
+ public void setWeightForLocale(final float value) {
+ // We're passing this option as a fixed point value, in thousands. This is decoded in
+ // native code by SuggestOptions#weightForLocale().
+ setIntegerOption(WEIGHT_FOR_LOCALE_IN_THOUSANDS, (int) (value * 1000));
+ }
+
public void setAdditionalFeaturesOptions(final int[] additionalOptions) {
if (additionalOptions == null) {
return;
diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java
index 84596b4ad..391fc1982 100644
--- a/java/src/com/android/inputmethod/latin/settings/Settings.java
+++ b/java/src/com/android/inputmethod/latin/settings/Settings.java
@@ -93,8 +93,8 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_GESTURE_INPUT = "gesture_input";
public static final String PREF_VIBRATION_DURATION_SETTINGS =
"pref_vibration_duration_settings";
- public static final String PREF_KEYPRESS_SOUND_VOLUME =
- "pref_keypress_sound_volume";
+ public static final String PREF_KEYPRESS_SOUND_VOLUME = "pref_keypress_sound_volume";
+ public static final String PREF_KEY_LONGPRESS_TIMEOUT = "pref_key_longpress_timeout";
public static final String PREF_GESTURE_PREVIEW_TRAIL = "pref_gesture_preview_trail";
public static final String PREF_GESTURE_FLOATING_PREVIEW_TEXT =
"pref_gesture_floating_preview_text";
@@ -106,8 +106,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_KEY_IS_INTERNAL = "pref_key_is_internal";
public static final String PREF_ENABLE_METRICS_LOGGING = "pref_enable_metrics_logging";
- public static final String PREF_ACCOUNT_NAME = "pref_account_name";
-
// This preference key is deprecated. Use {@link #PREF_SHOW_LANGUAGE_SWITCH_KEY} instead.
// This is being used only for the backward compatibility.
private static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY =
@@ -319,7 +317,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static int readKeyLongpressTimeout(final SharedPreferences prefs,
final Resources res) {
final int milliseconds = prefs.getInt(
- DebugSettings.PREF_KEY_LONGPRESS_TIMEOUT, UNDEFINED_PREFERENCE_VALUE_INT);
+ PREF_KEY_LONGPRESS_TIMEOUT, UNDEFINED_PREFERENCE_VALUE_INT);
return (milliseconds != UNDEFINED_PREFERENCE_VALUE_INT) ? milliseconds
: readDefaultKeyLongpressTimeout(res);
}
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
index 8c4801798..6c21accf6 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsFragment.java
@@ -56,6 +56,7 @@ public final class SettingsFragment extends InputMethodSettingsFragment {
final Preference accountsPreference = findPreference(Settings.SCREEN_ACCOUNTS);
preferenceScreen.removePreference(accountsPreference);
}
+ AdditionalFeaturesSettingUtils.addAdditionalFeaturesPreferences(getActivity(), this);
}
@Override
diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
index ce8a0ab9c..660b4e095 100644
--- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
+++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java
@@ -64,7 +64,6 @@ public class SettingsValues {
public final boolean mSoundOn;
public final boolean mKeyPreviewPopupOn;
public final boolean mShowsVoiceInputKey;
- public final String mAccountName;
public final boolean mIncludesOtherImesInLanguageSwitchList;
public final boolean mShowsLanguageSwitchKey;
public final boolean mUseContactsDict;
@@ -141,7 +140,6 @@ public class SettingsValues {
mShowsVoiceInputKey = needsToShowVoiceInputKey(prefs, res)
&& mInputAttributes.mShouldShowVoiceInputKey
&& SubtypeSwitcher.getInstance().isShortcutImeEnabled();
- mAccountName = prefs.getString(Settings.PREF_ACCOUNT_NAME, null);
final String autoCorrectionThresholdRawValue = prefs.getString(
Settings.PREF_AUTO_CORRECTION_THRESHOLD,
res.getString(R.string.auto_correction_threshold_mode_index_modest));
@@ -385,8 +383,6 @@ public class SettingsValues {
sb.append("" + mKeyPreviewPopupOn);
sb.append("\n mShowsVoiceInputKey = ");
sb.append("" + mShowsVoiceInputKey);
- sb.append("\n mAccountName = ");
- sb.append("" + mAccountName);
sb.append("\n mIncludesOtherImesInLanguageSwitchList = ");
sb.append("" + mIncludesOtherImesInLanguageSwitchList);
sb.append("\n mShowsLanguageSwitchKey = ");
diff --git a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
index 54562f39d..c3b30dcb4 100644
--- a/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
+++ b/java/src/com/android/inputmethod/latin/setup/SetupWizardActivity.java
@@ -42,6 +42,8 @@ import com.android.inputmethod.latin.utils.UncachedInputMethodManagerUtils;
import java.util.ArrayList;
+import javax.annotation.Nonnull;
+
// TODO: Use Fragment to implement welcome screen and setup steps.
public final class SetupWizardActivity extends Activity implements View.OnClickListener {
static final String TAG = SetupWizardActivity.class.getSimpleName();
@@ -82,7 +84,7 @@ public final class SetupWizardActivity extends Activity implements View.OnClickL
private final InputMethodManager mImmInHandler;
- public SettingsPoolingHandler(final SetupWizardActivity ownerInstance,
+ public SettingsPoolingHandler(@Nonnull final SetupWizardActivity ownerInstance,
final InputMethodManager imm) {
super(ownerInstance);
mImmInHandler = imm;
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
index d55939971..7b66bbb75 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java
@@ -321,18 +321,6 @@ final class SuggestionStripLayoutHelper {
} else {
color = mColorSuggested;
}
- if (DebugFlags.DEBUG_ENABLED && suggestedWords.size() > 1) {
- // If we auto-correct, then the autocorrection is in slot 0 and the typed word
- // is in slot 1.
- if (indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION
- && suggestedWords.mWillAutoCorrect
- && AutoCorrectionUtils.shouldBlockAutoCorrectionBySafetyNet(
- suggestedWords.getLabel(SuggestedWords.INDEX_OF_AUTO_CORRECTION),
- suggestedWords.getLabel(SuggestedWords.INDEX_OF_TYPED_WORD))) {
- return 0xFFFF0000;
- }
- }
-
if (suggestedWords.mIsObsoleteSuggestions && !isTypedWord) {
return applyAlpha(color, mAlphaObsoleted);
}
@@ -553,12 +541,12 @@ final class SuggestionStripLayoutHelper {
return countInStrip;
}
- public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip) {
- final boolean shouldShowUiToAcceptTypedWord = Settings.getInstance().getCurrent()
- .mShouldShowLxxSuggestionUi;
+ public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip,
+ final boolean shouldShowWordToSave) {
+ final boolean showsHintWithWord = shouldShowWordToSave
+ || !Settings.getInstance().getCurrent().mShouldShowLxxSuggestionUi;
final int stripWidth = addToDictionaryStrip.getWidth();
- final int width = shouldShowUiToAcceptTypedWord ? stripWidth
- : stripWidth - mDividerWidth - mPadding * 2;
+ final int width = stripWidth - (showsHintWithWord ? mDividerWidth + mPadding * 2 : 0);
final TextView wordView = (TextView)addToDictionaryStrip.findViewById(R.id.word_to_save);
wordView.setTextColor(mColorTypedWord);
@@ -569,7 +557,7 @@ final class SuggestionStripLayoutHelper {
wordView.setText(wordToSave);
wordView.setTextScaleX(wordScaleX);
setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT);
- final int wordVisibility = shouldShowUiToAcceptTypedWord ? View.GONE : View.VISIBLE;
+ final int wordVisibility = showsHintWithWord ? View.VISIBLE : View.GONE;
wordView.setVisibility(wordVisibility);
addToDictionaryStrip.findViewById(R.id.word_to_save_divider).setVisibility(wordVisibility);
@@ -579,12 +567,7 @@ final class SuggestionStripLayoutHelper {
final float hintWeight;
final TextView hintView = (TextView)addToDictionaryStrip.findViewById(
R.id.hint_add_to_dictionary);
- if (shouldShowUiToAcceptTypedWord) {
- hintText = res.getText(R.string.hint_add_to_dictionary_without_word);
- hintWidth = width;
- hintWeight = 1.0f;
- hintView.setGravity(Gravity.CENTER);
- } else {
+ if (showsHintWithWord) {
final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip)
== ViewCompat.LAYOUT_DIRECTION_RTL);
final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW;
@@ -595,6 +578,11 @@ final class SuggestionStripLayoutHelper {
hintWidth = width - wordWidth;
hintWeight = 1.0f - mCenterSuggestionWeight;
hintView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START);
+ } else {
+ hintText = res.getText(R.string.hint_add_to_dictionary_without_word);
+ hintWidth = width;
+ hintWeight = 1.0f;
+ hintView.setGravity(Gravity.CENTER);
}
hintView.setTextColor(mColorAutoCorrect);
final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint());
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
index e40fd8800..789d549d7 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java
@@ -231,8 +231,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return mStripVisibilityGroup.isShowingAddToDictionaryStrip();
}
- public void showAddToDictionaryHint(final String word) {
- mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip);
+ public void showAddToDictionaryHint(final String word, final boolean shouldShowWordToSave) {
+ mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip, shouldShowWordToSave);
// {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word
// will be extracted at {@link #onClick(View)}.
mAddToDictionaryStrip.setTag(word);
@@ -501,7 +501,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return;
}
final Object tag = view.getTag();
- // {@link String} tag is set at {@link #showAddToDictionaryHint(String,CharSequence)}.
+ // {@link String} tag is set at {@link #suggestAddingToDictionary(String,CharSequence)}.
if (tag instanceof String) {
final String wordToSave = (String)tag;
mListener.addWordToUserDictionary(wordToSave);
diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java
index 52708455e..5c86a02af 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java
@@ -22,7 +22,7 @@ import com.android.inputmethod.latin.SuggestedWords;
* An object that gives basic control of a suggestion strip and some info on it.
*/
public interface SuggestionStripViewAccessor {
- public void showAddToDictionaryHint(final String word);
+ public void suggestAddingToDictionary(final String word, final boolean isFromSuggestionStrip);
public boolean isShowingAddToDictionaryHint();
public void dismissAddToDictionaryHint();
public void setNeutralSuggestionStrip();
diff --git a/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java b/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java
index 156fcf57c..cba769521 100644
--- a/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/AutoCorrectionUtils.java
@@ -52,41 +52,9 @@ public final class AutoCorrectionUtils {
if (DBG) {
Log.d(TAG, "Auto corrected by S-threshold.");
}
- return !shouldBlockAutoCorrectionBySafetyNet(consideredWord, suggestion.mWord);
+ return true;
}
}
return false;
}
-
- // TODO: Resolve the inconsistencies between the native auto correction algorithms and
- // this safety net
- public static boolean shouldBlockAutoCorrectionBySafetyNet(final String typedWord,
- final String suggestion) {
- // Safety net for auto correction.
- // Actually if we hit this safety net, it's a bug.
- // If user selected aggressive auto correction mode, there is no need to use the safety
- // net.
- // If the length of typed word is less than MINIMUM_SAFETY_NET_CHAR_LENGTH,
- // we should not use net because relatively edit distance can be big.
- final int typedWordLength = typedWord.length();
- if (typedWordLength < MINIMUM_SAFETY_NET_CHAR_LENGTH) {
- return false;
- }
- final int maxEditDistanceOfNativeDictionary = (typedWordLength / 2) + 1;
- final int distance = BinaryDictionaryUtils.editDistance(typedWord, suggestion);
- if (DBG) {
- Log.d(TAG, "Autocorrected edit distance = " + distance
- + ", " + maxEditDistanceOfNativeDictionary);
- }
- if (distance > maxEditDistanceOfNativeDictionary) {
- if (DBG) {
- Log.e(TAG, "Safety net: before = " + typedWord + ", after = " + suggestion);
- Log.e(TAG, "(Error) The edit distance of this correction exceeds limit. "
- + "Turning off auto-correction.");
- }
- return true;
- } else {
- return false;
- }
- }
}
diff --git a/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java
index 5d7deba15..ce25fe6a4 100644
--- a/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java
@@ -43,7 +43,6 @@ public final class BinaryDictionaryUtils {
private static native boolean createEmptyDictFileNative(String filePath, long dictVersion,
String locale, String[] attributeKeyStringArray, String[] attributeValueStringArray);
private static native float calcNormalizedScoreNative(int[] before, int[] after, int score);
- private static native int editDistanceNative(int[] before, int[] after);
private static native int setCurrentTimeForTestNative(int currentTime);
public static DictionaryHeader getHeader(final File dictFile)
@@ -112,14 +111,6 @@ public final class BinaryDictionaryUtils {
StringUtils.toCodePointArray(after), score);
}
- public static int editDistance(final String before, final String after) {
- if (before == null || after == null) {
- throw new IllegalArgumentException();
- }
- return editDistanceNative(StringUtils.toCodePointArray(before),
- StringUtils.toCodePointArray(after));
- }
-
/**
* Control the current time to be used in the native code. If currentTime >= 0, this method sets
* the current time and gets into test mode.
diff --git a/java/src/com/android/inputmethod/latin/utils/CursorAnchorInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/CursorAnchorInfoUtils.java
index 9dc0524a2..e05618901 100644
--- a/java/src/com/android/inputmethod/latin/utils/CursorAnchorInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/CursorAnchorInfoUtils.java
@@ -16,10 +16,12 @@
package com.android.inputmethod.latin.utils;
+import android.annotation.TargetApi;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.inputmethodservice.ExtractEditText;
import android.inputmethodservice.InputMethodService;
+import android.os.Build;
import android.text.Layout;
import android.text.Spannable;
import android.view.View;
@@ -27,6 +29,12 @@ import android.view.ViewParent;
import android.view.inputmethod.CursorAnchorInfo;
import android.widget.TextView;
+import com.android.inputmethod.compat.BuildCompatUtils;
+import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
/**
* This class allows input methods to extract {@link CursorAnchorInfo} directly from the given
* {@link TextView}. This is useful and even necessary to support full-screen mode where the default
@@ -77,13 +85,32 @@ public final class CursorAnchorInfoUtils {
}
/**
+ * Extracts {@link CursorAnchorInfoCompatWrapper} from the given {@link TextView}.
+ * @param textView the target text view from which {@link CursorAnchorInfoCompatWrapper} is to
+ * be extracted.
+ * @return the {@link CursorAnchorInfoCompatWrapper} object based on the current layout.
+ * {@code null} if {@code Build.VERSION.SDK_INT} is 20 or prior or {@link TextView} is not
+ * ready to provide layout information.
+ */
+ @Nullable
+ public static CursorAnchorInfoCompatWrapper extractFromTextView(
+ @Nonnull final TextView textView) {
+ if (Build.VERSION.SDK_INT < BuildCompatUtils.VERSION_CODES_LXX) {
+ return null;
+ }
+ return CursorAnchorInfoCompatWrapper.wrap(extractFromTextViewInternal(textView));
+ }
+
+ /**
* Returns {@link CursorAnchorInfo} from the given {@link TextView}.
* @param textView the target text view from which {@link CursorAnchorInfo} is to be extracted.
* @return the {@link CursorAnchorInfo} object based on the current layout. {@code null} if it
* is not feasible.
*/
- public static CursorAnchorInfo getCursorAnchorInfo(final TextView textView) {
- Layout layout = textView.getLayout();
+ @TargetApi(BuildCompatUtils.VERSION_CODES_LXX)
+ @Nullable
+ private static CursorAnchorInfo extractFromTextViewInternal(@Nonnull final TextView textView) {
+ final Layout layout = textView.getLayout();
if (layout == null) {
return null;
}
diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
index 249478785..e29aabacd 100644
--- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
+++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java
@@ -230,6 +230,7 @@ public class DictionaryInfoUtils {
/**
* Helper method to return a dictionary res id for a locale, or 0 if none.
+ * @param res resources for the app
* @param locale dictionary locale
* @return main dictionary resource id
*/
@@ -258,6 +259,7 @@ public class DictionaryInfoUtils {
/**
* Returns a main dictionary resource id
+ * @param res resources for the app
* @param locale dictionary locale
* @return main dictionary resource id
*/
@@ -283,6 +285,25 @@ public class DictionaryInfoUtils {
BinaryDictionaryGetter.ID_CATEGORY_SEPARATOR + locale.getLanguage().toString();
}
+ /**
+ * Returns whether a main dictionary is readily available for this locale.
+ *
+ * This does not query the content provider.
+ *
+ * @param context context to open files upon
+ * @param locale dictionary locale
+ * @return true if a dictionary is available right away, false otherwise
+ */
+ public static boolean hasReadilyAvailableMainDictionaryForLocale(final Context context,
+ final Locale locale) {
+ final Resources res = context.getResources();
+ if (0 != getMainDictionaryResourceIdIfAvailableForLocale(res, locale)) {
+ return true;
+ }
+ final String fileName = getCacheFileName(getMainDictId(locale), locale.toString(), context);
+ return new File(fileName).exists();
+ }
+
public static DictionaryHeader getDictionaryFileHeaderOrNull(final File file) {
return getDictionaryFileHeaderOrNull(file, 0, file.length());
}
diff --git a/java/src/com/android/inputmethod/latin/utils/LeakGuardHandlerWrapper.java b/java/src/com/android/inputmethod/latin/utils/LeakGuardHandlerWrapper.java
index dd6fac671..9a5be99b3 100644
--- a/java/src/com/android/inputmethod/latin/utils/LeakGuardHandlerWrapper.java
+++ b/java/src/com/android/inputmethod/latin/utils/LeakGuardHandlerWrapper.java
@@ -21,21 +21,22 @@ import android.os.Looper;
import java.lang.ref.WeakReference;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
public class LeakGuardHandlerWrapper<T> extends Handler {
private final WeakReference<T> mOwnerInstanceRef;
- public LeakGuardHandlerWrapper(final T ownerInstance) {
+ public LeakGuardHandlerWrapper(@Nonnull final T ownerInstance) {
this(ownerInstance, Looper.myLooper());
}
- public LeakGuardHandlerWrapper(final T ownerInstance, final Looper looper) {
+ public LeakGuardHandlerWrapper(@Nonnull final T ownerInstance, final Looper looper) {
super(looper);
- if (ownerInstance == null) {
- throw new NullPointerException("ownerInstance is null");
- }
mOwnerInstanceRef = new WeakReference<>(ownerInstance);
}
+ @Nullable
public T getOwnerInstance() {
return mOwnerInstanceRef.get();
}
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
index 76c7fdd6f..f8dadb488 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp
@@ -28,7 +28,7 @@
#include "suggest/core/dictionary/property/unigram_property.h"
#include "suggest/core/dictionary/property/word_property.h"
#include "suggest/core/result/suggestion_results.h"
-#include "suggest/core/session/prev_words_info.h"
+#include "suggest/core/session/ngram_context.h"
#include "suggest/core/suggest_options.h"
#include "suggest/policyimpl/dictionary/structure/dictionary_structure_with_buffer_policy_factory.h"
#include "utils/char_utils.h"
@@ -242,15 +242,15 @@ static void latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jclass clazz,
env->GetFloatArrayRegion(inOutWeightOfLangModelVsSpatialModel, 0, 1 /* len */,
&weightOfLangModelVsSpatialModel);
SuggestionResults suggestionResults(MAX_RESULTS);
- const PrevWordsInfo prevWordsInfo = JniDataUtils::constructPrevWordsInfo(env,
+ const NgramContext ngramContext = JniDataUtils::constructNgramContext(env,
prevWordCodePointArrays, isBeginningOfSentenceArray, prevWordCount);
if (givenSuggestOptions.isGesture() || inputSize > 0) {
// TODO: Use SuggestionResults to return suggestions.
dictionary->getSuggestions(pInfo, traverseSession, xCoordinates, yCoordinates,
- times, pointerIds, inputCodePoints, inputSize, &prevWordsInfo,
+ times, pointerIds, inputCodePoints, inputSize, &ngramContext,
&givenSuggestOptions, weightOfLangModelVsSpatialModel, &suggestionResults);
} else {
- dictionary->getPredictions(&prevWordsInfo, &suggestionResults);
+ dictionary->getPredictions(&ngramContext, &suggestionResults);
}
if (DEBUG_DICT) {
suggestionResults.dumpSuggestions();
@@ -289,10 +289,10 @@ static jint latinime_BinaryDictionary_getNgramProbability(JNIEnv *env, jclass cl
const jsize wordLength = env->GetArrayLength(word);
int wordCodePoints[wordLength];
env->GetIntArrayRegion(word, 0, wordLength, wordCodePoints);
- const PrevWordsInfo prevWordsInfo = JniDataUtils::constructPrevWordsInfo(env,
+ const NgramContext ngramContext = JniDataUtils::constructNgramContext(env,
prevWordCodePointArrays, isBeginningOfSentenceArray,
env->GetArrayLength(prevWordCodePointArrays));
- return dictionary->getNgramProbability(&prevWordsInfo,
+ return dictionary->getNgramProbability(&ngramContext,
CodePointArrayView(wordCodePoints, wordLength));
}
@@ -327,8 +327,9 @@ static jint latinime_BinaryDictionary_getNextWord(JNIEnv *env, jclass clazz,
static void latinime_BinaryDictionary_getWordProperty(JNIEnv *env, jclass clazz,
jlong dict, jintArray word, jboolean isBeginningOfSentence, jintArray outCodePoints,
- jbooleanArray outFlags, jintArray outProbabilityInfo, jobject outBigramTargets,
- jobject outBigramProbabilityInfo, jobject outShortcutTargets,
+ jbooleanArray outFlags, jintArray outProbabilityInfo, jobject /* outNgramPrevWordsArray */,
+ jobject /* outNgramPrevWordIsBeginningOfSentenceArray */, jobject outNgramTargets,
+ jobject outNgramProbabilityInfo, jobject outShortcutTargets,
jobject outShortcutProbabilities) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
if (!dictionary) return;
@@ -351,7 +352,7 @@ static void latinime_BinaryDictionary_getWordProperty(JNIEnv *env, jclass clazz,
const WordProperty wordProperty = dictionary->getWordProperty(
CodePointArrayView(wordCodePoints, codePointCount));
wordProperty.outputProperties(env, outCodePoints, outFlags, outProbabilityInfo,
- outBigramTargets, outBigramProbabilityInfo, outShortcutTargets,
+ outNgramTargets, outNgramProbabilityInfo, outShortcutTargets,
outShortcutProbabilities);
}
@@ -401,7 +402,7 @@ static bool latinime_BinaryDictionary_addNgramEntry(JNIEnv *env, jclass clazz, j
if (!dictionary) {
return false;
}
- const PrevWordsInfo prevWordsInfo = JniDataUtils::constructPrevWordsInfo(env,
+ const NgramContext ngramContext = JniDataUtils::constructNgramContext(env,
prevWordCodePointArrays, isBeginningOfSentenceArray,
env->GetArrayLength(prevWordCodePointArrays));
jsize wordLength = env->GetArrayLength(word);
@@ -410,7 +411,7 @@ static bool latinime_BinaryDictionary_addNgramEntry(JNIEnv *env, jclass clazz, j
// Use 1 for count to indicate the ngram has inputted.
const NgramProperty ngramProperty(CodePointArrayView(wordCodePoints, wordLength).toVector(),
probability, HistoricalInfo(timestamp, 0 /* level */, 1 /* count */));
- return dictionary->addNgramEntry(&prevWordsInfo, &ngramProperty);
+ return dictionary->addNgramEntry(&ngramContext, &ngramProperty);
}
static bool latinime_BinaryDictionary_removeNgramEntry(JNIEnv *env, jclass clazz, jlong dict,
@@ -420,31 +421,32 @@ static bool latinime_BinaryDictionary_removeNgramEntry(JNIEnv *env, jclass clazz
if (!dictionary) {
return false;
}
- const PrevWordsInfo prevWordsInfo = JniDataUtils::constructPrevWordsInfo(env,
+ const NgramContext ngramContext = JniDataUtils::constructNgramContext(env,
prevWordCodePointArrays, isBeginningOfSentenceArray,
env->GetArrayLength(prevWordCodePointArrays));
jsize codePointCount = env->GetArrayLength(word);
int wordCodePoints[codePointCount];
env->GetIntArrayRegion(word, 0, codePointCount, wordCodePoints);
- return dictionary->removeNgramEntry(&prevWordsInfo,
+ return dictionary->removeNgramEntry(&ngramContext,
CodePointArrayView(wordCodePoints, codePointCount));
}
-static bool latinime_BinaryDictionary_updateCounter(JNIEnv *env, jclass clazz, jlong dict,
- jobjectArray prevWordCodePointArrays, jbooleanArray isBeginningOfSentenceArray,
- jintArray word, jboolean isValidWord, jint count, jint timestamp) {
+static bool latinime_BinaryDictionary_updateEntriesForWordWithNgramContext(JNIEnv *env,
+ jclass clazz, jlong dict, jobjectArray prevWordCodePointArrays,
+ jbooleanArray isBeginningOfSentenceArray, jintArray word, jboolean isValidWord, jint count,
+ jint timestamp) {
Dictionary *dictionary = reinterpret_cast<Dictionary *>(dict);
if (!dictionary) {
return false;
}
- const PrevWordsInfo prevWordsInfo = JniDataUtils::constructPrevWordsInfo(env,
+ const NgramContext ngramContext = JniDataUtils::constructNgramContext(env,
prevWordCodePointArrays, isBeginningOfSentenceArray,
env->GetArrayLength(prevWordCodePointArrays));
jsize codePointCount = env->GetArrayLength(word);
int wordCodePoints[codePointCount];
env->GetIntArrayRegion(word, 0, codePointCount, wordCodePoints);
const HistoricalInfo historicalInfo(timestamp, 0 /* level */, count);
- return dictionary->updateCounter(&prevWordsInfo,
+ return dictionary->updateEntriesForWordWithNgramContext(&ngramContext,
CodePointArrayView(wordCodePoints, codePointCount), isValidWord == JNI_TRUE,
historicalInfo);
}
@@ -527,9 +529,9 @@ static int latinime_BinaryDictionary_addMultipleDictionaryEntries(JNIEnv *env, j
const NgramProperty ngramProperty(
CodePointArrayView(word1CodePoints, word1Length).toVector(),
bigramProbability, HistoricalInfo(timestamp, 0 /* level */, 1 /* count */));
- const PrevWordsInfo prevWordsInfo(word0CodePoints, word0Length,
+ const NgramContext ngramContext(word0CodePoints, word0Length,
false /* isBeginningOfSentence */);
- dictionary->addNgramEntry(&prevWordsInfo, &ngramProperty);
+ dictionary->addNgramEntry(&ngramContext, &ngramProperty);
}
if (dictionary->needsToRunGC(true /* mindsBlockByGC */)) {
return i + 1;
@@ -639,10 +641,10 @@ static bool latinime_BinaryDictionary_migrateNative(JNIEnv *env, jclass clazz, j
return false;
}
}
- const PrevWordsInfo prevWordsInfo(wordCodePoints, wordCodePointCount,
+ const NgramContext ngramContext(wordCodePoints, wordCodePointCount,
wordProperty.getUnigramProperty()->representsBeginningOfSentence());
for (const NgramProperty &ngramProperty : *wordProperty.getNgramProperties()) {
- if (!dictionaryStructureWithBufferPolicy->addNgramEntry(&prevWordsInfo,
+ if (!dictionaryStructureWithBufferPolicy->addNgramEntry(&ngramContext,
&ngramProperty)) {
LogUtils::logToJava(env, "Cannot add ngram to the new dict.");
return false;
@@ -718,7 +720,8 @@ static const JNINativeMethod sMethods[] = {
{
const_cast<char *>("getWordPropertyNative"),
const_cast<char *>("(J[IZ[I[Z[ILjava/util/ArrayList;Ljava/util/ArrayList;"
- "Ljava/util/ArrayList;Ljava/util/ArrayList;)V"),
+ "Ljava/util/ArrayList;Ljava/util/ArrayList;Ljava/util/ArrayList;"
+ "Ljava/util/ArrayList;)V"),
reinterpret_cast<void *>(latinime_BinaryDictionary_getWordProperty)
},
{
@@ -747,9 +750,9 @@ static const JNINativeMethod sMethods[] = {
reinterpret_cast<void *>(latinime_BinaryDictionary_removeNgramEntry)
},
{
- const_cast<char *>("updateCounterNative"),
+ const_cast<char *>("updateEntriesForWordWithNgramContextNative"),
const_cast<char *>("(J[[I[Z[IZII)Z"),
- reinterpret_cast<void *>(latinime_BinaryDictionary_updateCounter)
+ reinterpret_cast<void *>(latinime_BinaryDictionary_updateEntriesForWordWithNgramContext)
},
{
const_cast<char *>("addMultipleDictionaryEntriesNative"),
diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.cpp
index 0a34b783a..68bf417e5 100644
--- a/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.cpp
+++ b/native/jni/com_android_inputmethod_latin_BinaryDictionaryUtils.cpp
@@ -68,18 +68,6 @@ static jfloat latinime_BinaryDictionaryUtils_calcNormalizedScore(JNIEnv *env, jc
afterCodePoints, afterLength, score);
}
-static jint latinime_BinaryDictionaryUtils_editDistance(JNIEnv *env, jclass clazz, jintArray before,
- jintArray after) {
- jsize beforeLength = env->GetArrayLength(before);
- jsize afterLength = env->GetArrayLength(after);
- int beforeCodePoints[beforeLength];
- int afterCodePoints[afterLength];
- env->GetIntArrayRegion(before, 0, beforeLength, beforeCodePoints);
- env->GetIntArrayRegion(after, 0, afterLength, afterCodePoints);
- return AutocorrectionThresholdUtils::editDistance(beforeCodePoints, beforeLength,
- afterCodePoints, afterLength);
-}
-
static int latinime_BinaryDictionaryUtils_setCurrentTimeForTest(JNIEnv *env, jclass clazz,
jint currentTime) {
if (currentTime >= 0) {
@@ -104,11 +92,6 @@ static const JNINativeMethod sMethods[] = {
reinterpret_cast<void *>(latinime_BinaryDictionaryUtils_calcNormalizedScore)
},
{
- const_cast<char *>("editDistanceNative"),
- const_cast<char *>("([I[I)I"),
- reinterpret_cast<void *>(latinime_BinaryDictionaryUtils_editDistance)
- },
- {
const_cast<char *>("setCurrentTimeForTestNative"),
const_cast<char *>("(I)I"),
reinterpret_cast<void *>(latinime_BinaryDictionaryUtils_setCurrentTimeForTest)
diff --git a/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp b/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp
index 766064153..3c6bff3b6 100644
--- a/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp
+++ b/native/jni/com_android_inputmethod_latin_DicTraverseSession.cpp
@@ -22,7 +22,7 @@
#include "jni.h"
#include "jni_common.h"
#include "suggest/core/session/dic_traverse_session.h"
-#include "suggest/core/session/prev_words_info.h"
+#include "suggest/core/session/ngram_context.h"
namespace latinime {
class Dictionary;
@@ -40,14 +40,14 @@ static void latinime_initDicTraverseSession(JNIEnv *env, jclass clazz, jlong tra
}
Dictionary *dict = reinterpret_cast<Dictionary *>(dictionary);
if (!previousWord) {
- PrevWordsInfo prevWordsInfo;
- ts->init(dict, &prevWordsInfo, 0 /* suggestOptions */);
+ NgramContext emptyNgramContext;
+ ts->init(dict, &emptyNgramContext, 0 /* suggestOptions */);
return;
}
int prevWord[previousWordLength];
env->GetIntArrayRegion(previousWord, 0, previousWordLength, prevWord);
- PrevWordsInfo prevWordsInfo(prevWord, previousWordLength, false /* isStartOfSentence */);
- ts->init(dict, &prevWordsInfo, 0 /* suggestOptions */);
+ NgramContext ngramContext(prevWord, previousWordLength, false /* isStartOfSentence */);
+ ts->init(dict, &ngramContext, 0 /* suggestOptions */);
}
static void latinime_releaseDicTraverseSession(JNIEnv *env, jclass clazz, jlong traverseSession) {
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.cpp b/native/jni/src/suggest/core/dictionary/dictionary.cpp
index 7a69d3ceb..697e99ffb 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary.cpp
@@ -23,7 +23,7 @@
#include "suggest/core/policy/dictionary_header_structure_policy.h"
#include "suggest/core/result/suggestion_results.h"
#include "suggest/core/session/dic_traverse_session.h"
-#include "suggest/core/session/prev_words_info.h"
+#include "suggest/core/session/ngram_context.h"
#include "suggest/core/suggest.h"
#include "suggest/core/suggest_options.h"
#include "suggest/policyimpl/gesture/gesture_suggest_policy_factory.h"
@@ -46,11 +46,11 @@ Dictionary::Dictionary(JNIEnv *env, DictionaryStructureWithBufferPolicy::Structu
void Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints,
- int inputSize, const PrevWordsInfo *const prevWordsInfo,
+ int inputSize, const NgramContext *const ngramContext,
const SuggestOptions *const suggestOptions, const float weightOfLangModelVsSpatialModel,
SuggestionResults *const outSuggestionResults) const {
TimeKeeper::setCurrentTime();
- traverseSession->init(this, prevWordsInfo, suggestOptions);
+ traverseSession->init(this, ngramContext, suggestOptions);
const auto &suggest = suggestOptions->isGesture() ? mGestureSuggest : mTypingSuggest;
suggest->getSuggestions(proximityInfo, traverseSession, xcoordinates,
ycoordinates, times, pointerIds, inputCodePoints, inputSize,
@@ -58,10 +58,10 @@ void Dictionary::getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession
}
Dictionary::NgramListenerForPrediction::NgramListenerForPrediction(
- const PrevWordsInfo *const prevWordsInfo, const WordIdArrayView prevWordIds,
+ const NgramContext *const ngramContext, const WordIdArrayView prevWordIds,
SuggestionResults *const suggestionResults,
const DictionaryStructureWithBufferPolicy *const dictStructurePolicy)
- : mPrevWordsInfo(prevWordsInfo), mPrevWordIds(prevWordIds),
+ : mNgramContext(ngramContext), mPrevWordIds(prevWordIds),
mSuggestionResults(suggestionResults), mDictStructurePolicy(dictStructurePolicy) {}
void Dictionary::NgramListenerForPrediction::onVisitEntry(const int ngramProbability,
@@ -69,7 +69,7 @@ void Dictionary::NgramListenerForPrediction::onVisitEntry(const int ngramProbabi
if (targetWordId == NOT_A_WORD_ID) {
return;
}
- if (mPrevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)
+ if (mNgramContext->isNthPrevWordBeginningOfSentence(1 /* n */)
&& ngramProbability == NOT_A_PROBABILITY) {
return;
}
@@ -85,20 +85,20 @@ void Dictionary::NgramListenerForPrediction::onVisitEntry(const int ngramProbabi
wordAttributes.getProbability());
}
-void Dictionary::getPredictions(const PrevWordsInfo *const prevWordsInfo,
+void Dictionary::getPredictions(const NgramContext *const ngramContext,
SuggestionResults *const outSuggestionResults) const {
TimeKeeper::setCurrentTime();
WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
- const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds(
+ const WordIdArrayView prevWordIds = ngramContext->getPrevWordIds(
mDictionaryStructureWithBufferPolicy.get(), &prevWordIdArray,
true /* tryLowerCaseSearch */);
- NgramListenerForPrediction listener(prevWordsInfo, prevWordIds, outSuggestionResults,
+ NgramListenerForPrediction listener(ngramContext, prevWordIds, outSuggestionResults,
mDictionaryStructureWithBufferPolicy.get());
mDictionaryStructureWithBufferPolicy->iterateNgramEntries(prevWordIds, &listener);
}
int Dictionary::getProbability(const CodePointArrayView codePoints) const {
- return getNgramProbability(nullptr /* prevWordsInfo */, codePoints);
+ return getNgramProbability(nullptr /* ngramContext */, codePoints);
}
int Dictionary::getMaxProbabilityOfExactMatches(const CodePointArrayView codePoints) const {
@@ -107,18 +107,18 @@ int Dictionary::getMaxProbabilityOfExactMatches(const CodePointArrayView codePoi
mDictionaryStructureWithBufferPolicy.get(), codePoints);
}
-int Dictionary::getNgramProbability(const PrevWordsInfo *const prevWordsInfo,
+int Dictionary::getNgramProbability(const NgramContext *const ngramContext,
const CodePointArrayView codePoints) const {
TimeKeeper::setCurrentTime();
const int wordId = mDictionaryStructureWithBufferPolicy->getWordId(codePoints,
false /* forceLowerCaseSearch */);
if (wordId == NOT_A_WORD_ID) return NOT_A_PROBABILITY;
- if (!prevWordsInfo) {
+ if (!ngramContext) {
return getDictionaryStructurePolicy()->getProbabilityOfWord(WordIdArrayView(), wordId);
}
WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
- const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds
- (mDictionaryStructureWithBufferPolicy.get(), &prevWordIdArray,
+ const WordIdArrayView prevWordIds = ngramContext->getPrevWordIds(
+ mDictionaryStructureWithBufferPolicy.get(), &prevWordIdArray,
true /* tryLowerCaseSearch */);
return getDictionaryStructurePolicy()->getProbabilityOfWord(prevWordIds, wordId);
}
@@ -140,24 +140,24 @@ bool Dictionary::removeUnigramEntry(const CodePointArrayView codePoints) {
return mDictionaryStructureWithBufferPolicy->removeUnigramEntry(codePoints);
}
-bool Dictionary::addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+bool Dictionary::addNgramEntry(const NgramContext *const ngramContext,
const NgramProperty *const ngramProperty) {
TimeKeeper::setCurrentTime();
- return mDictionaryStructureWithBufferPolicy->addNgramEntry(prevWordsInfo, ngramProperty);
+ return mDictionaryStructureWithBufferPolicy->addNgramEntry(ngramContext, ngramProperty);
}
-bool Dictionary::removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+bool Dictionary::removeNgramEntry(const NgramContext *const ngramContext,
const CodePointArrayView codePoints) {
TimeKeeper::setCurrentTime();
- return mDictionaryStructureWithBufferPolicy->removeNgramEntry(prevWordsInfo, codePoints);
+ return mDictionaryStructureWithBufferPolicy->removeNgramEntry(ngramContext, codePoints);
}
-bool Dictionary::updateCounter(const PrevWordsInfo *const prevWordsInfo,
+bool Dictionary::updateEntriesForWordWithNgramContext(const NgramContext *const ngramContext,
const CodePointArrayView codePoints, const bool isValidWord,
const HistoricalInfo historicalInfo) {
TimeKeeper::setCurrentTime();
- return mDictionaryStructureWithBufferPolicy->updateCounter(prevWordsInfo, codePoints,
- isValidWord, historicalInfo);
+ return mDictionaryStructureWithBufferPolicy->updateEntriesForWordWithNgramContext(ngramContext,
+ codePoints, isValidWord, historicalInfo);
}
bool Dictionary::flush(const char *const filePath) {
diff --git a/native/jni/src/suggest/core/dictionary/dictionary.h b/native/jni/src/suggest/core/dictionary/dictionary.h
index a58dbfbd7..843aec473 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary.h
+++ b/native/jni/src/suggest/core/dictionary/dictionary.h
@@ -33,7 +33,7 @@ namespace latinime {
class DictionaryStructureWithBufferPolicy;
class DicTraverseSession;
-class PrevWordsInfo;
+class NgramContext;
class ProximityInfo;
class SuggestionResults;
class SuggestOptions;
@@ -66,18 +66,18 @@ class Dictionary {
void getSuggestions(ProximityInfo *proximityInfo, DicTraverseSession *traverseSession,
int *xcoordinates, int *ycoordinates, int *times, int *pointerIds, int *inputCodePoints,
- int inputSize, const PrevWordsInfo *const prevWordsInfo,
+ int inputSize, const NgramContext *const ngramContext,
const SuggestOptions *const suggestOptions, const float weightOfLangModelVsSpatialModel,
SuggestionResults *const outSuggestionResults) const;
- void getPredictions(const PrevWordsInfo *const prevWordsInfo,
+ void getPredictions(const NgramContext *const ngramContext,
SuggestionResults *const outSuggestionResults) const;
int getProbability(const CodePointArrayView codePoints) const;
int getMaxProbabilityOfExactMatches(const CodePointArrayView codePoints) const;
- int getNgramProbability(const PrevWordsInfo *const prevWordsInfo,
+ int getNgramProbability(const NgramContext *const ngramContext,
const CodePointArrayView codePoints) const;
bool addUnigramEntry(const CodePointArrayView codePoints,
@@ -85,13 +85,13 @@ class Dictionary {
bool removeUnigramEntry(const CodePointArrayView codePoints);
- bool addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+ bool addNgramEntry(const NgramContext *const ngramContext,
const NgramProperty *const ngramProperty);
- bool removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+ bool removeNgramEntry(const NgramContext *const ngramContext,
const CodePointArrayView codePoints);
- bool updateCounter(const PrevWordsInfo *const prevWordsInfo,
+ bool updateEntriesForWordWithNgramContext(const NgramContext *const ngramContext,
const CodePointArrayView codePoints, const bool isValidWord,
const HistoricalInfo historicalInfo);
@@ -123,7 +123,7 @@ class Dictionary {
class NgramListenerForPrediction : public NgramListener {
public:
- NgramListenerForPrediction(const PrevWordsInfo *const prevWordsInfo,
+ NgramListenerForPrediction(const NgramContext *const ngramContext,
const WordIdArrayView prevWordIds, SuggestionResults *const suggestionResults,
const DictionaryStructureWithBufferPolicy *const dictStructurePolicy);
virtual void onVisitEntry(const int ngramProbability, const int targetWordId);
@@ -131,7 +131,7 @@ class Dictionary {
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(NgramListenerForPrediction);
- const PrevWordsInfo *const mPrevWordsInfo;
+ const NgramContext *const mNgramContext;
const WordIdArrayView mPrevWordIds;
SuggestionResults *const mSuggestionResults;
const DictionaryStructureWithBufferPolicy *const mDictStructurePolicy;
diff --git a/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp b/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp
index b85f3622a..9573c37bc 100644
--- a/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp
+++ b/native/jni/src/suggest/core/dictionary/dictionary_utils.cpp
@@ -21,7 +21,7 @@
#include "suggest/core/dicnode/dic_node_vector.h"
#include "suggest/core/dictionary/dictionary.h"
#include "suggest/core/dictionary/digraph_utils.h"
-#include "suggest/core/session/prev_words_info.h"
+#include "suggest/core/session/ngram_context.h"
#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
#include "utils/int_array_view.h"
@@ -33,10 +33,10 @@ namespace latinime {
std::vector<DicNode> current;
std::vector<DicNode> next;
- // No prev words information.
- PrevWordsInfo emptyPrevWordsInfo;
+ // No ngram context.
+ NgramContext emptyNgramContext;
WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
- const WordIdArrayView prevWordIds = emptyPrevWordsInfo.getPrevWordIds(
+ const WordIdArrayView prevWordIds = emptyNgramContext.getPrevWordIds(
dictionaryStructurePolicy, &prevWordIdArray, false /* tryLowerCaseSearch */);
current.emplace_back();
DicNodeUtils::initAsRoot(dictionaryStructurePolicy, prevWordIds, &current.front());
diff --git a/native/jni/src/suggest/core/dictionary/property/historical_info.h b/native/jni/src/suggest/core/dictionary/property/historical_info.h
index 5ed9ebfca..f9bd6fd8c 100644
--- a/native/jni/src/suggest/core/dictionary/property/historical_info.h
+++ b/native/jni/src/suggest/core/dictionary/property/historical_info.h
@@ -47,12 +47,12 @@ class HistoricalInfo {
}
private:
- // Default copy constructor and assign operator are used for using in std::vector.
+ // Default copy constructor is used for using in std::vector.
+ DISALLOW_ASSIGNMENT_OPERATOR(HistoricalInfo);
- // TODO: Make members const.
- int mTimestamp;
- int mLevel;
- int mCount;
+ const int mTimestamp;
+ const int mLevel;
+ const int mCount;
};
} // namespace latinime
#endif /* LATINIME_HISTORICAL_INFO_H */
diff --git a/native/jni/src/suggest/core/dictionary/property/ngram_property.h b/native/jni/src/suggest/core/dictionary/property/ngram_property.h
index dce460099..8709799f9 100644
--- a/native/jni/src/suggest/core/dictionary/property/ngram_property.h
+++ b/native/jni/src/suggest/core/dictionary/property/ngram_property.h
@@ -44,13 +44,13 @@ class NgramProperty {
}
private:
- // Default copy constructor and assign operator are used for using in std::vector.
+ // Default copy constructor is used for using in std::vector.
DISALLOW_DEFAULT_CONSTRUCTOR(NgramProperty);
+ DISALLOW_ASSIGNMENT_OPERATOR(NgramProperty);
- // TODO: Make members const.
- std::vector<int> mTargetCodePoints;
- int mProbability;
- HistoricalInfo mHistoricalInfo;
+ const std::vector<int> mTargetCodePoints;
+ const int mProbability;
+ const HistoricalInfo mHistoricalInfo;
};
} // namespace latinime
#endif // LATINIME_NGRAM_PROPERTY_H
diff --git a/native/jni/src/suggest/core/dictionary/property/unigram_property.h b/native/jni/src/suggest/core/dictionary/property/unigram_property.h
index d1f0ab4ca..5ed2e2602 100644
--- a/native/jni/src/suggest/core/dictionary/property/unigram_property.h
+++ b/native/jni/src/suggest/core/dictionary/property/unigram_property.h
@@ -41,12 +41,11 @@ class UnigramProperty {
}
private:
- // Default copy constructor and assign operator are used for using in std::vector.
+ // Default copy constructor is used for using in std::vector.
DISALLOW_DEFAULT_CONSTRUCTOR(ShortcutProperty);
- // TODO: Make members const.
- std::vector<int> mTargetCodePoints;
- int mProbability;
+ const std::vector<int> mTargetCodePoints;
+ const int mProbability;
};
UnigramProperty()
@@ -104,13 +103,12 @@ class UnigramProperty {
// Default copy constructor is used for using as a return value.
DISALLOW_ASSIGNMENT_OPERATOR(UnigramProperty);
- // TODO: Make members const.
- bool mRepresentsBeginningOfSentence;
- bool mIsNotAWord;
- bool mIsBlacklisted;
- int mProbability;
- HistoricalInfo mHistoricalInfo;
- std::vector<ShortcutProperty> mShortcuts;
+ const bool mRepresentsBeginningOfSentence;
+ const bool mIsNotAWord;
+ const bool mIsBlacklisted;
+ const int mProbability;
+ const HistoricalInfo mHistoricalInfo;
+ const std::vector<ShortcutProperty> mShortcuts;
};
} // namespace latinime
#endif // LATINIME_UNIGRAM_PROPERTY_H
diff --git a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
index 6624b7921..ceda5c03f 100644
--- a/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
+++ b/native/jni/src/suggest/core/policy/dictionary_structure_with_buffer_policy.h
@@ -33,7 +33,7 @@ class DicNodeVector;
class DictionaryHeaderStructurePolicy;
class MultiBigramMap;
class NgramListener;
-class PrevWordsInfo;
+class NgramContext;
class UnigramProperty;
/*
@@ -81,15 +81,15 @@ class DictionaryStructureWithBufferPolicy {
virtual bool removeUnigramEntry(const CodePointArrayView wordCodePoints) = 0;
// Returns whether the update was success or not.
- virtual bool addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+ virtual bool addNgramEntry(const NgramContext *const ngramContext,
const NgramProperty *const ngramProperty) = 0;
// Returns whether the update was success or not.
- virtual bool removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+ virtual bool removeNgramEntry(const NgramContext *const ngramContext,
const CodePointArrayView wordCodePoints) = 0;
// Returns whether the update was success or not.
- virtual bool updateCounter(const PrevWordsInfo *const prevWordsInfo,
+ virtual bool updateEntriesForWordWithNgramContext(const NgramContext *const ngramContext,
const CodePointArrayView wordCodePoints, const bool isValidWord,
const HistoricalInfo historicalInfo) = 0;
diff --git a/native/jni/src/suggest/core/policy/traversal.h b/native/jni/src/suggest/core/policy/traversal.h
index 6dfa7e314..5b6616d9a 100644
--- a/native/jni/src/suggest/core/policy/traversal.h
+++ b/native/jni/src/suggest/core/policy/traversal.h
@@ -44,7 +44,7 @@ class Traversal {
virtual bool needsToTraverseAllUserInput() const = 0;
virtual float getMaxSpatialDistance() const = 0;
virtual int getDefaultExpandDicNodeSize() const = 0;
- virtual int getMaxCacheSize(const int inputSize) const = 0;
+ virtual int getMaxCacheSize(const int inputSize, const float weightForLocale) const = 0;
virtual int getTerminalCacheSize() const = 0;
virtual bool isPossibleOmissionChildNode(const DicTraverseSession *const traverseSession,
const DicNode *const parentDicNode, const DicNode *const dicNode) const = 0;
diff --git a/native/jni/src/suggest/core/policy/weighting.cpp b/native/jni/src/suggest/core/policy/weighting.cpp
index c202b81fe..a06e7d070 100644
--- a/native/jni/src/suggest/core/policy/weighting.cpp
+++ b/native/jni/src/suggest/core/policy/weighting.cpp
@@ -110,10 +110,14 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
return weighting->getOmissionCost(parentDicNode, dicNode);
case CT_ADDITIONAL_PROXIMITY:
// only used for typing
- return weighting->getAdditionalProximityCost();
+ // TODO: Quit calling getMatchedCost().
+ return weighting->getAdditionalProximityCost()
+ + weighting->getMatchedCost(traverseSession, dicNode, inputStateG);
case CT_SUBSTITUTION:
// only used for typing
- return weighting->getSubstitutionCost();
+ // TODO: Quit calling getMatchedCost().
+ return weighting->getSubstitutionCost()
+ + weighting->getMatchedCost(traverseSession, dicNode, inputStateG);
case CT_NEW_WORD_SPACE_OMISSION:
return weighting->getNewWordSpatialCost(traverseSession, dicNode, inputStateG);
case CT_MATCH:
@@ -176,9 +180,9 @@ static inline void profile(const CorrectionType correctionType, DicNode *const n
case CT_OMISSION:
return 0;
case CT_ADDITIONAL_PROXIMITY:
- return 0; /* 0 because CT_MATCH will be called */
+ return 1;
case CT_SUBSTITUTION:
- return 0; /* 0 because CT_MATCH will be called */
+ return 1;
case CT_NEW_WORD_SPACE_OMISSION:
return 0;
case CT_MATCH:
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 b4d01d0f0..52dc2f86c 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.cpp
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.cpp
@@ -20,7 +20,7 @@
#include "suggest/core/dictionary/dictionary.h"
#include "suggest/core/policy/dictionary_header_structure_policy.h"
#include "suggest/core/policy/dictionary_structure_with_buffer_policy.h"
-#include "suggest/core/session/prev_words_info.h"
+#include "suggest/core/session/ngram_context.h"
namespace latinime {
@@ -30,12 +30,12 @@ const int DicTraverseSession::DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_S
256 * 1024;
void DicTraverseSession::init(const Dictionary *const dictionary,
- const PrevWordsInfo *const prevWordsInfo, const SuggestOptions *const suggestOptions) {
+ const NgramContext *const ngramContext, const SuggestOptions *const suggestOptions) {
mDictionary = dictionary;
mMultiWordCostMultiplier = getDictionaryStructurePolicy()->getHeaderStructurePolicy()
->getMultiWordCostMultiplier();
mSuggestOptions = suggestOptions;
- mPrevWordIdCount = prevWordsInfo->getPrevWordIds(getDictionaryStructurePolicy(),
+ mPrevWordIdCount = ngramContext->getPrevWordIds(getDictionaryStructurePolicy(),
&mPrevWordIdArray, true /* tryLowerCaseSearch */).size();
}
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 9f841aa3c..bc53167f0 100644
--- a/native/jni/src/suggest/core/session/dic_traverse_session.h
+++ b/native/jni/src/suggest/core/session/dic_traverse_session.h
@@ -30,7 +30,7 @@ namespace latinime {
class Dictionary;
class DictionaryStructureWithBufferPolicy;
-class PrevWordsInfo;
+class NgramContext;
class ProximityInfo;
class SuggestOptions;
@@ -61,7 +61,7 @@ class DicTraverseSession {
// Non virtual inline destructor -- never inherit this class
AK_FORCE_INLINE ~DicTraverseSession() {}
- void init(const Dictionary *dictionary, const PrevWordsInfo *const prevWordsInfo,
+ void init(const Dictionary *dictionary, const NgramContext *const ngramContext,
const SuggestOptions *const suggestOptions);
// TODO: Remove and merge into init
void setupForGetSuggestions(const ProximityInfo *pInfo, const int *inputCodePoints,
diff --git a/native/jni/src/suggest/core/session/prev_words_info.h b/native/jni/src/suggest/core/session/ngram_context.h
index 553d5ad07..64c71410f 100644
--- a/native/jni/src/suggest/core/session/prev_words_info.h
+++ b/native/jni/src/suggest/core/session/ngram_context.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef LATINIME_PREV_WORDS_INFO_H
-#define LATINIME_PREV_WORDS_INFO_H
+#ifndef LATINIME_NGRAM_CONTEXT_H
+#define LATINIME_NGRAM_CONTEXT_H
#include <array>
@@ -26,25 +26,26 @@
namespace latinime {
-class PrevWordsInfo {
+// Rename to NgramContext.
+class NgramContext {
public:
// No prev word information.
- PrevWordsInfo() : mPrevWordCount(0) {
+ NgramContext() : mPrevWordCount(0) {
clear();
}
- PrevWordsInfo(const PrevWordsInfo &prevWordsInfo)
- : mPrevWordCount(prevWordsInfo.mPrevWordCount) {
+ NgramContext(const NgramContext &ngramContext)
+ : mPrevWordCount(ngramContext.mPrevWordCount) {
for (size_t i = 0; i < mPrevWordCount; ++i) {
- mPrevWordCodePointCount[i] = prevWordsInfo.mPrevWordCodePointCount[i];
- memmove(mPrevWordCodePoints[i], prevWordsInfo.mPrevWordCodePoints[i],
+ mPrevWordCodePointCount[i] = ngramContext.mPrevWordCodePointCount[i];
+ memmove(mPrevWordCodePoints[i], ngramContext.mPrevWordCodePoints[i],
sizeof(mPrevWordCodePoints[i][0]) * mPrevWordCodePointCount[i]);
- mIsBeginningOfSentence[i] = prevWordsInfo.mIsBeginningOfSentence[i];
+ mIsBeginningOfSentence[i] = ngramContext.mIsBeginningOfSentence[i];
}
}
// Construct from previous words.
- PrevWordsInfo(const int prevWordCodePoints[][MAX_WORD_LENGTH],
+ NgramContext(const int prevWordCodePoints[][MAX_WORD_LENGTH],
const int *const prevWordCodePointCount, const bool *const isBeginningOfSentence,
const size_t prevWordCount)
: mPrevWordCount(std::min(NELEMS(mPrevWordCodePoints), prevWordCount)) {
@@ -61,7 +62,7 @@ class PrevWordsInfo {
}
// Construct from a previous word.
- PrevWordsInfo(const int *const prevWordCodePoints, const int prevWordCodePointCount,
+ NgramContext(const int *const prevWordCodePoints, const int prevWordCodePointCount,
const bool isBeginningOfSentence) : mPrevWordCount(1) {
clear();
if (prevWordCodePointCount > MAX_WORD_LENGTH || !prevWordCodePoints) {
@@ -78,8 +79,8 @@ class PrevWordsInfo {
}
// TODO: Remove.
- const PrevWordsInfo getTrimmedPrevWordsInfo(const size_t maxPrevWordCount) const {
- return PrevWordsInfo(mPrevWordCodePoints, mPrevWordCodePointCount, mIsBeginningOfSentence,
+ const NgramContext getTrimmedNgramContext(const size_t maxPrevWordCount) const {
+ return NgramContext(mPrevWordCodePoints, mPrevWordCodePointCount, mIsBeginningOfSentence,
std::min(mPrevWordCount, maxPrevWordCount));
}
@@ -122,7 +123,7 @@ class PrevWordsInfo {
}
private:
- DISALLOW_ASSIGNMENT_OPERATOR(PrevWordsInfo);
+ DISALLOW_ASSIGNMENT_OPERATOR(NgramContext);
static int getWordId(const DictionaryStructureWithBufferPolicy *const dictStructurePolicy,
const int *const wordCodePoints, const int wordCodePointCount,
@@ -165,4 +166,4 @@ class PrevWordsInfo {
bool mIsBeginningOfSentence[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
};
} // namespace latinime
-#endif // LATINIME_PREV_WORDS_INFO_H
+#endif // LATINIME_NGRAM_CONTEXT_H
diff --git a/native/jni/src/suggest/core/suggest.cpp b/native/jni/src/suggest/core/suggest.cpp
index 457414f2b..c71526293 100644
--- a/native/jni/src/suggest/core/suggest.cpp
+++ b/native/jni/src/suggest/core/suggest.cpp
@@ -28,6 +28,7 @@
#include "suggest/core/policy/weighting.h"
#include "suggest/core/result/suggestions_output_utils.h"
#include "suggest/core/session/dic_traverse_session.h"
+#include "suggest/core/suggest_options.h"
namespace latinime {
@@ -88,7 +89,8 @@ void Suggest::initializeSearch(DicTraverseSession *traverseSession) const {
traverseSession->getDicTraverseCache()->continueSearch();
} else {
// Restart recognition at the root.
- traverseSession->resetCache(TRAVERSAL->getMaxCacheSize(traverseSession->getInputSize()),
+ traverseSession->resetCache(TRAVERSAL->getMaxCacheSize(traverseSession->getInputSize(),
+ traverseSession->getSuggestOptions()->weightForLocale()),
TRAVERSAL->getTerminalCacheSize());
// Create a new dic node here
DicNode rootNode;
@@ -282,7 +284,6 @@ void Suggest::processDicNodeAsAdditionalProximityChar(DicTraverseSession *traver
// not treat the node as a terminal. There is no need to pass the bigram map in these cases.
Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_ADDITIONAL_PROXIMITY,
traverseSession, dicNode, childDicNode, 0 /* multiBigramMap */);
- weightChildNode(traverseSession, childDicNode);
processExpandedDicNode(traverseSession, childDicNode);
}
@@ -290,7 +291,6 @@ void Suggest::processDicNodeAsSubstitution(DicTraverseSession *traverseSession,
DicNode *dicNode, DicNode *childDicNode) const {
Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_SUBSTITUTION, traverseSession,
dicNode, childDicNode, 0 /* multiBigramMap */);
- weightChildNode(traverseSession, childDicNode);
processExpandedDicNode(traverseSession, childDicNode);
}
@@ -401,7 +401,7 @@ void Suggest::weightChildNode(DicTraverseSession *traverseSession, DicNode *dicN
if (dicNode->isCompletion(inputSize)) {
Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_COMPLETION, traverseSession,
0 /* parentDicNode */, dicNode, 0 /* multiBigramMap */);
- } else { // completion
+ } else {
Weighting::addCostAndForwardInputIndex(WEIGHTING, CT_MATCH, traverseSession,
0 /* parentDicNode */, dicNode, 0 /* multiBigramMap */);
}
diff --git a/native/jni/src/suggest/core/suggest_options.h b/native/jni/src/suggest/core/suggest_options.h
index d456680dd..4d331292b 100644
--- a/native/jni/src/suggest/core/suggest_options.h
+++ b/native/jni/src/suggest/core/suggest_options.h
@@ -42,6 +42,12 @@ class SuggestOptions{
return getBoolOption(SPACE_AWARE_GESTURE_ENABLED);
}
+ AK_FORCE_INLINE float weightForLocale() const {
+ // The weight is in thousands and we want the real value, so we divide by 1000.
+ // NativeSuggestOptions#setWeightForLocale does the opposite processing in Java.
+ return static_cast<float>(getIntOption(WEIGHT_FOR_LOCALE_IN_THOUSANDS)) / 1000.0f;
+ }
+
AK_FORCE_INLINE bool getAdditionalFeaturesBoolOption(const int key) const {
return getBoolOption(key + ADDITIONAL_FEATURES_OPTIONS);
}
@@ -55,9 +61,10 @@ class SuggestOptions{
static const int USE_FULL_EDIT_DISTANCE = 1;
static const int BLOCK_OFFENSIVE_WORDS = 2;
static const int SPACE_AWARE_GESTURE_ENABLED = 3;
+ static const int WEIGHT_FOR_LOCALE_IN_THOUSANDS = 4;
// Additional features options are stored after the other options and used as setting values of
// experimental features.
- static const int ADDITIONAL_FEATURES_OPTIONS = 4;
+ static const int ADDITIONAL_FEATURES_OPTIONS = 5;
const int *const mOptions;
const int mLength;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
index 4c4dfc578..8fb256c54 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.cpp
@@ -38,15 +38,17 @@ const char *const HeaderPolicy::LOCALE_KEY = "locale"; // match Java declaration
const char *const HeaderPolicy::FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID_KEY =
"FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID";
-const char *const HeaderPolicy::MAX_UNIGRAM_COUNT_KEY = "MAX_UNIGRAM_COUNT";
-const char *const HeaderPolicy::MAX_BIGRAM_COUNT_KEY = "MAX_BIGRAM_COUNT";
+const char *const HeaderPolicy::MAX_UNIGRAM_COUNT_KEY = "MAX_UNIGRAM_ENTRY_COUNT";
+const char *const HeaderPolicy::MAX_BIGRAM_COUNT_KEY = "MAX_BIGRAM_ENTRY_COUNT";
+const char *const HeaderPolicy::MAX_TRIGRAM_COUNT_KEY = "MAX_TRIGRAM_ENTRY_COUNT";
const int HeaderPolicy::DEFAULT_MULTIPLE_WORDS_DEMOTION_RATE = 100;
const float HeaderPolicy::MULTIPLE_WORD_COST_MULTIPLIER_SCALE = 100.0f;
const int HeaderPolicy::DEFAULT_FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID = 3;
const int HeaderPolicy::DEFAULT_MAX_UNIGRAM_COUNT = 10000;
-const int HeaderPolicy::DEFAULT_MAX_BIGRAM_COUNT = 10000;
+const int HeaderPolicy::DEFAULT_MAX_BIGRAM_COUNT = 30000;
+const int HeaderPolicy::DEFAULT_MAX_TRIGRAM_COUNT = 30000;
// Used for logging. Question mark is used to indicate that the key is not found.
void HeaderPolicy::readHeaderValueOrQuestionMark(const char *const key, int *outValue,
diff --git a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
index bc8eaded3..836bbe5a1 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/header/header_policy.h
@@ -253,11 +253,13 @@ class HeaderPolicy : public DictionaryHeaderStructurePolicy {
static const char *const FORGETTING_CURVE_DURATION_TO_LEVEL_DOWN_IN_SECONDS_KEY;
static const char *const MAX_UNIGRAM_COUNT_KEY;
static const char *const MAX_BIGRAM_COUNT_KEY;
+ static const char *const MAX_TRIGRAM_COUNT_KEY;
static const int DEFAULT_MULTIPLE_WORDS_DEMOTION_RATE;
static const float MULTIPLE_WORD_COST_MULTIPLIER_SCALE;
static const int DEFAULT_FORGETTING_CURVE_PROBABILITY_VALUES_TABLE_ID;
static const int DEFAULT_MAX_UNIGRAM_COUNT;
static const int DEFAULT_MAX_BIGRAM_COUNT;
+ static const int DEFAULT_MAX_TRIGRAM_COUNT;
const FormatUtils::FORMAT_VERSION mDictFormatVersion;
const HeaderReadWriteUtils::DictionaryFlags mDictionaryFlags;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp
index 8d169743c..6243f14cc 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_writer.cpp
@@ -310,7 +310,7 @@ bool Ver4PatriciaTrieNodeWriter::addShortcutTarget(const PtNodeParams *const ptN
const int shortcutProbability) {
if (!mShortcutPolicy->addNewShortcut(ptNodeParams->getTerminalId(),
targetCodePoints, targetCodePointCount, shortcutProbability)) {
- AKLOGE("Cannot add new shortuct entry. terminalId: %d", ptNodeParams->getTerminalId());
+ AKLOGE("Cannot add new shortcut entry. terminalId: %d", ptNodeParams->getTerminalId());
return false;
}
if (!ptNodeParams->hasShortcutTargets()) {
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 36eafa1e9..0eae934ae 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
@@ -33,7 +33,7 @@
#include "suggest/core/dictionary/property/ngram_property.h"
#include "suggest/core/dictionary/property/unigram_property.h"
#include "suggest/core/dictionary/property/word_property.h"
-#include "suggest/core/session/prev_words_info.h"
+#include "suggest/core/session/ngram_context.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h"
#include "suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_node_reader.h"
#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h"
@@ -186,7 +186,9 @@ int Ver4PatriciaTriePolicy::getProbabilityOfWord(const WordIdArrayView prevWordI
if (bigramsIt.getBigramPos() == ptNodePos
&& bigramsIt.getProbability() != NOT_A_PROBABILITY) {
const int bigramConditionalProbability = getBigramConditionalProbability(
- prevWordPtNodeParams.getProbability(), bigramsIt.getProbability());
+ prevWordPtNodeParams.getProbability(),
+ prevWordPtNodeParams.representsBeginningOfSentence(),
+ bigramsIt.getProbability());
return getProbability(ptNodeParams.getProbability(), bigramConditionalProbability);
}
}
@@ -209,15 +211,19 @@ void Ver4PatriciaTriePolicy::iterateNgramEntries(const WordIdArrayView prevWordI
while (bigramsIt.hasNext()) {
bigramsIt.next();
const int bigramConditionalProbability = getBigramConditionalProbability(
- prevWordPtNodeParams.getProbability(), bigramsIt.getProbability());
+ prevWordPtNodeParams.getProbability(),
+ prevWordPtNodeParams.representsBeginningOfSentence(), bigramsIt.getProbability());
listener->onVisitEntry(bigramConditionalProbability,
getWordIdFromTerminalPtNodePos(bigramsIt.getBigramPos()));
}
}
int Ver4PatriciaTriePolicy::getBigramConditionalProbability(const int prevWordUnigramProbability,
- const int bigramProbability) const {
+ const bool isInBeginningOfSentenceContext, const int bigramProbability) const {
if (mHeaderPolicy->hasHistoricalInfoOfWords()) {
+ if (isInBeginningOfSentenceContext) {
+ return bigramProbability;
+ }
// Calculate conditional probability.
return std::min(MAX_PROBABILITY - prevWordUnigramProbability + bigramProbability,
MAX_PROBABILITY);
@@ -338,7 +344,7 @@ bool Ver4PatriciaTriePolicy::removeUnigramEntry(const CodePointArrayView wordCod
return mNodeWriter.suppressUnigramEntry(&ptNodeParams);
}
-bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+bool Ver4PatriciaTriePolicy::addNgramEntry(const NgramContext *const ngramContext,
const NgramProperty *const ngramProperty) {
if (!mBuffers->isUpdatable()) {
AKLOGI("Warning: addNgramEntry() is called for non-updatable dictionary.");
@@ -349,8 +355,8 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
mDictBuffer->getTailPosition());
return false;
}
- if (!prevWordsInfo->isValid()) {
- AKLOGE("prev words info is not valid for adding n-gram entry to the dictionary.");
+ if (!ngramContext->isValid()) {
+ AKLOGE("Ngram context is not valid for adding n-gram entry to the dictionary.");
return false;
}
if (ngramProperty->getTargetCodePoints()->size() > MAX_WORD_LENGTH) {
@@ -359,23 +365,23 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
return false;
}
WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
- const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds(this, &prevWordIdArray,
+ const WordIdArrayView prevWordIds = ngramContext->getPrevWordIds(this, &prevWordIdArray,
false /* tryLowerCaseSearch */);
if (prevWordIds.empty()) {
return false;
}
if (prevWordIds[0] == NOT_A_WORD_ID) {
- if (prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)) {
+ if (ngramContext->isNthPrevWordBeginningOfSentence(1 /* n */)) {
const UnigramProperty beginningOfSentenceUnigramProperty(
true /* representsBeginningOfSentence */, true /* isNotAWord */,
false /* isBlacklisted */, MAX_PROBABILITY /* probability */, HistoricalInfo());
- if (!addUnigramEntry(prevWordsInfo->getNthPrevWordCodePoints(1 /* n */),
+ if (!addUnigramEntry(ngramContext->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 */);
+ ngramContext->getPrevWordIds(this, &prevWordIdArray, false /* tryLowerCaseSearch */);
} else {
return false;
}
@@ -399,7 +405,7 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
}
}
-bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+bool Ver4PatriciaTriePolicy::removeNgramEntry(const NgramContext *const ngramContext,
const CodePointArrayView wordCodePoints) {
if (!mBuffers->isUpdatable()) {
AKLOGI("Warning: removeNgramEntry() is called for non-updatable dictionary.");
@@ -410,8 +416,8 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor
mDictBuffer->getTailPosition());
return false;
}
- if (!prevWordsInfo->isValid()) {
- AKLOGE("prev words info is not valid for removing n-gram entry form the dictionary.");
+ if (!ngramContext->isValid()) {
+ AKLOGE("Ngram context is not valid for removing n-gram entry form the dictionary.");
return false;
}
if (wordCodePoints.size() > MAX_WORD_LENGTH) {
@@ -419,7 +425,7 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor
wordCodePoints.size());
}
WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
- const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds(this, &prevWordIdArray,
+ const WordIdArrayView prevWordIds = ngramContext->getPrevWordIds(this, &prevWordIdArray,
false /* tryLowerCaseSerch */);
if (prevWordIds.firstOrDefault(NOT_A_WORD_ID) == NOT_A_WORD_ID) {
return false;
@@ -440,26 +446,27 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor
}
-bool Ver4PatriciaTriePolicy::updateCounter(const PrevWordsInfo *const prevWordsInfo,
- const CodePointArrayView wordCodePoints, const bool isValidWord,
- const HistoricalInfo historicalInfo) {
+bool Ver4PatriciaTriePolicy::updateEntriesForWordWithNgramContext(
+ const NgramContext *const ngramContext, const CodePointArrayView wordCodePoints,
+ const bool isValidWord, const HistoricalInfo historicalInfo) {
if (!mBuffers->isUpdatable()) {
- AKLOGI("Warning: updateCounter() is called for non-updatable dictionary.");
+ AKLOGI("Warning: updateEntriesForWordWithNgramContext() is called for non-updatable "
+ "dictionary.");
return false;
}
const int probability = isValidWord ? DUMMY_PROBABILITY_FOR_VALID_WORDS : NOT_A_PROBABILITY;
const UnigramProperty unigramProperty(false /* representsBeginningOfSentence */,
false /* isNotAWord */, false /*isBlacklisted*/, probability, historicalInfo);
if (!addUnigramEntry(wordCodePoints, &unigramProperty)) {
- AKLOGE("Cannot update unigarm entry in updateCounter().");
+ AKLOGE("Cannot update unigarm entry in updateEntriesForWordWithNgramContext().");
return false;
}
- const int probabilityForNgram = prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)
+ const int probabilityForNgram = ngramContext->isNthPrevWordBeginningOfSentence(1 /* n */)
? NOT_A_PROBABILITY : probability;
const NgramProperty ngramProperty(wordCodePoints.toVector(), probabilityForNgram,
historicalInfo);
- if (!addNgramEntry(prevWordsInfo, &ngramProperty)) {
- AKLOGE("Cannot update unigarm entry in updateCounter().");
+ if (!addNgramEntry(ngramContext, &ngramProperty)) {
+ AKLOGE("Cannot update unigarm entry in updateEntriesForWordWithNgramContext().");
return false;
}
return true;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h
index b82563e61..1ad5e7e36 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/backward/v402/ver4_patricia_trie_policy.h
@@ -112,13 +112,13 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
bool removeUnigramEntry(const CodePointArrayView wordCodePoints);
- bool addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+ bool addNgramEntry(const NgramContext *const ngramContext,
const NgramProperty *const ngramProperty);
- bool removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+ bool removeNgramEntry(const NgramContext *const ngramContext,
const CodePointArrayView wordCodePoints);
- bool updateCounter(const PrevWordsInfo *const prevWordsInfo,
+ bool updateEntriesForWordWithNgramContext(const NgramContext *const ngramContext,
const CodePointArrayView wordCodePoints, const bool isValidWord,
const HistoricalInfo historicalInfo);
@@ -175,7 +175,7 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
const WordAttributes getWordAttributes(const int probability,
const PtNodeParams &ptNodeParams) const;
int getBigramConditionalProbability(const int prevWordUnigramProbability,
- const int bigramProbability) const;
+ const bool isInBeginningOfSentenceContext, const int bigramProbability) const;
};
} // namespace v402
} // namespace backward
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 d3d684bfa..b7f1199c5 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
@@ -23,7 +23,7 @@
#include "suggest/core/dictionary/binary_dictionary_bigrams_iterator.h"
#include "suggest/core/dictionary/multi_bigram_map.h"
#include "suggest/core/dictionary/ngram_listener.h"
-#include "suggest/core/session/prev_words_info.h"
+#include "suggest/core/session/ngram_context.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/patricia_trie_reading_utils.h"
#include "suggest/policyimpl/dictionary/utils/probability_utils.h"
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 32a95bb6c..b17681388 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
@@ -93,25 +93,26 @@ class PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
return false;
}
- bool addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+ bool addNgramEntry(const NgramContext *const ngramContext,
const NgramProperty *const ngramProperty) {
// This method should not be called for non-updatable dictionary.
AKLOGI("Warning: addNgramEntry() is called for non-updatable dictionary.");
return false;
}
- bool removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+ bool removeNgramEntry(const NgramContext *const ngramContext,
const CodePointArrayView wordCodePoints) {
// This method should not be called for non-updatable dictionary.
AKLOGI("Warning: removeNgramEntry() is called for non-updatable dictionary.");
return false;
}
- bool updateCounter(const PrevWordsInfo *const prevWordsInfo,
+ bool updateEntriesForWordWithNgramContext(const NgramContext *const ngramContext,
const CodePointArrayView wordCodePoints, const bool isValidWord,
const HistoricalInfo historicalInfo) {
// This method should not be called for non-updatable dictionary.
- AKLOGI("Warning: updateCounter() is called for non-updatable dictionary.");
+ AKLOGI("Warning: updateEntriesForWordWithNgramContext() is called for non-updatable "
+ "dictionary.");
return false;
}
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 dc0ed96d0..90d4687dd 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
@@ -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(mBuffer.data(), ptNodePos, mShortuctPolicy,
+ PatriciaTrieReadingUtils::readPtNodeInfo(mBuffer.data(), ptNodePos, mShortcutPolicy,
mBigramPolicy, mCodePointTable, &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 24ec5bcca..838d37314 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
@@ -35,7 +35,7 @@ class Ver2ParticiaTrieNodeReader : public PtNodeReader {
const DictionaryBigramsStructurePolicy *const bigramPolicy,
const DictionaryShortcutsStructurePolicy *const shortcutPolicy,
const int *const codePointTable)
- : mBuffer(buffer), mBigramPolicy(bigramPolicy), mShortuctPolicy(shortcutPolicy),
+ : mBuffer(buffer), mBigramPolicy(bigramPolicy), mShortcutPolicy(shortcutPolicy),
mCodePointTable(codePointTable) {}
virtual const PtNodeParams fetchPtNodeParamsInBufferFromPtNodePos(const int ptNodePos) const;
@@ -45,7 +45,7 @@ class Ver2ParticiaTrieNodeReader : public PtNodeReader {
const ReadOnlyByteArrayView mBuffer;
const DictionaryBigramsStructurePolicy *const mBigramPolicy;
- const DictionaryShortcutsStructurePolicy *const mShortuctPolicy;
+ const DictionaryShortcutsStructurePolicy *const mShortcutPolicy;
const int *const mCodePointTable;
};
} // namespace latinime
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 956dabb4f..c4297f5d6 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
@@ -25,6 +25,7 @@ namespace latinime {
const int LanguageModelDictContent::UNIGRAM_COUNT_INDEX_IN_ENTRY_COUNT_TABLE = 0;
const int LanguageModelDictContent::BIGRAM_COUNT_INDEX_IN_ENTRY_COUNT_TABLE = 1;
+const int LanguageModelDictContent::DUMMY_PROBABILITY_FOR_VALID_WORDS = 1;
bool LanguageModelDictContent::save(FILE *const file) const {
return mTrieMap.save(file);
@@ -42,18 +43,18 @@ const WordAttributes LanguageModelDictContent::getWordAttributes(const WordIdArr
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;
+ int maxPrevWordCount = 0;
for (size_t i = 0; i < prevWordIds.size(); ++i) {
const int nextBitmapEntryIndex =
mTrieMap.get(prevWordIds[i], bitmapEntryIndices[i]).mNextLevelBitmapEntryIndex;
if (nextBitmapEntryIndex == TrieMap::INVALID_INDEX) {
break;
}
- maxLevel = i + 1;
+ maxPrevWordCount = i + 1;
bitmapEntryIndices[i + 1] = nextBitmapEntryIndex;
}
- for (int i = maxLevel; i >= 0; --i) {
+ for (int i = maxPrevWordCount; i >= 0; --i) {
const TrieMap::Result result = mTrieMap.get(wordId, bitmapEntryIndices[i]);
if (!result.mIsValid) {
continue;
@@ -68,9 +69,24 @@ const WordAttributes LanguageModelDictContent::getWordAttributes(const WordIdArr
// The entry should not be treated as a valid entry.
continue;
}
- probability = std::min(rawProbability
- + ForgettingCurveUtils::getProbabilityBiasForNgram(i + 1 /* n */),
- MAX_PROBABILITY);
+ if (i == 0) {
+ // unigram
+ probability = rawProbability;
+ } else {
+ const ProbabilityEntry prevWordProbabilityEntry = getNgramProbabilityEntry(
+ prevWordIds.skip(1 /* n */).limit(i - 1), prevWordIds[0]);
+ if (!prevWordProbabilityEntry.isValid()) {
+ continue;
+ }
+ if (prevWordProbabilityEntry.representsBeginningOfSentence()) {
+ probability = rawProbability;
+ } else {
+ const int prevWordRawProbability = ForgettingCurveUtils::decodeProbability(
+ prevWordProbabilityEntry.getHistoricalInfo(), headerPolicy);
+ probability = std::min(MAX_PROBABILITY - prevWordRawProbability
+ + rawProbability, MAX_PROBABILITY);
+ }
+ }
} else {
probability = probabilityEntry.getProbability();
}
@@ -143,6 +159,56 @@ bool LanguageModelDictContent::truncateEntries(const int *const entryCounts,
return true;
}
+bool LanguageModelDictContent::updateAllEntriesOnInputWord(const WordIdArrayView prevWordIds,
+ const int wordId, const bool isValid, const HistoricalInfo historicalInfo,
+ const HeaderPolicy *const headerPolicy, int *const outAddedNewNgramEntryCount) {
+ if (outAddedNewNgramEntryCount) {
+ *outAddedNewNgramEntryCount = 0;
+ }
+ if (!mHasHistoricalInfo) {
+ AKLOGE("updateAllEntriesOnInputWord is called for dictionary without historical info.");
+ return false;
+ }
+ const ProbabilityEntry originalUnigramProbabilityEntry = getProbabilityEntry(wordId);
+ const ProbabilityEntry updatedUnigramProbabilityEntry = createUpdatedEntryFrom(
+ originalUnigramProbabilityEntry, isValid, historicalInfo, headerPolicy);
+ if (!setProbabilityEntry(wordId, &updatedUnigramProbabilityEntry)) {
+ return false;
+ }
+ for (size_t i = 0; i < prevWordIds.size(); ++i) {
+ if (prevWordIds[i] == NOT_A_WORD_ID) {
+ break;
+ }
+ // TODO: Optimize this code.
+ const WordIdArrayView limitedPrevWordIds = prevWordIds.limit(i + 1);
+ const ProbabilityEntry originalNgramProbabilityEntry = getNgramProbabilityEntry(
+ limitedPrevWordIds, wordId);
+ const ProbabilityEntry updatedNgramProbabilityEntry = createUpdatedEntryFrom(
+ originalNgramProbabilityEntry, isValid, historicalInfo, headerPolicy);
+ if (!setNgramProbabilityEntry(limitedPrevWordIds, wordId, &updatedNgramProbabilityEntry)) {
+ return false;
+ }
+ if (!originalNgramProbabilityEntry.isValid() && outAddedNewNgramEntryCount) {
+ *outAddedNewNgramEntryCount += 1;
+ }
+ }
+ return true;
+}
+
+const ProbabilityEntry LanguageModelDictContent::createUpdatedEntryFrom(
+ const ProbabilityEntry &originalProbabilityEntry, const bool isValid,
+ const HistoricalInfo historicalInfo, const HeaderPolicy *const headerPolicy) const {
+ const HistoricalInfo updatedHistoricalInfo = ForgettingCurveUtils::createUpdatedHistoricalInfo(
+ originalProbabilityEntry.getHistoricalInfo(), isValid ?
+ DUMMY_PROBABILITY_FOR_VALID_WORDS : NOT_A_PROBABILITY,
+ &historicalInfo, headerPolicy);
+ if (originalProbabilityEntry.isValid()) {
+ return ProbabilityEntry(originalProbabilityEntry.getFlags(), &updatedHistoricalInfo);
+ } else {
+ return ProbabilityEntry(0 /* flags */, &updatedHistoricalInfo);
+ }
+}
+
bool LanguageModelDictContent::runGCInner(
const TerminalPositionLookupTable::TerminalIdMap *const terminalIdMap,
const TrieMap::TrieMapRange trieMapRange,
@@ -203,17 +269,27 @@ int LanguageModelDictContent::getBitmapEntryIndex(const WordIdArrayView prevWord
return bitmapEntryIndex;
}
-bool LanguageModelDictContent::updateAllProbabilityEntriesInner(const int bitmapEntryIndex,
- const int level, const HeaderPolicy *const headerPolicy, int *const outEntryCounts) {
+bool LanguageModelDictContent::updateAllProbabilityEntriesForGCInner(const int bitmapEntryIndex,
+ const int prevWordCount, const HeaderPolicy *const headerPolicy,
+ int *const outEntryCounts) {
for (const auto &entry : mTrieMap.getEntriesInSpecifiedLevel(bitmapEntryIndex)) {
- if (level > MAX_PREV_WORD_COUNT_FOR_N_GRAM) {
- AKLOGE("Invalid level. level: %d, MAX_PREV_WORD_COUNT_FOR_N_GRAM: %d.",
- level, MAX_PREV_WORD_COUNT_FOR_N_GRAM);
+ if (prevWordCount > MAX_PREV_WORD_COUNT_FOR_N_GRAM) {
+ AKLOGE("Invalid prevWordCount. prevWordCount: %d, MAX_PREV_WORD_COUNT_FOR_N_GRAM: %d.",
+ prevWordCount, MAX_PREV_WORD_COUNT_FOR_N_GRAM);
return false;
}
const ProbabilityEntry probabilityEntry =
ProbabilityEntry::decode(entry.value(), mHasHistoricalInfo);
- if (mHasHistoricalInfo && !probabilityEntry.representsBeginningOfSentence()) {
+ if (prevWordCount > 0 && probabilityEntry.isValid()
+ && !mTrieMap.getRoot(entry.key()).mIsValid) {
+ // The entry is related to a word that has been removed. Remove the entry.
+ if (!mTrieMap.remove(entry.key(), bitmapEntryIndex)) {
+ return false;
+ }
+ continue;
+ }
+ if (mHasHistoricalInfo && !probabilityEntry.representsBeginningOfSentence()
+ && probabilityEntry.isValid()) {
const HistoricalInfo historicalInfo = ForgettingCurveUtils::createHistoricalInfoToSave(
probabilityEntry.getHistoricalInfo(), headerPolicy);
if (ForgettingCurveUtils::needsToKeep(&historicalInfo, headerPolicy)) {
@@ -232,13 +308,13 @@ bool LanguageModelDictContent::updateAllProbabilityEntriesInner(const int bitmap
}
}
if (!probabilityEntry.representsBeginningOfSentence()) {
- outEntryCounts[level] += 1;
+ outEntryCounts[prevWordCount] += 1;
}
if (!entry.hasNextLevelMap()) {
continue;
}
- if (!updateAllProbabilityEntriesInner(entry.getNextLevelBitmapEntryIndex(), level + 1,
- headerPolicy, outEntryCounts)) {
+ if (!updateAllProbabilityEntriesForGCInner(entry.getNextLevelBitmapEntryIndex(),
+ prevWordCount + 1, headerPolicy, outEntryCounts)) {
return false;
}
}
@@ -266,7 +342,7 @@ bool LanguageModelDictContent::turncateEntriesInSpecifiedLevel(
for (int i = 0; i < entryCountToRemove; ++i) {
const EntryInfoToTurncate &entryInfo = entryInfoVector[i];
if (!removeNgramProbabilityEntry(
- WordIdArrayView(entryInfo.mPrevWordIds, entryInfo.mEntryLevel), entryInfo.mKey)) {
+ WordIdArrayView(entryInfo.mPrevWordIds, entryInfo.mPrevWordCount), entryInfo.mKey)) {
return false;
}
}
@@ -276,9 +352,9 @@ bool LanguageModelDictContent::turncateEntriesInSpecifiedLevel(
bool LanguageModelDictContent::getEntryInfo(const HeaderPolicy *const headerPolicy,
const int targetLevel, const int bitmapEntryIndex, std::vector<int> *const prevWordIds,
std::vector<EntryInfoToTurncate> *const outEntryInfo) const {
- const int currentLevel = prevWordIds->size();
+ const int prevWordCount = prevWordIds->size();
for (const auto &entry : mTrieMap.getEntriesInSpecifiedLevel(bitmapEntryIndex)) {
- if (currentLevel < targetLevel) {
+ if (prevWordCount < targetLevel) {
if (!entry.hasNextLevelMap()) {
continue;
}
@@ -313,10 +389,10 @@ bool LanguageModelDictContent::EntryInfoToTurncate::Comparator::operator()(
if (left.mKey != right.mKey) {
return left.mKey < right.mKey;
}
- if (left.mEntryLevel != right.mEntryLevel) {
- return left.mEntryLevel > right.mEntryLevel;
+ if (left.mPrevWordCount != right.mPrevWordCount) {
+ return left.mPrevWordCount > right.mPrevWordCount;
}
- for (int i = 0; i < left.mEntryLevel; ++i) {
+ for (int i = 0; i < left.mPrevWordCount; ++i) {
if (left.mPrevWordIds[i] != right.mPrevWordIds[i]) {
return left.mPrevWordIds[i] < right.mPrevWordIds[i];
}
@@ -326,9 +402,10 @@ bool LanguageModelDictContent::EntryInfoToTurncate::Comparator::operator()(
}
LanguageModelDictContent::EntryInfoToTurncate::EntryInfoToTurncate(const int probability,
- const int timestamp, const int key, const int entryLevel, const int *const prevWordIds)
- : mProbability(probability), mTimestamp(timestamp), mKey(key), mEntryLevel(entryLevel) {
- memmove(mPrevWordIds, prevWordIds, mEntryLevel * sizeof(mPrevWordIds[0]));
+ const int timestamp, const int key, const int prevWordCount, const int *const prevWordIds)
+ : mProbability(probability), mTimestamp(timestamp), mKey(key),
+ mPrevWordCount(prevWordCount) {
+ memmove(mPrevWordIds, prevWordIds, mPrevWordCount * sizeof(mPrevWordIds[0]));
}
} // namespace latinime
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 b7e4af977..51ef090e1 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
@@ -154,19 +154,23 @@ class LanguageModelDictContent {
EntryRange getProbabilityEntries(const WordIdArrayView prevWordIds) const;
- bool updateAllProbabilityEntries(const HeaderPolicy *const headerPolicy,
+ bool updateAllProbabilityEntriesForGC(const HeaderPolicy *const headerPolicy,
int *const outEntryCounts) {
for (int i = 0; i <= MAX_PREV_WORD_COUNT_FOR_N_GRAM; ++i) {
outEntryCounts[i] = 0;
}
- return updateAllProbabilityEntriesInner(mTrieMap.getRootBitmapEntryIndex(), 0 /* level */,
- headerPolicy, outEntryCounts);
+ return updateAllProbabilityEntriesForGCInner(mTrieMap.getRootBitmapEntryIndex(),
+ 0 /* prevWordCount */, headerPolicy, outEntryCounts);
}
// entryCounts should be created by updateAllProbabilityEntries.
bool truncateEntries(const int *const entryCounts, const int *const maxEntryCounts,
const HeaderPolicy *const headerPolicy, int *const outEntryCounts);
+ bool updateAllEntriesOnInputWord(const WordIdArrayView prevWordIds, const int wordId,
+ const bool isValid, const HistoricalInfo historicalInfo,
+ const HeaderPolicy *const headerPolicy, int *const outAddedNewNgramEntryCount);
+
private:
DISALLOW_COPY_AND_ASSIGN(LanguageModelDictContent);
@@ -181,18 +185,21 @@ class LanguageModelDictContent {
};
EntryInfoToTurncate(const int probability, const int timestamp, const int key,
- const int entryLevel, const int *const prevWordIds);
+ const int prevWordCount, const int *const prevWordIds);
int mProbability;
int mTimestamp;
int mKey;
- int mEntryLevel;
+ int mPrevWordCount;
int mPrevWordIds[MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1];
private:
DISALLOW_DEFAULT_CONSTRUCTOR(EntryInfoToTurncate);
};
+ // TODO: Remove
+ static const int DUMMY_PROBABILITY_FOR_VALID_WORDS;
+
TrieMap mTrieMap;
const bool mHasHistoricalInfo;
@@ -201,13 +208,16 @@ class LanguageModelDictContent {
int *const outNgramCount);
int createAndGetBitmapEntryIndex(const WordIdArrayView prevWordIds);
int getBitmapEntryIndex(const WordIdArrayView prevWordIds) const;
- bool updateAllProbabilityEntriesInner(const int bitmapEntryIndex, const int level,
+ bool updateAllProbabilityEntriesForGCInner(const int bitmapEntryIndex, const int prevWordCount,
const HeaderPolicy *const headerPolicy, int *const outEntryCounts);
bool turncateEntriesInSpecifiedLevel(const HeaderPolicy *const headerPolicy,
const int maxEntryCount, const int targetLevel, int *const outEntryCount);
bool getEntryInfo(const HeaderPolicy *const headerPolicy, const int targetLevel,
const int bitmapEntryIndex, std::vector<int> *const prevWordIds,
std::vector<EntryInfoToTurncate> *const outEntryInfo) const;
+ const ProbabilityEntry createUpdatedEntryFrom(const ProbabilityEntry &originalProbabilityEntry,
+ const bool isValid, const HistoricalInfo historicalInfo,
+ const HeaderPolicy *const headerPolicy) const;
};
} // namespace latinime
#endif /* LATINIME_LANGUAGE_MODEL_DICT_CONTENT_H */
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 fa1415633..f4d340f86 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
@@ -98,17 +98,17 @@ class ProbabilityEntry {
}
uint64_t encode(const bool hasHistoricalInfo) const {
- uint64_t encodedEntry = static_cast<uint64_t>(mFlags);
+ uint64_t encodedEntry = static_cast<uint8_t>(mFlags);
if (hasHistoricalInfo) {
encodedEntry = (encodedEntry << (Ver4DictConstants::TIME_STAMP_FIELD_SIZE * CHAR_BIT))
- ^ static_cast<uint64_t>(mHistoricalInfo.getTimestamp());
+ | static_cast<uint32_t>(mHistoricalInfo.getTimestamp());
encodedEntry = (encodedEntry << (Ver4DictConstants::WORD_LEVEL_FIELD_SIZE * CHAR_BIT))
- ^ static_cast<uint64_t>(mHistoricalInfo.getLevel());
+ | static_cast<uint8_t>(mHistoricalInfo.getLevel());
encodedEntry = (encodedEntry << (Ver4DictConstants::WORD_COUNT_FIELD_SIZE * CHAR_BIT))
- ^ static_cast<uint64_t>(mHistoricalInfo.getCount());
+ | static_cast<uint8_t>(mHistoricalInfo.getCount());
} else {
encodedEntry = (encodedEntry << (Ver4DictConstants::PROBABILITY_SIZE * CHAR_BIT))
- ^ static_cast<uint64_t>(mProbability);
+ | static_cast<uint8_t>(mProbability);
}
return encodedEntry;
}
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 f13512d5a..794c63ffd 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
@@ -142,14 +142,9 @@ bool Ver4PatriciaTrieNodeWriter::updatePtNodeUnigramProperty(
if (!toBeUpdatedPtNodeParams->isTerminal()) {
return false;
}
- const ProbabilityEntry originalProbabilityEntry =
- mBuffers->getLanguageModelDictContent()->getProbabilityEntry(
- toBeUpdatedPtNodeParams->getTerminalId());
const ProbabilityEntry probabilityEntryOfUnigramProperty = ProbabilityEntry(unigramProperty);
- const ProbabilityEntry updatedProbabilityEntry =
- createUpdatedEntryFrom(&originalProbabilityEntry, &probabilityEntryOfUnigramProperty);
return mBuffers->getMutableLanguageModelDictContent()->setProbabilityEntry(
- toBeUpdatedPtNodeParams->getTerminalId(), &updatedProbabilityEntry);
+ toBeUpdatedPtNodeParams->getTerminalId(), &probabilityEntryOfUnigramProperty);
}
bool Ver4PatriciaTrieNodeWriter::updatePtNodeProbabilityAndGetNeedsToKeepPtNodeAfterGC(
@@ -203,10 +198,8 @@ bool Ver4PatriciaTrieNodeWriter::writeNewTerminalPtNodeAndAdvancePosition(
// Write probability.
ProbabilityEntry newProbabilityEntry;
const ProbabilityEntry probabilityEntryOfUnigramProperty = ProbabilityEntry(unigramProperty);
- const ProbabilityEntry probabilityEntryToWrite = createUpdatedEntryFrom(
- &newProbabilityEntry, &probabilityEntryOfUnigramProperty);
return mBuffers->getMutableLanguageModelDictContent()->setProbabilityEntry(
- terminalId, &probabilityEntryToWrite);
+ terminalId, &probabilityEntryOfUnigramProperty);
}
// TODO: Support counting ngram entries.
@@ -217,10 +210,8 @@ bool Ver4PatriciaTrieNodeWriter::addNgramEntry(const WordIdArrayView prevWordIds
const ProbabilityEntry probabilityEntry =
languageModelDictContent->getNgramProbabilityEntry(prevWordIds, wordId);
const ProbabilityEntry probabilityEntryOfNgramProperty(ngramProperty);
- const ProbabilityEntry updatedProbabilityEntry = createUpdatedEntryFrom(
- &probabilityEntry, &probabilityEntryOfNgramProperty);
if (!languageModelDictContent->setNgramProbabilityEntry(
- prevWordIds, wordId, &updatedProbabilityEntry)) {
+ prevWordIds, wordId, &probabilityEntryOfNgramProperty)) {
AKLOGE("Cannot add new ngram entry. prevWordId[0]: %d, prevWordId.size(): %zd, wordId: %d",
prevWordIds[0], prevWordIds.size(), wordId);
return false;
@@ -285,7 +276,7 @@ bool Ver4PatriciaTrieNodeWriter::addShortcutTarget(const PtNodeParams *const ptN
const int shortcutProbability) {
if (!mShortcutPolicy->addNewShortcut(ptNodeParams->getTerminalId(),
targetCodePoints, targetCodePointCount, shortcutProbability)) {
- AKLOGE("Cannot add new shortuct entry. terminalId: %d", ptNodeParams->getTerminalId());
+ AKLOGE("Cannot add new shortcut entry. terminalId: %d", ptNodeParams->getTerminalId());
return false;
}
return true;
@@ -346,22 +337,6 @@ bool Ver4PatriciaTrieNodeWriter::writePtNodeAndGetTerminalIdAndAdvancePosition(
ptNodeParams->getCodePointCount() > 1 /* hasMultipleChars */);
}
-// TODO: Move probability handling code to LanguageModelDictContent.
-const ProbabilityEntry Ver4PatriciaTrieNodeWriter::createUpdatedEntryFrom(
- const ProbabilityEntry *const originalProbabilityEntry,
- const ProbabilityEntry *const probabilityEntry) const {
- if (mHeaderPolicy->hasHistoricalInfoOfWords()) {
- const HistoricalInfo updatedHistoricalInfo =
- ForgettingCurveUtils::createUpdatedHistoricalInfo(
- originalProbabilityEntry->getHistoricalInfo(),
- probabilityEntry->getProbability(), probabilityEntry->getHistoricalInfo(),
- mHeaderPolicy);
- return ProbabilityEntry(probabilityEntry->getFlags(), &updatedHistoricalInfo);
- } else {
- return *probabilityEntry;
- }
-}
-
bool Ver4PatriciaTrieNodeWriter::updatePtNodeFlags(const int ptNodePos, const bool isTerminal,
const bool hasMultipleChars) {
// Create node flags and write them.
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h
index ea4f09904..4ecf88729 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_writer.h
@@ -38,11 +38,10 @@ class Ver4ShortcutListPolicy;
class Ver4PatriciaTrieNodeWriter : public PtNodeWriter {
public:
Ver4PatriciaTrieNodeWriter(BufferWithExtendableBuffer *const trieBuffer,
- Ver4DictBuffers *const buffers, const HeaderPolicy *const headerPolicy,
- const PtNodeReader *const ptNodeReader,
+ Ver4DictBuffers *const buffers, const PtNodeReader *const ptNodeReader,
const PtNodeArrayReader *const ptNodeArrayReader,
Ver4ShortcutListPolicy *const shortcutPolicy)
- : mTrieBuffer(trieBuffer), mBuffers(buffers), mHeaderPolicy(headerPolicy),
+ : mTrieBuffer(trieBuffer), mBuffers(buffers),
mReadingHelper(ptNodeReader, ptNodeArrayReader), mShortcutPolicy(shortcutPolicy) {}
virtual ~Ver4PatriciaTrieNodeWriter() {}
@@ -96,20 +95,12 @@ class Ver4PatriciaTrieNodeWriter : public PtNodeWriter {
const PtNodeParams *const ptNodeParams, int *const outTerminalId,
int *const ptNodeWritingPos);
- // Create updated probability entry using given probability property. In addition to the
- // probability, this method updates historical information if needed.
- // TODO: Update flags.
- const ProbabilityEntry createUpdatedEntryFrom(
- const ProbabilityEntry *const originalProbabilityEntry,
- const ProbabilityEntry *const probabilityEntry) const;
-
bool updatePtNodeFlags(const int ptNodePos, const bool isTerminal, const bool hasMultipleChars);
static const int CHILDREN_POSITION_FIELD_SIZE;
BufferWithExtendableBuffer *const mTrieBuffer;
Ver4DictBuffers *const mBuffers;
- const HeaderPolicy *const mHeaderPolicy;
DynamicPtReadingHelper mReadingHelper;
Ver4ShortcutListPolicy *const mShortcutPolicy;
};
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 036197c41..ea8c0dc22 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
@@ -26,7 +26,7 @@
#include "suggest/core/dictionary/property/ngram_property.h"
#include "suggest/core/dictionary/property/unigram_property.h"
#include "suggest/core/dictionary/property/word_property.h"
-#include "suggest/core/session/prev_words_info.h"
+#include "suggest/core/session/ngram_context.h"
#include "suggest/policyimpl/dictionary/structure/pt_common/dynamic_pt_reading_helper.h"
#include "suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_node_reader.h"
#include "suggest/policyimpl/dictionary/utils/forgetting_curve_utils.h"
@@ -43,7 +43,6 @@ const char *const Ver4PatriciaTriePolicy::MAX_BIGRAM_COUNT_QUERY = "MAX_BIGRAM_C
const int Ver4PatriciaTriePolicy::MARGIN_TO_REFUSE_DYNAMIC_OPERATIONS = 1024;
const int Ver4PatriciaTriePolicy::MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS =
Ver4DictConstants::MAX_DICTIONARY_SIZE - MARGIN_TO_REFUSE_DYNAMIC_OPERATIONS;
-const int Ver4PatriciaTriePolicy::DUMMY_PROBABILITY_FOR_VALID_WORDS = 1;
void Ver4PatriciaTriePolicy::createAndGetAllChildDicNodes(const DicNode *const dicNode,
DicNodeVector *const childDicNodes) const {
@@ -151,8 +150,7 @@ void Ver4PatriciaTriePolicy::iterateNgramEntries(const WordIdArrayView prevWordI
}
const int probability = probabilityEntry.hasHistoricalInfo() ?
ForgettingCurveUtils::decodeProbability(
- probabilityEntry.getHistoricalInfo(), mHeaderPolicy)
- + ForgettingCurveUtils::getProbabilityBiasForNgram(i + 1 /* n */) :
+ probabilityEntry.getHistoricalInfo(), mHeaderPolicy) :
probabilityEntry.getProbability();
listener->onVisitEntry(probability, entry.getWordId());
}
@@ -266,7 +264,7 @@ bool Ver4PatriciaTriePolicy::removeUnigramEntry(const CodePointArrayView wordCod
return true;
}
-bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+bool Ver4PatriciaTriePolicy::addNgramEntry(const NgramContext *const ngramContext,
const NgramProperty *const ngramProperty) {
if (!mBuffers->isUpdatable()) {
AKLOGI("Warning: addNgramEntry() is called for non-updatable dictionary.");
@@ -277,8 +275,8 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
mDictBuffer->getTailPosition());
return false;
}
- if (!prevWordsInfo->isValid()) {
- AKLOGE("prev words info is not valid for adding n-gram entry to the dictionary.");
+ if (!ngramContext->isValid()) {
+ AKLOGE("Ngram context is not valid for adding n-gram entry to the dictionary.");
return false;
}
if (ngramProperty->getTargetCodePoints()->size() > MAX_WORD_LENGTH) {
@@ -287,7 +285,7 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
return false;
}
WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
- const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds(this, &prevWordIdArray,
+ const WordIdArrayView prevWordIds = ngramContext->getPrevWordIds(this, &prevWordIdArray,
false /* tryLowerCaseSearch */);
if (prevWordIds.empty()) {
return false;
@@ -296,19 +294,19 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
if (prevWordIds[i] != NOT_A_WORD_ID) {
continue;
}
- if (!prevWordsInfo->isNthPrevWordBeginningOfSentence(i + 1 /* n */)) {
+ if (!ngramContext->isNthPrevWordBeginningOfSentence(i + 1 /* n */)) {
return false;
}
const UnigramProperty beginningOfSentenceUnigramProperty(
true /* representsBeginningOfSentence */, true /* isNotAWord */,
false /* isBlacklisted */, MAX_PROBABILITY /* probability */, HistoricalInfo());
- if (!addUnigramEntry(prevWordsInfo->getNthPrevWordCodePoints(1 /* n */),
+ if (!addUnigramEntry(ngramContext->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 */);
+ ngramContext->getPrevWordIds(this, &prevWordIdArray, false /* tryLowerCaseSearch */);
}
const int wordId = getWordId(CodePointArrayView(*ngramProperty->getTargetCodePoints()),
false /* forceLowerCaseSearch */);
@@ -326,7 +324,7 @@ bool Ver4PatriciaTriePolicy::addNgramEntry(const PrevWordsInfo *const prevWordsI
}
}
-bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+bool Ver4PatriciaTriePolicy::removeNgramEntry(const NgramContext *const ngramContext,
const CodePointArrayView wordCodePoints) {
if (!mBuffers->isUpdatable()) {
AKLOGI("Warning: removeNgramEntry() is called for non-updatable dictionary.");
@@ -337,8 +335,8 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor
mDictBuffer->getTailPosition());
return false;
}
- if (!prevWordsInfo->isValid()) {
- AKLOGE("prev words info is not valid for removing n-gram entry form the dictionary.");
+ if (!ngramContext->isValid()) {
+ AKLOGE("Ngram context is not valid for removing n-gram entry form the dictionary.");
return false;
}
if (wordCodePoints.size() > MAX_WORD_LENGTH) {
@@ -346,7 +344,7 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor
wordCodePoints.size());
}
WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
- const WordIdArrayView prevWordIds = prevWordsInfo->getPrevWordIds(this, &prevWordIdArray,
+ const WordIdArrayView prevWordIds = ngramContext->getPrevWordIds(this, &prevWordIdArray,
false /* tryLowerCaseSerch */);
if (prevWordIds.empty() || prevWordIds.contains(NOT_A_WORD_ID)) {
return false;
@@ -363,32 +361,52 @@ bool Ver4PatriciaTriePolicy::removeNgramEntry(const PrevWordsInfo *const prevWor
}
}
-bool Ver4PatriciaTriePolicy::updateCounter(const PrevWordsInfo *const prevWordsInfo,
- const CodePointArrayView wordCodePoints, const bool isValidWord,
- const HistoricalInfo historicalInfo) {
+bool Ver4PatriciaTriePolicy::updateEntriesForWordWithNgramContext(
+ const NgramContext *const ngramContext, const CodePointArrayView wordCodePoints,
+ const bool isValidWord, const HistoricalInfo historicalInfo) {
if (!mBuffers->isUpdatable()) {
- AKLOGI("Warning: updateCounter() is called for non-updatable dictionary.");
+ AKLOGI("Warning: updateEntriesForWordWithNgramContext() is called for non-updatable "
+ "dictionary.");
return false;
}
- // TODO: Have count up method in language model dict content.
- const int probability = isValidWord ? DUMMY_PROBABILITY_FOR_VALID_WORDS : NOT_A_PROBABILITY;
- const UnigramProperty unigramProperty(false /* representsBeginningOfSentence */,
- false /* isNotAWord */, false /*isBlacklisted*/, probability, historicalInfo);
- if (!addUnigramEntry(wordCodePoints, &unigramProperty)) {
- AKLOGE("Cannot update unigarm entry in updateCounter().");
- return false;
+ const bool updateAsAValidWord = ngramContext->isNthPrevWordBeginningOfSentence(1 /* n */) ?
+ false : isValidWord;
+ int wordId = getWordId(wordCodePoints, false /* tryLowerCaseSearch */);
+ if (wordId == NOT_A_WORD_ID) {
+ // The word is not in the dictionary.
+ const UnigramProperty unigramProperty(false /* representsBeginningOfSentence */,
+ false /* isNotAWord */, false /* isBlacklisted */, NOT_A_PROBABILITY,
+ HistoricalInfo(historicalInfo.getTimestamp(), 0 /* level */, 0 /* count */));
+ if (!addUnigramEntry(wordCodePoints, &unigramProperty)) {
+ AKLOGE("Cannot add unigarm entry in updateEntriesForWordWithNgramContext().");
+ return false;
+ }
+ wordId = getWordId(wordCodePoints, false /* tryLowerCaseSearch */);
}
- const int probabilityForNgram = prevWordsInfo->isNthPrevWordBeginningOfSentence(1 /* n */)
- ? NOT_A_PROBABILITY : probability;
- const NgramProperty ngramProperty(wordCodePoints.toVector(), probabilityForNgram,
- historicalInfo);
- for (size_t i = 1; i <= prevWordsInfo->getPrevWordCount(); ++i) {
- const PrevWordsInfo trimmedPrevWordsInfo(prevWordsInfo->getTrimmedPrevWordsInfo(i));
- if (!addNgramEntry(&trimmedPrevWordsInfo, &ngramProperty)) {
- AKLOGE("Cannot update ngram entry in updateCounter().");
+
+ WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> prevWordIdArray;
+ const WordIdArrayView prevWordIds = ngramContext->getPrevWordIds(this, &prevWordIdArray,
+ false /* tryLowerCaseSearch */);
+ if (prevWordIds.firstOrDefault(NOT_A_WORD_ID) == NOT_A_WORD_ID
+ && ngramContext->isNthPrevWordBeginningOfSentence(1 /* n */)) {
+ const UnigramProperty beginningOfSentenceUnigramProperty(
+ true /* representsBeginningOfSentence */,
+ true /* isNotAWord */, false /* isBlacklisted */, NOT_A_PROBABILITY,
+ HistoricalInfo(historicalInfo.getTimestamp(), 0 /* level */, 0 /* count */));
+ if (!addUnigramEntry(ngramContext->getNthPrevWordCodePoints(1 /* n */),
+ &beginningOfSentenceUnigramProperty)) {
+ AKLOGE("Cannot add BoS entry in updateEntriesForWordWithNgramContext().");
return false;
}
+ // Refresh word ids.
+ ngramContext->getPrevWordIds(this, &prevWordIdArray, false /* tryLowerCaseSearch */);
+ }
+ int addedNewNgramEntryCount = 0;
+ if (!mBuffers->getMutableLanguageModelDictContent()->updateAllEntriesOnInputWord(prevWordIds,
+ wordId, updateAsAValidWord, historicalInfo, mHeaderPolicy, &addedNewNgramEntryCount)) {
+ return false;
}
+ mBigramCount += addedNewNgramEntryCount;
return true;
}
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
index 662bb8d4b..c0532815c 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_policy.h
@@ -47,8 +47,8 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
mShortcutPolicy(mBuffers->getMutableShortcutDictContent(),
mBuffers->getTerminalPositionLookupTable()),
mNodeReader(mDictBuffer), mPtNodeArrayReader(mDictBuffer),
- mNodeWriter(mDictBuffer, mBuffers.get(), mHeaderPolicy, &mNodeReader,
- &mPtNodeArrayReader, &mShortcutPolicy),
+ mNodeWriter(mDictBuffer, mBuffers.get(), &mNodeReader, &mPtNodeArrayReader,
+ &mShortcutPolicy),
mUpdatingHelper(mDictBuffer, &mNodeReader, &mNodeWriter),
mWritingHelper(mBuffers.get()),
mUnigramCount(mHeaderPolicy->getUnigramCount()),
@@ -92,13 +92,13 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
bool removeUnigramEntry(const CodePointArrayView wordCodePoints);
- bool addNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+ bool addNgramEntry(const NgramContext *const ngramContext,
const NgramProperty *const ngramProperty);
- bool removeNgramEntry(const PrevWordsInfo *const prevWordsInfo,
+ bool removeNgramEntry(const NgramContext *const ngramContext,
const CodePointArrayView wordCodePoints);
- bool updateCounter(const PrevWordsInfo *const prevWordsInfo,
+ bool updateEntriesForWordWithNgramContext(const NgramContext *const ngramContext,
const CodePointArrayView wordCodePoints, const bool isValidWord,
const HistoricalInfo historicalInfo);
@@ -131,8 +131,6 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
// prevent the dictionary from overflowing.
static const int MARGIN_TO_REFUSE_DYNAMIC_OPERATIONS;
static const int MIN_DICT_SIZE_TO_REFUSE_DYNAMIC_OPERATIONS;
- // TODO: Remove
- static const int DUMMY_PROBABILITY_FOR_VALID_WORDS;
const Ver4DictBuffers::Ver4DictBuffersPtr mBuffers;
const HeaderPolicy *const mHeaderPolicy;
@@ -144,6 +142,7 @@ class Ver4PatriciaTriePolicy : public DictionaryStructureWithBufferPolicy {
DynamicPtUpdatingHelper mUpdatingHelper;
Ver4PatriciaTrieWritingHelper mWritingHelper;
int mUnigramCount;
+ // TODO: Support counting ngram entries.
int mBigramCount;
std::vector<int> mTerminalPtNodePositionsForIteratingWords;
mutable bool mIsCorrupted;
diff --git a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
index e1ff973de..f0d59c150 100644
--- a/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
+++ b/native/jni/src/suggest/policyimpl/dictionary/structure/v4/ver4_patricia_trie_writing_helper.cpp
@@ -78,11 +78,11 @@ bool Ver4PatriciaTrieWritingHelper::runGC(const int rootPtNodeArrayPos,
Ver4ShortcutListPolicy shortcutPolicy(mBuffers->getMutableShortcutDictContent(),
mBuffers->getTerminalPositionLookupTable());
Ver4PatriciaTrieNodeWriter ptNodeWriter(mBuffers->getWritableTrieBuffer(),
- mBuffers, headerPolicy, &ptNodeReader, &ptNodeArrayReader, &shortcutPolicy);
+ mBuffers, &ptNodeReader, &ptNodeArrayReader, &shortcutPolicy);
int entryCountTable[MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1];
- if (!mBuffers->getMutableLanguageModelDictContent()->updateAllProbabilityEntries(headerPolicy,
- entryCountTable)) {
+ if (!mBuffers->getMutableLanguageModelDictContent()->updateAllProbabilityEntriesForGC(
+ headerPolicy, entryCountTable)) {
AKLOGE("Failed to update probabilities in language model dict content.");
return false;
}
@@ -118,7 +118,7 @@ bool Ver4PatriciaTrieWritingHelper::runGC(const int rootPtNodeArrayPos,
PtNodeWriter::DictPositionRelocationMap dictPositionRelocationMap;
readingHelper.initWithPtNodeArrayPos(rootPtNodeArrayPos);
Ver4PatriciaTrieNodeWriter ptNodeWriterForNewBuffers(buffersToWrite->getWritableTrieBuffer(),
- buffersToWrite, headerPolicy, &ptNodeReader, &ptNodeArrayReader, &shortcutPolicy);
+ buffersToWrite, &ptNodeReader, &ptNodeArrayReader, &shortcutPolicy);
DynamicPtGcEventListeners::TraversePolicyToPlaceAndWriteValidPtNodesToBuffer
traversePolicyToPlaceAndWriteValidPtNodesToBuffer(&ptNodeWriterForNewBuffers,
buffersToWrite->getWritableTrieBuffer(), &dictPositionRelocationMap);
@@ -133,7 +133,7 @@ bool Ver4PatriciaTrieWritingHelper::runGC(const int rootPtNodeArrayPos,
Ver4ShortcutListPolicy newShortcutPolicy(buffersToWrite->getMutableShortcutDictContent(),
buffersToWrite->getTerminalPositionLookupTable());
Ver4PatriciaTrieNodeWriter newPtNodeWriter(buffersToWrite->getWritableTrieBuffer(),
- buffersToWrite, headerPolicy, &newPtNodeReader, &newPtNodeArrayreader,
+ buffersToWrite, &newPtNodeReader, &newPtNodeArrayreader,
&newShortcutPolicy);
// Re-assign terminal IDs for valid terminal PtNodes.
TerminalPositionLookupTable::TerminalIdMap terminalIdMap;
diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
index 3fc566e7a..6a2db687d 100644
--- a/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
+++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.cpp
@@ -31,6 +31,7 @@ const float ScoringParams::DIGRAPH_PENALTY_FOR_EXACT_MATCH = 0.03f;
// TODO: Unlimit max cache dic node size
const int ScoringParams::MAX_CACHE_DIC_NODE_SIZE = 170;
const int ScoringParams::MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT = 310;
+const int ScoringParams::MAX_CACHE_DIC_NODE_SIZE_FOR_LOW_PROBABILITY_LOCALE = 50;
const int ScoringParams::THRESHOLD_SHORT_WORD_LENGTH = 4;
const float ScoringParams::DISTANCE_WEIGHT_LENGTH = 0.1524f;
@@ -48,7 +49,7 @@ const float ScoringParams::INSERTION_COST_PROXIMITY_CHAR = 0.674f;
const float ScoringParams::INSERTION_COST_FIRST_CHAR = 0.639f;
const float ScoringParams::TRANSPOSITION_COST = 0.5608f;
const float ScoringParams::SPACE_SUBSTITUTION_COST = 0.334f;
-const float ScoringParams::ADDITIONAL_PROXIMITY_COST = 0.4576f;
+const float ScoringParams::ADDITIONAL_PROXIMITY_COST = 0.37972f;
const float ScoringParams::SUBSTITUTION_COST = 0.3806f;
const float ScoringParams::COST_NEW_WORD = 0.0314f;
const float ScoringParams::COST_SECOND_OR_LATER_WORD_FIRST_CHAR_UPPERCASE = 0.3224f;
@@ -61,4 +62,7 @@ const float ScoringParams::HAS_MULTI_WORD_TERMINAL_COST = 0.4182f;
const float ScoringParams::TYPING_BASE_OUTPUT_SCORE = 1.0f;
const float ScoringParams::TYPING_MAX_OUTPUT_SCORE_PER_INPUT = 0.1f;
const float ScoringParams::NORMALIZED_SPATIAL_DISTANCE_THRESHOLD_FOR_EDIT = 0.095f;
+const float ScoringParams::LOCALE_WEIGHT_THRESHOLD_FOR_SPACE_SUBSTITUTION = 0.99f;
+const float ScoringParams::LOCALE_WEIGHT_THRESHOLD_FOR_SPACE_OMISSION = 0.99f;
+const float ScoringParams::LOCALE_WEIGHT_THRESHOLD_FOR_SMALL_CACHE_SIZE = 0.99f;
} // namespace latinime
diff --git a/native/jni/src/suggest/policyimpl/typing/scoring_params.h b/native/jni/src/suggest/policyimpl/typing/scoring_params.h
index b12de6d87..731424f3d 100644
--- a/native/jni/src/suggest/policyimpl/typing/scoring_params.h
+++ b/native/jni/src/suggest/policyimpl/typing/scoring_params.h
@@ -30,6 +30,7 @@ class ScoringParams {
static const float AUTOCORRECT_OUTPUT_THRESHOLD;
static const int MAX_CACHE_DIC_NODE_SIZE;
static const int MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT;
+ static const int MAX_CACHE_DIC_NODE_SIZE_FOR_LOW_PROBABILITY_LOCALE;
static const int THRESHOLD_SHORT_WORD_LENGTH;
static const float EXACT_MATCH_PROMOTION;
@@ -68,6 +69,9 @@ class ScoringParams {
static const float TYPING_BASE_OUTPUT_SCORE;
static const float TYPING_MAX_OUTPUT_SCORE_PER_INPUT;
static const float NORMALIZED_SPATIAL_DISTANCE_THRESHOLD_FOR_EDIT;
+ static const float LOCALE_WEIGHT_THRESHOLD_FOR_SPACE_SUBSTITUTION;
+ static const float LOCALE_WEIGHT_THRESHOLD_FOR_SPACE_OMISSION;
+ static const float LOCALE_WEIGHT_THRESHOLD_FOR_SMALL_CACHE_SIZE;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(ScoringParams);
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
index b64ee8be4..b9b6314ae 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
+++ b/native/jni/src/suggest/policyimpl/typing/typing_traversal.h
@@ -26,6 +26,7 @@
#include "suggest/core/layout/proximity_info_utils.h"
#include "suggest/core/policy/traversal.h"
#include "suggest/core/session/dic_traverse_session.h"
+#include "suggest/core/suggest_options.h"
#include "suggest/policyimpl/typing/scoring_params.h"
#include "utils/char_utils.h"
@@ -77,6 +78,13 @@ class TypingTraversal : public Traversal {
if (!CORRECT_NEW_WORD_SPACE_SUBSTITUTION) {
return false;
}
+ if (traverseSession->getSuggestOptions()->weightForLocale()
+ < ScoringParams::LOCALE_WEIGHT_THRESHOLD_FOR_SPACE_SUBSTITUTION) {
+ // Space substitution is heavy, so we skip doing it if the weight for this language
+ // is low because we anticipate the suggestions out of this dictionary are not for
+ // the language the user intends to type in.
+ return false;
+ }
if (!canDoLookAheadCorrection(traverseSession, dicNode)) {
return false;
}
@@ -91,6 +99,13 @@ class TypingTraversal : public Traversal {
if (!CORRECT_NEW_WORD_SPACE_OMISSION) {
return false;
}
+ if (traverseSession->getSuggestOptions()->weightForLocale()
+ < ScoringParams::LOCALE_WEIGHT_THRESHOLD_FOR_SPACE_OMISSION) {
+ // Space omission is heavy, so we skip doing it if the weight for this language
+ // is low because we anticipate the suggestions out of this dictionary are not for
+ // the language the user intends to type in.
+ return false;
+ }
const int inputSize = traverseSession->getInputSize();
// TODO: Don't refer to isCompletion?
if (dicNode->isCompletion(inputSize)) {
@@ -141,9 +156,14 @@ class TypingTraversal : public Traversal {
return DicNodeVector::DEFAULT_NODES_SIZE_FOR_OPTIMIZATION;
}
- AK_FORCE_INLINE int getMaxCacheSize(const int inputSize) const {
- return (inputSize <= 1) ? ScoringParams::MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT
- : ScoringParams::MAX_CACHE_DIC_NODE_SIZE;
+ AK_FORCE_INLINE int getMaxCacheSize(const int inputSize, const float weightForLocale) const {
+ if (inputSize <= 1) {
+ return ScoringParams::MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT;
+ }
+ if (weightForLocale < ScoringParams::LOCALE_WEIGHT_THRESHOLD_FOR_SMALL_CACHE_SIZE) {
+ return ScoringParams::MAX_CACHE_DIC_NODE_SIZE_FOR_LOW_PROBABILITY_LOCALE;
+ }
+ return ScoringParams::MAX_CACHE_DIC_NODE_SIZE;
}
AK_FORCE_INLINE int getTerminalCacheSize() const {
diff --git a/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp b/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp
index 1d590c353..db7a39efb 100644
--- a/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp
+++ b/native/jni/src/suggest/policyimpl/typing/typing_weighting.cpp
@@ -68,7 +68,8 @@ ErrorTypeUtils::ErrorType TypingWeighting::getErrorType(const CorrectionType cor
}
break;
case CT_ADDITIONAL_PROXIMITY:
- return ErrorTypeUtils::PROXIMITY_CORRECTION;
+ // TODO: Change to EDIT_CORRECTION.
+ return ErrorTypeUtils::PROXIMITY_CORRECTION;
case CT_OMISSION:
if (parentDicNode->canBeIntentionalOmission()) {
return ErrorTypeUtils::INTENTIONAL_OMISSION;
@@ -77,6 +78,8 @@ ErrorTypeUtils::ErrorType TypingWeighting::getErrorType(const CorrectionType cor
}
break;
case CT_SUBSTITUTION:
+ // TODO: Quit settng PROXIMITY_CORRECTION.
+ return ErrorTypeUtils::EDIT_CORRECTION | ErrorTypeUtils::PROXIMITY_CORRECTION;
case CT_INSERTION:
case CT_TERMINAL_INSERTION:
case CT_TRANSPOSITION:
diff --git a/native/jni/src/utils/jni_data_utils.h b/native/jni/src/utils/jni_data_utils.h
index 235a03bba..25cc41742 100644
--- a/native/jni/src/utils/jni_data_utils.h
+++ b/native/jni/src/utils/jni_data_utils.h
@@ -21,7 +21,7 @@
#include "defines.h"
#include "jni.h"
-#include "suggest/core/session/prev_words_info.h"
+#include "suggest/core/session/ngram_context.h"
#include "suggest/core/policy/dictionary_header_structure_policy.h"
#include "suggest/policyimpl/dictionary/header/header_read_write_utils.h"
#include "utils/char_utils.h"
@@ -96,7 +96,7 @@ class JniDataUtils {
}
}
- static PrevWordsInfo constructPrevWordsInfo(JNIEnv *env, jobjectArray prevWordCodePointArrays,
+ static NgramContext constructNgramContext(JNIEnv *env, jobjectArray prevWordCodePointArrays,
jbooleanArray isBeginningOfSentenceArray, const size_t prevWordCount) {
int prevWordCodePoints[MAX_PREV_WORD_COUNT_FOR_N_GRAM][MAX_WORD_LENGTH];
int prevWordCodePointCount[MAX_PREV_WORD_COUNT_FOR_N_GRAM];
@@ -119,7 +119,7 @@ class JniDataUtils {
&isBeginningOfSentenceBoolean);
isBeginningOfSentence[i] = isBeginningOfSentenceBoolean == JNI_TRUE;
}
- return PrevWordsInfo(prevWordCodePoints, prevWordCodePointCount, isBeginningOfSentence,
+ return NgramContext(prevWordCodePoints, prevWordCodePointCount, isBeginningOfSentence,
prevWordCount);
}
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index 26195d39f..c7a9e13a2 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -21,7 +21,8 @@
<uses-permission android:name="android.permission.READ_CONTACTS" />
- <application>
+ <application android:label="@string/app_name"
+ android:icon="@drawable/ic_app">
<uses-library android:name="android.test.runner" />
<!-- meta-data android:name="com.android.contacts.iconset" android:resource="@xml/iconset" /-->
</application>
diff --git a/tests/res/drawable-hdpi/ic_app.png b/tests/res/drawable-hdpi/ic_app.png
new file mode 100644
index 000000000..345c23d2c
--- /dev/null
+++ b/tests/res/drawable-hdpi/ic_app.png
Binary files differ
diff --git a/tests/res/values/strings.xml b/tests/res/values/strings.xml
new file mode 100644
index 000000000..5cc48b6bf
--- /dev/null
+++ b/tests/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <string name="app_name" translatable="false">LatinIMETests</string>
+</resources>
diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
index 34cf4072f..d642a1073 100644
--- a/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/KeyboardThemeTests.java
@@ -348,6 +348,31 @@ public class KeyboardThemeTests extends AndroidTestCase {
}
/*
+ * Test that KeyboardTheme array should be sorted by descending order of
+ * {@link KeyboardTheme#mMinApiVersion}.
+ */
+ private static void assertSortedKeyboardThemeArray(final KeyboardTheme[] array) {
+ assertNotNull(array);
+ final int length = array.length;
+ assertTrue("array length=" + length, length > 0);
+ for (int index = 0; index < length - 1; index++) {
+ final KeyboardTheme theme = array[index];
+ final KeyboardTheme nextTheme = array[index + 1];
+ assertTrue("sorted MinApiVersion: "
+ + theme.mThemeName + ": minApiVersion=" + theme.mMinApiVersion,
+ theme.mMinApiVersion >= nextTheme.mMinApiVersion);
+ }
+ }
+
+ public void testSortedKeyboardTheme() {
+ assertSortedKeyboardThemeArray(KeyboardTheme.KEYBOARD_THEMES);
+ }
+
+ public void testSortedAvailableKeyboardTheme() {
+ assertSortedKeyboardThemeArray(KeyboardTheme.getAvailableThemeArray(getContext()));
+ }
+
+ /*
* Test for missing selected theme.
*/
private static KeyboardTheme[] LIMITED_THEMES = {
@@ -356,6 +381,7 @@ public class KeyboardThemeTests extends AndroidTestCase {
};
static {
Arrays.sort(LIMITED_THEMES);
+ assertSortedKeyboardThemeArray(LIMITED_THEMES);
}
public void testMissingSelectedThemeIcs() {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/Telugu.java b/tests/src/com/android/inputmethod/keyboard/layout/Telugu.java
index 84c5df622..4f84c6806 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/Telugu.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/Telugu.java
@@ -140,8 +140,8 @@ public final class Telugu extends LayoutBase {
key("\u0C2A", moreKey("\u0C2B")),
// U+0C30: "ర" TELUGU LETTER RA
// U+0C31: "ఱ" TELUGU LETTER RRA
- // U+0C43: "ృ" TELUGU VOWEL SIGN VOCALIC R
- key("\u0C30", joinMoreKeys("\u0C31", "\u0C43")),
+ // U+0C4D/U+0C30: "్ర" TELUGU SIGN VIRAMA/TELUGU LETTER RA
+ key("\u0C30", joinMoreKeys("\u0C31", "\u0C4D\u0C30")),
// U+0C15: "క" TELUGU LETTER KA
// U+0C16: "ఖ" TELUGU LETTER KHA
key("\u0C15", moreKey("\u0C16")),
@@ -155,18 +155,21 @@ public final class Telugu extends LayoutBase {
// U+0C20: "ఠ" TELUGU LETTER TTHA
key("\u0C1F", moreKey("\u0C20")))
.setKeysOfRow(3,
- // U+0C46: "ె" TELUGU VOWEL SIGN E
+ // U+0C4A: "ొ" TELUGU VOWEL SIGN O
// U+0C12: "ఒ" TELUGU LETTER O
- key("\u0C46", moreKey("\u0C12")),
- // U+0C02: "ం" TELUGU SIGN ANUSVARA
+ key("\u0C4A", moreKey("\u0C12")),
+ // U+0C46: "ె" TELUGU VOWEL SIGN E
// U+0C0E: "ఎ" TELUGU LETTER E
- key("\u0C02", moreKey("\u0C0E")),
+ key("\u0C46", moreKey("\u0C0E")),
// U+0C2E: "మ" TELUGU LETTER MA
- "\u0C2E",
+ // U+0C02: "ం" TELUGU SIGN ANUSVARA
+ // U+0C01: "ఁ" TELUGU SIGN CANDRABINDU
+ key("\u0C2E", joinMoreKeys("\u0C02", "\u0C01")),
// U+0C28: "న" TELUGU LETTER NA
// U+0C23: "ణ" TELUGU LETTER NNA
// U+0C19: "ఙ" TELUGU LETTER NGA
- key("\u0C28", joinMoreKeys("\u0C23", "\u0C19")),
+ // U+0C1E: "ఞ" TELUGU LETTER NYA
+ key("\u0C28", joinMoreKeys("\u0C23", "\u0C19", "\u0C1E")),
// U+0C35: "వ" TELUGU LETTER VA
"\u0C35",
// U+0C32: "ల" TELUGU LETTER LA
@@ -176,8 +179,8 @@ public final class Telugu extends LayoutBase {
// U+0C36: "శ" TELUGU LETTER SHA
key("\u0C38", moreKey("\u0C36")),
// U+0C0B: "ఋ" TELUGU LETTER VOCALIC R
- // U+0C4D/U+0C30: "్ర" TELUGU SIGN VIRAMA/TELUGU LETTER RA
- key("\u0C0B", moreKey("\u0C4D\u0C30")),
+ // U+0C43: "ృ" TELUGU VOWEL SIGN VOCALIC R
+ key("\u0C0B", moreKey("\u0C43")),
// U+0C37: "ష" TELUGU LETTER SSA
// U+0C15/U+0C4D/U+0C37:
// "క్ష" TELUGU LETTER KA/TELUGU SIGN VIRAMA/TELUGU LETTER SSA
diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java
index 0e58b7211..f9ae9b8e4 100644
--- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java
+++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryDecayingTests.java
@@ -39,7 +39,6 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
-import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;
@@ -75,6 +74,10 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
return formatVersion > FormatSpec.VERSION401;
}
+ private static boolean supportsNgram(final int formatVersion) {
+ return formatVersion >= FormatSpec.VERSION4_DEV;
+ }
+
private void onInputWord(final BinaryDictionary binaryDictionary, final String word,
final boolean isValidWord) {
binaryDictionary.updateEntriesForWordWithNgramContext(NgramContext.EMPTY_PREV_WORDS_INFO,
@@ -88,6 +91,14 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
mCurrentTime /* timestamp */);
}
+ private void onInputWordWithPrevWords(final BinaryDictionary binaryDictionary,
+ final String word, final boolean isValidWord, final String prevWord,
+ final String prevPrevWord) {
+ binaryDictionary.updateEntriesForWordWithNgramContext(
+ new NgramContext(new WordInfo(prevWord), new WordInfo(prevPrevWord)), word,
+ isValidWord, 1 /* count */, mCurrentTime /* timestamp */);
+ }
+
private void onInputWordWithBeginningOfSentenceContext(
final BinaryDictionary binaryDictionary, final String word, final boolean isValidWord) {
binaryDictionary.updateEntriesForWordWithNgramContext(NgramContext.BEGINNING_OF_SENTENCE,
@@ -99,6 +110,12 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
return binaryDictionary.isValidNgram(new NgramContext(new WordInfo(word0)), word1);
}
+ private static boolean isValidTrigram(final BinaryDictionary binaryDictionary,
+ final String word0, final String word1, final String word2) {
+ return binaryDictionary.isValidNgram(
+ new NgramContext(new WordInfo(word1), new WordInfo(word0)), word2);
+ }
+
private void forcePassingShortTime(final BinaryDictionary binaryDictionary) {
// 30 days.
final int timeToElapse = (int)TimeUnit.SECONDS.convert(30, TimeUnit.DAYS);
@@ -118,11 +135,18 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
private HashSet<File> mDictFilesToBeDeleted = new HashSet<>();
private File createEmptyDictionaryAndGetFile(final int formatVersion) {
+ return createEmptyDictionaryWithAttributeMapAndGetFile(formatVersion,
+ new HashMap<String, String>());
+ }
+
+ private File createEmptyDictionaryWithAttributeMapAndGetFile(final int formatVersion,
+ final HashMap<String, String> attributeMap) {
if (formatVersion == FormatSpec.VERSION4
|| formatVersion == FormatSpec.VERSION4_ONLY_FOR_TESTING
|| formatVersion == FormatSpec.VERSION4_DEV) {
try {
- final File dictFile = createEmptyVer4DictionaryAndGetFile(formatVersion);
+ final File dictFile = createEmptyVer4DictionaryAndGetFile(formatVersion,
+ attributeMap);
mDictFilesToBeDeleted.add(dictFile);
return dictFile;
} catch (final IOException e) {
@@ -134,12 +158,12 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
return null;
}
- private File createEmptyVer4DictionaryAndGetFile(final int formatVersion)
+ private File createEmptyVer4DictionaryAndGetFile(final int formatVersion,
+ final HashMap<String, String> attributeMap)
throws IOException {
final File file = File.createTempFile(DICTIONARY_ID, TEST_DICT_FILE_EXTENSION,
getContext().getCacheDir());
FileUtils.deleteRecursively(file);
- Map<String, String> attributeMap = new HashMap<>();
attributeMap.put(DictionaryHeader.DICTIONARY_ID_KEY, DICTIONARY_ID);
attributeMap.put(DictionaryHeader.DICTIONARY_VERSION_KEY,
String.valueOf(TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis())));
@@ -256,7 +280,23 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
onInputWordWithPrevWord(binaryDictionary, "y", true /* isValidWord */, "x");
assertFalse(isValidBigram(binaryDictionary, "x", "y"));
- binaryDictionary.close();
+ if (!supportsNgram(formatVersion)) {
+ return;
+ }
+
+ onInputWordWithPrevWords(binaryDictionary, "c", false /* isValidWord */, "b", "a");
+ assertFalse(isValidTrigram(binaryDictionary, "a", "b", "c"));
+ assertFalse(isValidBigram(binaryDictionary, "b", "c"));
+ onInputWordWithPrevWords(binaryDictionary, "c", false /* isValidWord */, "b", "a");
+ assertTrue(isValidTrigram(binaryDictionary, "a", "b", "c"));
+ assertTrue(isValidBigram(binaryDictionary, "b", "c"));
+
+ onInputWordWithPrevWords(binaryDictionary, "d", true /* isValidWord */, "b", "a");
+ assertTrue(isValidTrigram(binaryDictionary, "a", "b", "d"));
+ assertTrue(isValidBigram(binaryDictionary, "b", "d"));
+
+ onInputWordWithPrevWords(binaryDictionary, "cd", true /* isValidWord */, "b", "a");
+ assertTrue(isValidTrigram(binaryDictionary, "a", "b", "cd"));
}
public void testDecayingProbability() {
@@ -301,6 +341,31 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
forcePassingLongTime(binaryDictionary);
assertFalse(isValidBigram(binaryDictionary, "a", "b"));
+ if (!supportsNgram(formatVersion)) {
+ return;
+ }
+
+ onInputWord(binaryDictionary, "ab", true /* isValidWord */);
+ onInputWordWithPrevWord(binaryDictionary, "bc", true /* isValidWord */, "ab");
+ onInputWordWithPrevWords(binaryDictionary, "cd", true /* isValidWord */, "bc", "ab");
+ assertTrue(isValidTrigram(binaryDictionary, "ab", "bc", "cd"));
+ forcePassingShortTime(binaryDictionary);
+ assertFalse(isValidTrigram(binaryDictionary, "ab", "bc", "cd"));
+
+ onInputWord(binaryDictionary, "ab", true /* isValidWord */);
+ onInputWordWithPrevWord(binaryDictionary, "bc", true /* isValidWord */, "ab");
+ onInputWordWithPrevWords(binaryDictionary, "cd", true /* isValidWord */, "bc", "ab");
+ onInputWord(binaryDictionary, "ab", true /* isValidWord */);
+ onInputWordWithPrevWord(binaryDictionary, "bc", true /* isValidWord */, "ab");
+ onInputWordWithPrevWords(binaryDictionary, "cd", true /* isValidWord */, "bc", "ab");
+ onInputWord(binaryDictionary, "ab", true /* isValidWord */);
+ onInputWordWithPrevWord(binaryDictionary, "bc", true /* isValidWord */, "ab");
+ onInputWordWithPrevWords(binaryDictionary, "cd", true /* isValidWord */, "bc", "ab");
+ forcePassingShortTime(binaryDictionary);
+ assertTrue(isValidTrigram(binaryDictionary, "ab", "bc", "cd"));
+ forcePassingLongTime(binaryDictionary);
+ assertFalse(isValidTrigram(binaryDictionary, "ab", "bc", "cd"));
+
binaryDictionary.close();
}
@@ -329,7 +394,8 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
}
final int maxUnigramCount = Integer.parseInt(
- binaryDictionary.getPropertyForGettingStats(BinaryDictionary.MAX_UNIGRAM_COUNT_QUERY));
+ binaryDictionary.getPropertyForGettingStats(
+ BinaryDictionary.MAX_UNIGRAM_COUNT_QUERY));
for (int i = 0; i < unigramTypedCount; i++) {
final String word = words.get(random.nextInt(words.size()));
onInputWord(binaryDictionary, word, true /* isValidWord */);
@@ -417,6 +483,12 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
}
private void testAddManyBigramsToDecayingDict(final int formatVersion) {
+ final int maxUnigramCount = 5000;
+ final int maxBigramCount = 10000;
+ final HashMap<String, String> attributeMap = new HashMap<>();
+ attributeMap.put(DictionaryHeader.MAX_UNIGRAM_COUNT_KEY, String.valueOf(maxUnigramCount));
+ attributeMap.put(DictionaryHeader.MAX_BIGRAM_COUNT_KEY, String.valueOf(maxBigramCount));
+
final int unigramCount = 5000;
final int bigramCount = 30000;
final int bigramTypedCount = 100000;
@@ -425,7 +497,8 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
final Random random = new Random(seed);
setCurrentTimeForTestMode(mCurrentTime);
- final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+ final File dictFile = createEmptyDictionaryWithAttributeMapAndGetFile(formatVersion,
+ attributeMap);
final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
@@ -448,9 +521,6 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
bigrams.add(bigram);
}
- final int maxBigramCount = Integer.parseInt(
- binaryDictionary.getPropertyForGettingStats(
- BinaryDictionary.MAX_BIGRAM_COUNT_QUERY));
for (int i = 0; i < bigramTypedCount; ++i) {
final Pair<String, String> bigram = bigrams.get(random.nextInt(bigrams.size()));
onInputWord(binaryDictionary, bigram.first, true /* isValidWord */);
@@ -487,6 +557,12 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
}
private void testOverflowBigrams(final int formatVersion) {
+ final int maxUnigramCount = 5000;
+ final int maxBigramCount = 10000;
+ final HashMap<String, String> attributeMap = new HashMap<>();
+ attributeMap.put(DictionaryHeader.MAX_UNIGRAM_COUNT_KEY, String.valueOf(maxUnigramCount));
+ attributeMap.put(DictionaryHeader.MAX_BIGRAM_COUNT_KEY, String.valueOf(maxBigramCount));
+
final int bigramCount = 20000;
final int unigramCount = 1000;
final int unigramTypedCount = 20;
@@ -497,7 +573,8 @@ public class BinaryDictionaryDecayingTests extends AndroidTestCase {
final long seed = System.currentTimeMillis();
final Random random = new Random(seed);
setCurrentTimeForTestMode(mCurrentTime);
- final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+ final File dictFile = createEmptyDictionaryWithAttributeMapAndGetFile(formatVersion,
+ attributeMap);
final BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
final int[] codePointSet = CodePointUtils.generateCodePointSet(codePointSetSize, random);
diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
index 90dd4366c..a640a9835 100644
--- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
+++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java
@@ -23,6 +23,7 @@ import android.util.Pair;
import com.android.inputmethod.latin.NgramContext.WordInfo;
import com.android.inputmethod.latin.makedict.CodePointUtils;
+import com.android.inputmethod.latin.makedict.DictionaryHeader;
import com.android.inputmethod.latin.makedict.FormatSpec;
import com.android.inputmethod.latin.makedict.WeightedString;
import com.android.inputmethod.latin.makedict.WordProperty;
@@ -78,11 +79,18 @@ public class BinaryDictionaryTests extends AndroidTestCase {
}
private File createEmptyDictionaryAndGetFile(final int formatVersion) {
+ return createEmptyDictionaryWithAttributesAndGetFile(formatVersion,
+ new HashMap<String, String>());
+ }
+
+ private File createEmptyDictionaryWithAttributesAndGetFile(final int formatVersion,
+ final HashMap<String, String> attributeMap) {
if (formatVersion == FormatSpec.VERSION4
|| formatVersion == FormatSpec.VERSION4_ONLY_FOR_TESTING
|| formatVersion == FormatSpec.VERSION4_DEV) {
try {
- final File dictFile = createEmptyVer4DictionaryAndGetFile(formatVersion);
+ final File dictFile = createEmptyVer4DictionaryAndGetFile(formatVersion,
+ attributeMap);
mDictFilesToBeDeleted.add(dictFile);
return dictFile;
} catch (final IOException e) {
@@ -94,12 +102,12 @@ public class BinaryDictionaryTests extends AndroidTestCase {
return null;
}
- private File createEmptyVer4DictionaryAndGetFile(final int formatVersion) throws IOException {
+ private File createEmptyVer4DictionaryAndGetFile(final int formatVersion,
+ final HashMap<String, String> attributeMap) throws IOException {
final File file = File.createTempFile(DICTIONARY_ID, TEST_DICT_FILE_EXTENSION,
getContext().getCacheDir());
file.delete();
file.mkdir();
- Map<String, String> attributeMap = new HashMap<>();
if (BinaryDictionaryUtils.createEmptyDictFile(file.getAbsolutePath(), formatVersion,
Locale.ENGLISH, attributeMap)) {
return file;
@@ -669,6 +677,12 @@ public class BinaryDictionaryTests extends AndroidTestCase {
}
private void testRandomOperationsAndFlashWithGC(final int formatVersion) {
+ final int maxUnigramCount = 5000;
+ final int maxBigramCount = 10000;
+ final HashMap<String, String> attributeMap = new HashMap<>();
+ attributeMap.put(DictionaryHeader.MAX_UNIGRAM_COUNT_KEY, String.valueOf(maxUnigramCount));
+ attributeMap.put(DictionaryHeader.MAX_BIGRAM_COUNT_KEY, String.valueOf(maxBigramCount));
+
final int flashWithGCIterationCount = 50;
final int operationCountInEachIteration = 200;
final int initialUnigramCount = 100;
@@ -679,7 +693,8 @@ public class BinaryDictionaryTests extends AndroidTestCase {
final long seed = System.currentTimeMillis();
final Random random = new Random(seed);
- final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+ final File dictFile = createEmptyDictionaryWithAttributesAndGetFile(formatVersion,
+ attributeMap);
BinaryDictionary binaryDictionary = getBinaryDictionary(dictFile);
final ArrayList<String> words = new ArrayList<>();
@@ -815,13 +830,20 @@ public class BinaryDictionaryTests extends AndroidTestCase {
}
private void testUnigramAndBigramCount(final int formatVersion) {
+ final int maxUnigramCount = 5000;
+ final int maxBigramCount = 10000;
+ final HashMap<String, String> attributeMap = new HashMap<>();
+ attributeMap.put(DictionaryHeader.MAX_UNIGRAM_COUNT_KEY, String.valueOf(maxUnigramCount));
+ attributeMap.put(DictionaryHeader.MAX_BIGRAM_COUNT_KEY, String.valueOf(maxBigramCount));
+
final int flashWithGCIterationCount = 10;
final int codePointSetSize = 50;
final int unigramCountPerIteration = 1000;
final int bigramCountPerIteration = 2000;
final long seed = System.currentTimeMillis();
final Random random = new Random(seed);
- final File dictFile = createEmptyDictionaryAndGetFile(formatVersion);
+ final File dictFile = createEmptyDictionaryWithAttributesAndGetFile(formatVersion,
+ attributeMap);
final ArrayList<String> words = new ArrayList<>();
final HashSet<Pair<String, String>> bigrams = new HashSet<>();
diff --git a/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java b/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java
index 30b088137..ae5cc5c73 100644
--- a/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java
+++ b/tests/src/com/android/inputmethod/latin/BlueUnderlineTests.java
@@ -28,7 +28,7 @@ public class BlueUnderlineTests extends InputTestsBase {
final int EXPECTED_SPAN_START = 0;
final int EXPECTED_SPAN_END = 4;
type(STRING_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
runMessages();
final SpanGetter span = new SpanGetter(mEditText.getText(), SuggestionSpan.class);
assertEquals("show blue underline, span start", EXPECTED_SPAN_START, span.mStart);
@@ -42,7 +42,7 @@ public class BlueUnderlineTests extends InputTestsBase {
final int EXPECTED_SPAN_START = 0;
final int EXPECTED_SPAN_END = 5;
type(STRING_1_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
runMessages();
type(STRING_2_TO_TYPE);
// We haven't have time to look into the dictionary yet, so the line should still be
@@ -51,7 +51,7 @@ public class BlueUnderlineTests extends InputTestsBase {
assertEquals("extend blue underline, span start", EXPECTED_SPAN_START, spanBefore.mStart);
assertEquals("extend blue underline, span end", EXPECTED_SPAN_END, spanBefore.mEnd);
assertTrue("extend blue underline, span color", spanBefore.isAutoCorrectionIndicator());
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
runMessages();
// Now we have been able to re-evaluate the word, there shouldn't be an auto-correction span
final SpanGetter spanAfter = new SpanGetter(mEditText.getText(), SuggestionSpan.class);
@@ -65,18 +65,18 @@ public class BlueUnderlineTests extends InputTestsBase {
final int EXPECTED_UNDERLINE_SPAN_START = 0;
final int EXPECTED_UNDERLINE_SPAN_END = 3;
type(STRING_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
runMessages();
type(Constants.CODE_SPACE);
// typedLength + 1 because we also typed a space
mLatinIME.onUpdateSelection(0, 0, typedLength + 1, typedLength + 1, -1, -1);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
runMessages();
type(Constants.CODE_DELETE);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
runMessages();
type(Constants.CODE_DELETE);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
runMessages();
final SpanGetter suggestionSpan = new SpanGetter(mEditText.getText(), SuggestionSpan.class);
assertFalse("show no blue underline after backspace, span should not be the auto-"
@@ -93,7 +93,7 @@ public class BlueUnderlineTests extends InputTestsBase {
final int typedLength = STRING_TO_TYPE.length();
final int NEW_CURSOR_POSITION = 0;
type(STRING_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
// Simulate the onUpdateSelection() event
mLatinIME.onUpdateSelection(0, 0, typedLength, typedLength, -1, -1);
runMessages();
@@ -103,7 +103,7 @@ public class BlueUnderlineTests extends InputTestsBase {
mInputConnection.setSelection(NEW_CURSOR_POSITION, NEW_CURSOR_POSITION);
mLatinIME.onUpdateSelection(typedLength, typedLength,
NEW_CURSOR_POSITION, NEW_CURSOR_POSITION, -1, -1);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
runMessages();
final SpanGetter span = new SpanGetter(mEditText.getText(), SuggestionSpan.class);
assertFalse("blue underline removed when cursor is moved",
@@ -113,7 +113,7 @@ public class BlueUnderlineTests extends InputTestsBase {
public void testComposingStopsOnSpace() {
final String STRING_TO_TYPE = "this ";
type(STRING_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
// Simulate the onUpdateSelection() event
mLatinIME.onUpdateSelection(0, 0, STRING_TO_TYPE.length(), STRING_TO_TYPE.length(), -1, -1);
runMessages();
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTests.java b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
index ec249dab3..99dc9a204 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTests.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTests.java
@@ -16,6 +16,7 @@
package com.android.inputmethod.latin;
+import android.test.MoreAsserts;
import android.test.suitebuilder.annotation.LargeTest;
import android.text.TextUtils;
import android.view.inputmethod.BaseInputConnection;
@@ -487,7 +488,7 @@ public class InputLogicTests extends InputTestsBase {
public void testPredictionsAfterSpace() {
final String WORD_TO_TYPE = "Barack ";
type(WORD_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
// Test the first prediction is displayed
final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
@@ -499,17 +500,17 @@ public class InputLogicTests extends InputTestsBase {
mLatinIME.clearPersonalizedDictionariesForTest();
final String WORD_TO_TYPE = "Barack ";
type(WORD_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
// No need to test here, testPredictionsAfterSpace is testing it already
type(" ");
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
// Test the predictions have been cleared
SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
assertEquals("predictions cleared after double-space-to-period", suggestedWords.size(), 0);
type(Constants.CODE_DELETE);
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
// Test the first prediction is displayed
suggestedWords = mLatinIME.getSuggestedWordsForTest();
@@ -522,7 +523,7 @@ public class InputLogicTests extends InputTestsBase {
type(WORD_TO_TYPE);
// Choose the auto-correction. For "Barack", the auto-correction should be "Barack".
pickSuggestionManually(WORD_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
// Test the first prediction is displayed
final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
@@ -534,13 +535,13 @@ public class InputLogicTests extends InputTestsBase {
mLatinIME.clearPersonalizedDictionariesForTest();
final String WORD_TO_TYPE = "Barack. ";
type(WORD_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
assertEquals("No prediction after period after inputting once.", 0, suggestedWords.size());
type(WORD_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
suggestedWords = mLatinIME.getSuggestedWordsForTest();
assertEquals("Beginning-of-Sentence prediction after inputting 2 times.", "Barack",
@@ -565,18 +566,18 @@ public class InputLogicTests extends InputTestsBase {
type(" ");
mLatinIME.onUpdateSelection(endOfSuggestion, endOfSuggestion,
endOfSuggestion + 1, endOfSuggestion + 1, -1, -1);
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
// Simulate a manual cursor move
mInputConnection.setSelection(indexForManualCursor, indexForManualCursor);
mLatinIME.onUpdateSelection(endOfSuggestion + 1, endOfSuggestion + 1,
indexForManualCursor, indexForManualCursor, -1, -1);
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
pickSuggestionManually(WORD_TO_TYPE);
mLatinIME.onUpdateSelection(indexForManualCursor, indexForManualCursor,
endOfWord, endOfWord, -1, -1);
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
// Test the first prediction is displayed
final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
@@ -624,7 +625,7 @@ public class InputLogicTests extends InputTestsBase {
for (int i = 0; i < WORD_TO_TYPE.length(); ++i) {
type(WORD_TO_TYPE.substring(i, i+1));
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
}
assertEquals("type many trailing single quotes one by one", EXPECTED_RESULT,
@@ -636,7 +637,7 @@ public class InputLogicTests extends InputTestsBase {
final String EXPECTED_RESULT = WORD_TO_TYPE;
for (int i = 0; i < WORD_TO_TYPE.length(); ++i) {
type(WORD_TO_TYPE.substring(i, i+1));
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
}
assertEquals("type words letter by letter", EXPECTED_RESULT,
@@ -652,10 +653,30 @@ public class InputLogicTests extends InputTestsBase {
changeLanguage("fr");
runMessages();
type(WORD_TO_TYPE_SECOND_PART);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
runMessages();
final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
assertEquals("Suggestions updated after switching languages",
EXPECTED_RESULT, suggestedWords.size() > 0 ? suggestedWords.getWord(1) : null);
}
+
+ public void testBasicGesture() {
+ gesture("this");
+ assertEquals("gesture \"this\"", "this", mEditText.getText().toString());
+ }
+
+ public void testGestureGesture() {
+ gesture("this");
+ gesture("is");
+ assertEquals("gesture \"this is\"", "this is", mEditText.getText().toString());
+ }
+
+ public void testGestureBackspaceGestureAgain() {
+ gesture("this");
+ type(Constants.CODE_DELETE);
+ assertEquals("gesture then backspace", "", mEditText.getText().toString());
+ gesture("this");
+ MoreAsserts.assertNotEqual("gesture twice the same thing", "this",
+ mEditText.getText().toString());
+ }
}
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java b/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java
index 2560407dc..c16372ab5 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTestsLanguageWithoutSpaces.java
@@ -74,7 +74,7 @@ public class InputLogicTestsLanguageWithoutSpaces extends InputTestsBase {
mInputConnection.setSelection(CURSOR_POS, CURSOR_POS);
mLatinIME.onUpdateSelection(typedLength, typedLength,
CURSOR_POS, CURSOR_POS, -1, -1);
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
assertEquals("start composing inside text", -1,
BaseInputConnection.getComposingSpanStart(mEditText.getText()));
@@ -91,7 +91,7 @@ public class InputLogicTestsLanguageWithoutSpaces extends InputTestsBase {
final String WORD_TO_TYPE = "Barack ";
changeKeyboardLocaleAndDictLocale("th", "en_US");
type(WORD_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
// Make sure there is no space
assertEquals("predictions in lang without spaces", "Barack",
diff --git a/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java b/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java
index 715d449a0..842b54fe1 100644
--- a/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java
+++ b/tests/src/com/android/inputmethod/latin/InputLogicTestsNonEnglish.java
@@ -70,7 +70,7 @@ public class InputLogicTestsNonEnglish extends InputTestsBase {
try {
changeLanguage("fr");
type(WORD_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
runMessages();
assertTrue("type word then type space should display punctuation strip",
mLatinIME.getSuggestedWordsForTest().isPunctuationSuggestions());
@@ -95,7 +95,7 @@ public class InputLogicTestsNonEnglish extends InputTestsBase {
try {
changeLanguage("fr");
type(WORD_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
runMessages();
final SuggestedWords suggestedWords = mLatinIME.getSuggestedWordsForTest();
assertEquals("type word then type space yields predictions for French",
diff --git a/tests/src/com/android/inputmethod/latin/InputTestsBase.java b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
index 6860bea45..dd900a22c 100644
--- a/tests/src/com/android/inputmethod/latin/InputTestsBase.java
+++ b/tests/src/com/android/inputmethod/latin/InputTestsBase.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.latin;
import android.content.Context;
import android.content.SharedPreferences;
+import android.graphics.Point;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.test.ServiceTestCase;
@@ -39,10 +40,13 @@ import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
import com.android.inputmethod.event.Event;
import com.android.inputmethod.keyboard.Key;
import com.android.inputmethod.keyboard.Keyboard;
+import com.android.inputmethod.latin.Dictionary;
+import com.android.inputmethod.latin.Dictionary.PhonyDictionary;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.settings.DebugSettings;
import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.utils.LocaleUtils;
+import com.android.inputmethod.latin.utils.StringUtils;
import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
import java.util.Locale;
@@ -56,11 +60,17 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
private static final String DEFAULT_AUTO_CORRECTION_THRESHOLD = "1";
// The message that sets the underline is posted with a 500 ms delay
- protected static final int DELAY_TO_WAIT_FOR_UNDERLINE = 500;
+ protected static final int DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS = 500;
// The message that sets predictions is posted with a 200 ms delay
- protected static final int DELAY_TO_WAIT_FOR_PREDICTIONS = 200;
+ protected static final int DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS = 200;
+ // We wait for gesture computation for this delay
+ protected static final int DELAY_TO_WAIT_FOR_GESTURE_MILLIS = 200;
private final int TIMEOUT_TO_WAIT_FOR_LOADING_MAIN_DICTIONARY_IN_SECONDS = 60;
+ // Type for a test phony dictionary
+ private static final String TYPE_TEST = "test";
+ private static final PhonyDictionary DICTIONARY_TEST = new PhonyDictionary(TYPE_TEST);
+
protected LatinIME mLatinIME;
protected Keyboard mKeyboard;
protected MyEditText mEditText;
@@ -211,7 +221,7 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
// Run messages to avoid the messages enqueued by startInputView() and its friends
// to run on a later call and ruin things. We need to wait first because some of them
// can be posted with a delay (notably, MSG_RESUME_SUGGESTIONS)
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
}
@@ -295,6 +305,47 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
}
}
+ protected Point getXY(final int codePoint) {
+ final Key key = mKeyboard.getKey(codePoint);
+ if (key == null) {
+ throw new RuntimeException("Code point not on the keyboard");
+ } else {
+ return new Point(key.getX() + key.getWidth() / 2, key.getY() + key.getHeight() / 2);
+ }
+ }
+
+ protected void gesture(final String stringToGesture) {
+ if (StringUtils.codePointCount(stringToGesture) < 2) {
+ throw new RuntimeException("Can't gesture strings less than 2 chars long");
+ }
+
+ mLatinIME.onStartBatchInput();
+ final int startCodePoint = stringToGesture.codePointAt(0);
+ Point oldPoint = getXY(startCodePoint);
+ int timestamp = 0; // In milliseconds since the start of the gesture
+ final InputPointers pointers = new InputPointers(Constants.DEFAULT_GESTURE_POINTS_CAPACITY);
+ pointers.addPointer(oldPoint.x, oldPoint.y, 0 /* pointerId */, timestamp);
+
+ for (int i = Character.charCount(startCodePoint); i < stringToGesture.length();
+ i = stringToGesture.offsetByCodePoints(i, 1)) {
+ final Point newPoint = getXY(stringToGesture.codePointAt(i));
+ // Arbitrarily 0.5s between letters and 0.1 between events. Refine this later if needed.
+ final int STEPS = 5;
+ for (int j = 0; j < STEPS; ++j) {
+ timestamp += 100;
+ pointers.addPointer(oldPoint.x + ((newPoint.x - oldPoint.x) * j) / STEPS,
+ oldPoint.y + ((newPoint.y - oldPoint.y) * j) / STEPS,
+ 0 /* pointerId */, timestamp);
+ }
+ oldPoint.x = newPoint.x;
+ oldPoint.y = newPoint.y;
+ mLatinIME.onUpdateBatchInput(pointers);
+ }
+ mLatinIME.onEndBatchInput(pointers);
+ sleep(DELAY_TO_WAIT_FOR_GESTURE_MILLIS);
+ runMessages();
+ }
+
protected void waitForDictionariesToBeLoaded() {
try {
mLatinIME.waitForLoadingDictionaries(
@@ -353,7 +404,7 @@ public class InputTestsBase extends ServiceTestCase<LatinIMEForTests> {
protected void pickSuggestionManually(final String suggestion) {
mLatinIME.pickSuggestionManually(new SuggestedWordInfo(suggestion, 1,
- SuggestedWordInfo.KIND_CORRECTION, null /* sourceDict */,
+ SuggestedWordInfo.KIND_CORRECTION, DICTIONARY_TEST,
SuggestedWordInfo.NOT_AN_INDEX /* indexOfTouchPointOfSecondWord */,
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */));
}
diff --git a/tests/src/com/android/inputmethod/latin/PunctuationTests.java b/tests/src/com/android/inputmethod/latin/PunctuationTests.java
index 64750fbda..3537918de 100644
--- a/tests/src/com/android/inputmethod/latin/PunctuationTests.java
+++ b/tests/src/com/android/inputmethod/latin/PunctuationTests.java
@@ -38,7 +38,7 @@ public class PunctuationTests extends InputTestsBase {
try {
mLatinIME.loadSettings();
type(WORD_TO_TYPE);
- sleep(DELAY_TO_WAIT_FOR_UNDERLINE);
+ sleep(DELAY_TO_WAIT_FOR_UNDERLINE_MILLIS);
runMessages();
assertTrue("type word then type space should display punctuation strip",
mLatinIME.getSuggestedWordsForTest().isPunctuationSuggestions());
diff --git a/tests/src/com/android/inputmethod/latin/ShiftModeTests.java b/tests/src/com/android/inputmethod/latin/ShiftModeTests.java
index db3c9baa9..8ba0174b5 100644
--- a/tests/src/com/android/inputmethod/latin/ShiftModeTests.java
+++ b/tests/src/com/android/inputmethod/latin/ShiftModeTests.java
@@ -75,7 +75,7 @@ public class ShiftModeTests extends InputTestsBase {
repeatKey(Constants.CODE_DELETE);
}
assertFalse("Caps immediately after repeating Backspace a lot", isCapsModeAutoShifted());
- sleep(DELAY_TO_WAIT_FOR_PREDICTIONS);
+ sleep(DELAY_TO_WAIT_FOR_PREDICTIONS_MILLIS);
runMessages();
assertTrue("Caps after a while after repeating Backspace a lot", isCapsModeAutoShifted());
}
diff --git a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
index 563261f8f..221541e4a 100644
--- a/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
+++ b/tests/src/com/android/inputmethod/latin/SuggestedWordsTests.java
@@ -59,40 +59,6 @@ public class SuggestedWordsTests extends AndroidTestCase {
SuggestedWordInfo.NOT_A_CONFIDENCE /* autoCommitFirstWordConfidence */);
}
- public void testGetSuggestedWordsExcludingTypedWord() {
- final String TYPED_WORD = "typed";
- final int NUMBER_OF_ADDED_SUGGESTIONS = 5;
- final int KIND_OF_SECOND_CORRECTION = SuggestedWordInfo.KIND_CORRECTION;
- final ArrayList<SuggestedWordInfo> list = new ArrayList<>();
- list.add(createTypedWordInfo(TYPED_WORD));
- for (int i = 0; i < NUMBER_OF_ADDED_SUGGESTIONS; ++i) {
- list.add(createCorrectionWordInfo(Integer.toString(i)));
- }
-
- final SuggestedWords words = new SuggestedWords(
- list, null /* rawSuggestions */,
- false /* typedWordValid */,
- false /* willAutoCorrect */,
- false /* isObsoleteSuggestions */,
- SuggestedWords.INPUT_STYLE_NONE);
- assertEquals(NUMBER_OF_ADDED_SUGGESTIONS + 1, words.size());
- assertEquals("typed", words.getWord(0));
- assertTrue(words.getInfo(0).isKindOf(SuggestedWordInfo.KIND_TYPED));
- assertEquals("0", words.getWord(1));
- assertTrue(words.getInfo(1).isKindOf(KIND_OF_SECOND_CORRECTION));
- assertEquals("4", words.getWord(5));
- assertTrue(words.getInfo(5).isKindOf(KIND_OF_SECOND_CORRECTION));
-
- final SuggestedWords wordsWithoutTyped =
- words.getSuggestedWordsExcludingTypedWordForRecorrection();
- // Make sure that the typed word has indeed been excluded, by testing the size of the
- // suggested words, the string and the kind of the top suggestion, which should match
- // the string and kind of what we inserted after the typed word.
- assertEquals(words.size() - 1, wordsWithoutTyped.size());
- assertEquals("0", wordsWithoutTyped.getWord(0));
- assertTrue(wordsWithoutTyped.getInfo(0).isKindOf(KIND_OF_SECOND_CORRECTION));
- }
-
// Helper for testGetTransformedWordInfo
private SuggestedWordInfo transformWordInfo(final String info,
final int trailingSingleQuotesCount) {
@@ -141,9 +107,14 @@ public class SuggestedWordsTests extends AndroidTestCase {
assertNotNull(typedWord);
assertEquals(TYPED_WORD, typedWord.mWord);
- // Make sure getTypedWordInfoOrNull() returns null.
- final SuggestedWords wordsWithoutTypedWord =
- wordsWithTypedWord.getSuggestedWordsExcludingTypedWordForRecorrection();
+ // Make sure getTypedWordInfoOrNull() returns null when no typed word.
+ list.remove(0);
+ final SuggestedWords wordsWithoutTypedWord = new SuggestedWords(
+ list, null /* rawSuggestions */,
+ false /* typedWordValid */,
+ false /* willAutoCorrect */,
+ false /* isObsoleteSuggestions */,
+ SuggestedWords.INPUT_STYLE_NONE);
assertNull(wordsWithoutTypedWord.getTypedWordInfoOrNull());
// Make sure getTypedWordInfoOrNull() returns null.
diff --git a/tests/src/com/android/inputmethod/latin/accounts/AccountsChangedReceiverTests.java b/tests/src/com/android/inputmethod/latin/accounts/AccountsChangedReceiverTests.java
index 00857e54e..832817967 100644
--- a/tests/src/com/android/inputmethod/latin/accounts/AccountsChangedReceiverTests.java
+++ b/tests/src/com/android/inputmethod/latin/accounts/AccountsChangedReceiverTests.java
@@ -23,7 +23,7 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.test.AndroidTestCase;
-import com.android.inputmethod.latin.settings.Settings;
+import com.android.inputmethod.latin.settings.LocalSettingsConstants;
/**
* Tests for {@link AccountsChangedReceiver}.
@@ -40,7 +40,7 @@ public class AccountsChangedReceiverTests extends AndroidTestCase {
super.setUp();
mPrefs = PreferenceManager.getDefaultSharedPreferences(getContext());
// Keep track of the current account so that we restore it when the test finishes.
- mLastKnownAccount = mPrefs.getString(Settings.PREF_ACCOUNT_NAME, null);
+ mLastKnownAccount = mPrefs.getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, null);
}
@Override
@@ -99,13 +99,14 @@ public class AccountsChangedReceiverTests extends AndroidTestCase {
private void updateAccountName(String accountName) {
if (accountName == null) {
- mPrefs.edit().remove(Settings.PREF_ACCOUNT_NAME).apply();
+ mPrefs.edit().remove(LocalSettingsConstants.PREF_ACCOUNT_NAME).apply();
} else {
- mPrefs.edit().putString(Settings.PREF_ACCOUNT_NAME, accountName).apply();
+ mPrefs.edit().putString(LocalSettingsConstants.PREF_ACCOUNT_NAME, accountName).apply();
}
}
private void assertAccountName(String expectedAccountName) {
- assertEquals(expectedAccountName, mPrefs.getString(Settings.PREF_ACCOUNT_NAME, null));
+ assertEquals(expectedAccountName,
+ mPrefs.getString(LocalSettingsConstants.PREF_ACCOUNT_NAME, null));
}
}
diff --git a/tests/src/com/android/inputmethod/latin/network/BlockingHttpClientTests.java b/tests/src/com/android/inputmethod/latin/network/BlockingHttpClientTests.java
index d151732aa..fed8be920 100644
--- a/tests/src/com/android/inputmethod/latin/network/BlockingHttpClientTests.java
+++ b/tests/src/com/android/inputmethod/latin/network/BlockingHttpClientTests.java
@@ -16,8 +16,8 @@
package com.android.inputmethod.latin.network;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.eq;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -53,41 +53,52 @@ public class BlockingHttpClientTests extends AndroidTestCase {
MockitoAnnotations.initMocks(this);
}
- public void testError_badGateway() throws IOException {
+ public void testError_badGateway() throws IOException, AuthException {
when(mMockHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_BAD_GATEWAY);
final BlockingHttpClient client = new BlockingHttpClient(mMockHttpConnection);
- final FakeErrorResponseProcessor processor =
- new FakeErrorResponseProcessor(HttpURLConnection.HTTP_BAD_GATEWAY);
-
- client.execute(null /* empty request */, processor);
- assertTrue("ResponseProcessor was not invoked", processor.mInvoked);
+ final FakeErrorResponseProcessor processor = new FakeErrorResponseProcessor();
+
+ try {
+ client.execute(null /* empty request */, processor);
+ fail("Expecting an HttpException");
+ } catch (HttpException e) {
+ // expected HttpException
+ assertEquals(HttpURLConnection.HTTP_BAD_GATEWAY, e.getHttpStatusCode());
+ }
}
- public void testError_clientTimeout() throws IOException {
+ public void testError_clientTimeout() throws Exception {
when(mMockHttpConnection.getResponseCode()).thenReturn(
HttpURLConnection.HTTP_CLIENT_TIMEOUT);
final BlockingHttpClient client = new BlockingHttpClient(mMockHttpConnection);
- final FakeErrorResponseProcessor processor =
- new FakeErrorResponseProcessor(HttpURLConnection.HTTP_CLIENT_TIMEOUT);
-
- client.execute(null /* empty request */, processor);
- assertTrue("ResponseProcessor was not invoked", processor.mInvoked);
+ final FakeErrorResponseProcessor processor = new FakeErrorResponseProcessor();
+
+ try {
+ client.execute(null /* empty request */, processor);
+ fail("Expecting an HttpException");
+ } catch (HttpException e) {
+ // expected HttpException
+ assertEquals(HttpURLConnection.HTTP_CLIENT_TIMEOUT, e.getHttpStatusCode());
+ }
}
- public void testError_forbiddenWithRequest() throws IOException {
+ public void testError_forbiddenWithRequest() throws Exception {
final OutputStream mockOutputStream = Mockito.mock(OutputStream.class);
when(mMockHttpConnection.getResponseCode()).thenReturn(HttpURLConnection.HTTP_FORBIDDEN);
when(mMockHttpConnection.getOutputStream()).thenReturn(mockOutputStream);
final BlockingHttpClient client = new BlockingHttpClient(mMockHttpConnection);
- final FakeErrorResponseProcessor processor =
- new FakeErrorResponseProcessor(HttpURLConnection.HTTP_FORBIDDEN);
+ final FakeErrorResponseProcessor processor = new FakeErrorResponseProcessor();
- client.execute(new byte[100], processor);
+ try {
+ client.execute(new byte[100], processor);
+ fail("Expecting an HttpException");
+ } catch (HttpException e) {
+ assertEquals(HttpURLConnection.HTTP_FORBIDDEN, e.getHttpStatusCode());
+ }
verify(mockOutputStream).write(any(byte[].class), eq(0), eq(100));
- assertTrue("ResponseProcessor was not invoked", processor.mInvoked);
}
- public void testSuccess_emptyRequest() throws IOException {
+ public void testSuccess_emptyRequest() throws Exception {
final Random rand = new Random();
byte[] response = new byte[100];
rand.nextBytes(response);
@@ -101,7 +112,7 @@ public class BlockingHttpClientTests extends AndroidTestCase {
assertTrue("ResponseProcessor was not invoked", processor.mInvoked);
}
- public void testSuccess() throws IOException {
+ public void testSuccess() throws Exception {
final OutputStream mockOutputStream = Mockito.mock(OutputStream.class);
final Random rand = new Random();
byte[] response = new byte[100];
@@ -117,28 +128,15 @@ public class BlockingHttpClientTests extends AndroidTestCase {
assertTrue("ResponseProcessor was not invoked", processor.mInvoked);
}
- private static class FakeErrorResponseProcessor implements ResponseProcessor {
- private final int mExpectedStatusCode;
-
- boolean mInvoked;
-
- FakeErrorResponseProcessor(int expectedStatusCode) {
- mExpectedStatusCode = expectedStatusCode;
- }
-
+ private static class FakeErrorResponseProcessor implements ResponseProcessor<Void> {
@Override
- public void onError(int httpStatusCode, String message) {
- mInvoked = true;
- assertEquals("onError:", mExpectedStatusCode, httpStatusCode);
- }
-
- @Override
- public void onSuccess(InputStream response) {
+ public Void onSuccess(InputStream response) {
fail("Expected an error but received success");
+ return null;
}
}
- private static class FakeSuccessResponseProcessor implements ResponseProcessor {
+ private static class FakeSuccessResponseProcessor implements ResponseProcessor<Void> {
private final byte[] mExpectedResponse;
boolean mInvoked;
@@ -148,12 +146,7 @@ public class BlockingHttpClientTests extends AndroidTestCase {
}
@Override
- public void onError(int httpStatusCode, String message) {
- fail("Expected a response but received an error");
- }
-
- @Override
- public void onSuccess(InputStream response) {
+ public Void onSuccess(InputStream response) {
try {
mInvoked = true;
BufferedInputStream in = new BufferedInputStream(response);
@@ -169,6 +162,7 @@ public class BlockingHttpClientTests extends AndroidTestCase {
} catch (IOException ex) {
fail("IOException in onSuccess");
}
+ return null;
}
}
}
diff --git a/tests/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilderTests.java b/tests/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilderTests.java
index 2b43d5b14..5b3e78eaf 100644
--- a/tests/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilderTests.java
+++ b/tests/src/com/android/inputmethod/latin/network/HttpUrlConnectionBuilderTests.java
@@ -142,4 +142,13 @@ public class HttpUrlConnectionBuilderTests extends AndroidTestCase {
assertTrue(connection.getDoInput());
assertTrue(connection.getDoOutput());
}
+
+ public void testSetAuthToken() throws IOException {
+ HttpUrlConnectionBuilder builder = new HttpUrlConnectionBuilder();
+ builder.setUrl("https://www.example.com");
+ builder.setAuthToken("some-random-auth-token");
+ HttpURLConnection connection = builder.build();
+ assertEquals("some-random-auth-token",
+ connection.getRequestProperty(HttpUrlConnectionBuilder.HTTP_HEADER_AUTHORIZATION));
+ }
}
diff --git a/tests/src/com/android/inputmethod/latin/utils/EditDistanceTests.java b/tests/src/com/android/inputmethod/latin/utils/EditDistanceTests.java
deleted file mode 100644
index 58312264b..000000000
--- a/tests/src/com/android/inputmethod/latin/utils/EditDistanceTests.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.latin.utils;
-
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-@SmallTest
-public class EditDistanceTests extends AndroidTestCase {
- /*
- * dist(kitten, sitting) == 3
- *
- * kitten-
- * .|||.|
- * sitting
- */
- public void testExample1() {
- final int dist = BinaryDictionaryUtils.editDistance("kitten", "sitting");
- assertEquals("edit distance between 'kitten' and 'sitting' is 3",
- 3, dist);
- }
-
- /*
- * dist(Sunday, Saturday) == 3
- *
- * Saturday
- * | |.|||
- * S--unday
- */
- public void testExample2() {
- final int dist = BinaryDictionaryUtils.editDistance("Saturday", "Sunday");
- assertEquals("edit distance between 'Saturday' and 'Sunday' is 3",
- 3, dist);
- }
-
- public void testBothEmpty() {
- final int dist = BinaryDictionaryUtils.editDistance("", "");
- assertEquals("when both string are empty, no edits are needed",
- 0, dist);
- }
-
- public void testFirstArgIsEmpty() {
- final int dist = BinaryDictionaryUtils.editDistance("", "aaaa");
- assertEquals("when only one string of the arguments is empty,"
- + " the edit distance is the length of the other.",
- 4, dist);
- }
-
- public void testSecoondArgIsEmpty() {
- final int dist = BinaryDictionaryUtils.editDistance("aaaa", "");
- assertEquals("when only one string of the arguments is empty,"
- + " the edit distance is the length of the other.",
- 4, dist);
- }
-
- public void testSameStrings() {
- final String arg1 = "The quick brown fox jumps over the lazy dog.";
- final String arg2 = "The quick brown fox jumps over the lazy dog.";
- final int dist = BinaryDictionaryUtils.editDistance(arg1, arg2);
- assertEquals("when same strings are passed, distance equals 0.",
- 0, dist);
- }
-
- public void testSameReference() {
- final String arg = "The quick brown fox jumps over the lazy dog.";
- final int dist = BinaryDictionaryUtils.editDistance(arg, arg);
- assertEquals("when same string references are passed, the distance equals 0.",
- 0, dist);
- }
-
- public void testNullArg() {
- try {
- BinaryDictionaryUtils.editDistance(null, "aaa");
- fail("IllegalArgumentException should be thrown.");
- } catch (Exception e) {
- assertTrue(e instanceof IllegalArgumentException);
- }
- try {
- BinaryDictionaryUtils.editDistance("aaa", null);
- fail("IllegalArgumentException should be thrown.");
- } catch (Exception e) {
- assertTrue(e instanceof IllegalArgumentException);
- }
- }
-}